From 71daf08317751c6e86375727513d0244d7e6cc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=85=E7=A8=8B?= <517719039@qq.com> Date: Wed, 12 Mar 2025 10:21:46 +0800 Subject: [PATCH 01/11] =?UTF-8?q?D=E5=BA=93@@=E9=83=A8=E5=88=86=E5=B8=B8?= =?UTF-8?q?=E7=94=A8=E5=87=BD=E6=95=B0=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/functions.out | 466 ++++++++++++++++++ contrib/shark/parallel_schedule | 1 + contrib/shark/shark--1.0.sql | 12 + contrib/shark/shark.cpp | 49 +- contrib/shark/shark.h | 14 + contrib/shark/sql/functions.sql | 169 +++++++ .../shark/src/backend_parser/gram-tsql-decl.y | 3 +- .../backend_parser/gram-tsql-epilogue.y.cpp | 9 + .../src/backend_parser/gram-tsql-prologue.y.h | 2 + .../shark/src/backend_parser/gram-tsql-rule.y | 17 +- .../backend_parser/scan-tsql-epilogue.l.cpp | 18 + .../src/backend_parser/scan-tsql-prologue.l.h | 2 + .../shark/src/backend_parser/scan-tsql-rule.l | 17 + src/common/backend/catalog/namespace.cpp | 9 +- src/common/pl/plpgsql/src/pl_comp.cpp | 3 +- .../optimizer/commands/portalcmds.cpp | 34 +- src/gausskernel/process/tcop/utility.cpp | 9 +- src/gausskernel/runtime/executor/execMain.cpp | 3 + .../runtime/opfusion/opfusion_delete.cpp | 5 + .../runtime/opfusion/opfusion_insert.cpp | 5 + .../runtime/opfusion/opfusion_select.cpp | 4 + .../runtime/opfusion/opfusion_update.cpp | 4 + src/include/knl/knl_session.h | 2 + src/include/tcop/utility.h | 3 + 24 files changed, 850 insertions(+), 10 deletions(-) create mode 100644 contrib/shark/expected/functions.out create mode 100644 contrib/shark/sql/functions.sql diff --git a/contrib/shark/expected/functions.out b/contrib/shark/expected/functions.out new file mode 100644 index 0000000000..bd14c5aee4 --- /dev/null +++ b/contrib/shark/expected/functions.out @@ -0,0 +1,466 @@ +create schema functions_test; +set search_path = 'functions_test'; +-- test @@rowcount +create table t1 (c1 int); +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +insert into t1 values(generate_series(1,10)); +select @@rowcount; + rowcount +---------- + 10 +(1 row) + +delete t1 where c1 in (1,3,5,7); +select @@rowcount; + rowcount +---------- + 4 +(1 row) + +update t1 set c1 = 12 where c1 in (2,4); +select @@rowcount; + rowcount +---------- + 2 +(1 row) + +select * from t1; + c1 +---- + 6 + 8 + 9 + 10 + 12 + 12 +(6 rows) + +select @@rowcount; + rowcount +---------- + 6 +(1 row) + +select count(*) from t1; + count +------- + 6 +(1 row) + +select @@rowcount; + rowcount +---------- + 1 +(1 row) + +do $$ +begin +execute 'select * from t1'; +RAISE NOTICE '@@rowcount: %', @@rowcount; +end $$; +NOTICE: @@rowcount: 6 +set enable_set_variable_b_format to on; +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +reset enable_set_variable_b_format; +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +begin; +declare c1 cursor for select * from t1; +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +fetch next from c1; + c1 +---- + 6 +(1 row) + +select @@rowcount; + rowcount +---------- + 1 +(1 row) + +end; +select abcd from t1; -- expect error +ERROR: column "abcd" does not exist +LINE 1: select abcd from t1; + ^ +CONTEXT: referenced column: abcd +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +-- rowcount_big() +drop table t1; +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +create table t1 (c1 int); +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +insert into t1 values(generate_series(1,10)); +select rowcount_big(); + rowcount_big +-------------- + 10 +(1 row) + +delete t1 where c1 in (1,3,5,7); +select rowcount_big(); + rowcount_big +-------------- + 4 +(1 row) + +update t1 set c1 = 12 where c1 in (2,4); +select rowcount_big(); + rowcount_big +-------------- + 2 +(1 row) + +select * from t1; + c1 +---- + 6 + 8 + 9 + 10 + 12 + 12 +(6 rows) + +select rowcount_big(); + rowcount_big +-------------- + 6 +(1 row) + +select count(*) from t1; + count +------- + 6 +(1 row) + +select rowcount_big(); + rowcount_big +-------------- + 1 +(1 row) + +set enable_set_variable_b_format to on; +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +reset enable_set_variable_b_format; +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +begin; +declare c1 cursor for select * from t1; +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +fetch next from c1; + c1 +---- + 6 +(1 row) + +select rowcount_big(); + rowcount_big +-------------- + 1 +(1 row) + +end; +select abcd from t1; -- expect error +ERROR: column "abcd" does not exist +LINE 1: select abcd from t1; + ^ +CONTEXT: referenced column: abcd +select rowcount_big(); + rowcount_big +-------------- + 0 +(1 row) + +-- bypass usecases +set enable_seqscan to off; +set enable_bitmapscan to off; +create index i1 on t1(c1); +explain (costs off) select * from t1; + QUERY PLAN +-------------------------------- + [Bypass] + Index Only Scan using i1 on t1 +(2 rows) + +select @@rowcount; + rowcount +---------- + 0 +(1 row) + +select * from t1; + c1 +---- + 6 + 8 + 9 + 10 + 12 + 12 +(6 rows) + +select @@rowcount; + rowcount +---------- + 6 +(1 row) + +explain (costs off) insert into t1 values(20); + QUERY PLAN +-------------- + [Bypass] + Insert on t1 + -> Result +(3 rows) + +insert into t1 values(generate_series(20,26)); +select @@rowcount; + rowcount +---------- + 7 +(1 row) + +explain (costs off) delete from t1 where c1 < 10; + QUERY PLAN +--------------------------------- + [Bypass] + Delete on t1 + -> Index Scan using i1 on t1 + Index Cond: (c1 < 10) +(4 rows) + +delete from t1 where c1 < 10; +select @@rowcount; + rowcount +---------- + 3 +(1 row) + +explain (costs off) update t1 set c1 = 30 where c1 > 21; + QUERY PLAN +--------------------------------- + [Bypass] + Update on t1 + -> Index Scan using i1 on t1 + Index Cond: (c1 > 21) +(4 rows) + +update t1 set c1 = 30 where c1 > 21; +select @@rowcount; + rowcount +---------- + 5 +(1 row) + +reset enable_seqscan; +reset enable_bitmapscan; +-- @@spid +select @@spid; +--?.* +--?.* +--?.* +(1 row) + +-- @@fetch_status +-- single cursor +begin; +cursor c1 for select * from t1; +fetch next from c1; + c1 +---- + 10 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch next from c1; + c1 +---- + 12 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch last from c1; + c1 +---- + 30 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch next from c2; -- expect error +ERROR: cursor "c2" does not exist +select @@fetch_status; +ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q] +end; +-- multi cursors +begin; +cursor c1 for select * from t1; +cursor c2 for select * from t1; +fetch next from c1; + c1 +---- + 10 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch next from c2; + c1 +---- + 10 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch last from c1; + c1 +---- + 30 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +fetch next from c2; + c1 +---- + 12 +(1 row) + +select @@fetch_status; + fetch_status +-------------- + 0 +(1 row) + +end; +-- pl/pgsql usecases +declare +rowcount int; +rowcount_big bigint; +spid bigint; +begin +spid := @@spid; +RAISE NOTICE '@@spid: %', spid; +execute 'select * from t1'; +rowcount := @@rowcount; +RAISE NOTICE '@@rowcount: %', rowcount; +execute 'select * from t1'; +rowcount_big := rowcount_big(); +RAISE NOTICE '@@rowcount_big: %', rowcount_big; +end; +/ +--?.* +NOTICE: @@rowcount: 10 +NOTICE: @@rowcount_big: 10 +-- pl/tsql usecases +CREATE OR REPLACE FUNCTION test_pltsql RETURNS INT AS +$$ +declare +rowcount int; +rowcount_big bigint; +spid bigint; +begin +spid := @@spid; +RAISE NOTICE '@@spid: %', spid; +execute 'select * from t1'; +rowcount := @@rowcount; +RAISE NOTICE '@@rowcount: %', rowcount; +execute 'select * from t1'; +rowcount_big := rowcount_big(); +RAISE NOTICE '@@rowcount_big: %', rowcount_big; +return 0; +end; +$$ +LANGUAGE 'pltsql'; +select test_pltsql(); +--?.* +CONTEXT: referenced column: test_pltsql +NOTICE: @@rowcount: 10 +CONTEXT: referenced column: test_pltsql +NOTICE: @@rowcount_big: 10 +CONTEXT: referenced column: test_pltsql + test_pltsql +------------- + 0 +(1 row) + +drop schema functions_test cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table t1 +drop cascades to function test_pltsql() diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index e2b24e038b..4071912506 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -2,3 +2,4 @@ test: init test: basetest test: clustered_index insert_stmt sbr_test +test: functions diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index ab79280b27..0b84288df7 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -17,5 +17,17 @@ create trusted language pltsql validator pltsql_validator; grant usage on language pltsql to public; + +create function fetch_status() + returns int as 'MODULE_PATHNAME' language C; + +create function rowcount() + returns int as 'MODULE_PATHNAME' language C; + +create function rowcount_big() + returns bigint as 'MODULE_PATHNAME' language C; + +create function spid() + returns bigint language sql as $$ select pg_current_sessid() $$; reset search_path; \ No newline at end of file diff --git a/contrib/shark/shark.cpp b/contrib/shark/shark.cpp index 5af5a2c8e0..90d257ecb5 100644 --- a/contrib/shark/shark.cpp +++ b/contrib/shark/shark.cpp @@ -26,11 +26,15 @@ void init_session_vars(void) u_sess->hook_cxt.coreYYlexHook = (void*)pgtsql_core_yylex; u_sess->hook_cxt.plsqlCompileHook = (void*)pltsql_compile; u_sess->hook_cxt.checkVaildUserHook = (void*)check_vaild_username; + u_sess->hook_cxt.fetchStatusHook = (void*)fetch_cursor_end_hook; + u_sess->hook_cxt.rowcountHook = (void*)rowcount_hook; RepallocSessionVarsArrayIfNecessary(); SharkContext *cxt = (SharkContext*) MemoryContextAlloc(u_sess->self_mem_cxt, sizeof(sharkContext)); u_sess->attr.attr_common.extension_session_vars_array[shark_index] = cxt; cxt->dialect_sql = false; + cxt->rowcount = 0; + cxt->fetch_status = FETCH_STATUS_SUCCESS; } SharkContext* GetSessionContext() @@ -47,4 +51,47 @@ void set_extension_index(uint32 index) } void _PG_fini(void) -{} \ No newline at end of file +{} + +void fetch_cursor_end_hook(int fetch_status) +{ + SharkContext *cxt = GetSessionContext(); + switch(fetch_status) { + case FETCH_STATUS_SUCCESS: + case FETCH_STATUS_FAIL: + case FETCH_STATUS_NOT_EXIST: + case FETCH_STATUS_NOT_FETCH: + cxt->fetch_status = fetch_status; + break; + default: + cxt->fetch_status = FETCH_STATUS_FAIL; + break; + } +} + +void rowcount_hook(int64 rowcount) +{ + SharkContext *cxt = GetSessionContext(); + cxt->rowcount = rowcount; +} + +PG_FUNCTION_INFO_V1(fetch_status); +Datum fetch_status(PG_FUNCTION_ARGS) +{ + SharkContext *cxt = GetSessionContext(); + PG_RETURN_INT32(cxt->fetch_status); +} + +PG_FUNCTION_INFO_V1(rowcount); +Datum rowcount(PG_FUNCTION_ARGS) +{ + SharkContext *cxt = GetSessionContext(); + PG_RETURN_INT32(cxt->rowcount); +} + +PG_FUNCTION_INFO_V1(rowcount_big); +Datum rowcount_big(PG_FUNCTION_ARGS) +{ + SharkContext *cxt = GetSessionContext(); + PG_RETURN_INT64(cxt->rowcount); +} diff --git a/contrib/shark/shark.h b/contrib/shark/shark.h index 18ec337928..6bbd0f2db4 100644 --- a/contrib/shark/shark.h +++ b/contrib/shark/shark.h @@ -5,9 +5,23 @@ extern "C" void _PG_init(void); extern "C" void _PG_fini(void); extern "C" void init_session_vars(void); extern "C" void set_extension_index(uint32 index); +extern "C" Datum fetch_status(PG_FUNCTION_ARGS); +extern "C" Datum rowcount(PG_FUNCTION_ARGS); +extern "C" Datum rowcount_big(PG_FUNCTION_ARGS); +static void fetch_cursor_end_hook(int fetch_status); +static void rowcount_hook(int64 rowcount); typedef struct SharkContext { bool dialect_sql; + int fetch_status; + int64 rowcount; } sharkContext; SharkContext* GetSessionContext(); + +typedef enum { + FETCH_STATUS_SUCCESS = 0, // The FETCH statement was successful. + FETCH_STATUS_FAIL = -1, // The FETCH statement failed or the row was beyond the result set. + FETCH_STATUS_NOT_EXIST = -2, // The row fetched is missing. + FETCH_STATUS_NOT_FETCH = -9 // The cursor is not performing a fetch operation. +} CursorFetchStatus; diff --git a/contrib/shark/sql/functions.sql b/contrib/shark/sql/functions.sql new file mode 100644 index 0000000000..0cfeb391b8 --- /dev/null +++ b/contrib/shark/sql/functions.sql @@ -0,0 +1,169 @@ +create schema functions_test; +set search_path = 'functions_test'; + +-- test @@rowcount +create table t1 (c1 int); +select @@rowcount; +insert into t1 values(generate_series(1,10)); +select @@rowcount; +delete t1 where c1 in (1,3,5,7); +select @@rowcount; +update t1 set c1 = 12 where c1 in (2,4); +select @@rowcount; +select * from t1; +select @@rowcount; +select count(*) from t1; +select @@rowcount; + +do $$ +begin +execute 'select * from t1'; +RAISE NOTICE '@@rowcount: %', @@rowcount; +end $$; + +set enable_set_variable_b_format to on; +select @@rowcount; +reset enable_set_variable_b_format; +select @@rowcount; + +begin; +declare c1 cursor for select * from t1; +select @@rowcount; +fetch next from c1; +select @@rowcount; +end; + +select abcd from t1; -- expect error +select @@rowcount; + +-- rowcount_big() +drop table t1; +select rowcount_big(); +create table t1 (c1 int); +select rowcount_big(); +insert into t1 values(generate_series(1,10)); +select rowcount_big(); +delete t1 where c1 in (1,3,5,7); +select rowcount_big(); +update t1 set c1 = 12 where c1 in (2,4); +select rowcount_big(); +select * from t1; +select rowcount_big(); +select count(*) from t1; +select rowcount_big(); + +set enable_set_variable_b_format to on; +select rowcount_big(); +reset enable_set_variable_b_format; +select rowcount_big(); + +begin; +declare c1 cursor for select * from t1; +select rowcount_big(); +fetch next from c1; +select rowcount_big(); +end; + +select abcd from t1; -- expect error +select rowcount_big(); + +-- bypass usecases +set enable_seqscan to off; +set enable_bitmapscan to off; +create index i1 on t1(c1); + +explain (costs off) select * from t1; +select @@rowcount; +select * from t1; +select @@rowcount; + +explain (costs off) insert into t1 values(20); +insert into t1 values(generate_series(20,26)); +select @@rowcount; + +explain (costs off) delete from t1 where c1 < 10; +delete from t1 where c1 < 10; +select @@rowcount; + +explain (costs off) update t1 set c1 = 30 where c1 > 21; +update t1 set c1 = 30 where c1 > 21; +select @@rowcount; + +reset enable_seqscan; +reset enable_bitmapscan; + +-- @@spid +select @@spid; + +-- @@fetch_status +-- single cursor +begin; +cursor c1 for select * from t1; + +fetch next from c1; +select @@fetch_status; +fetch next from c1; +select @@fetch_status; +fetch last from c1; +select @@fetch_status; + +fetch next from c2; -- expect error +select @@fetch_status; +end; + +-- multi cursors +begin; +cursor c1 for select * from t1; +cursor c2 for select * from t1; + +fetch next from c1; +select @@fetch_status; +fetch next from c2; +select @@fetch_status; +fetch last from c1; +select @@fetch_status; +fetch next from c2; +select @@fetch_status; +end; + +-- pl/pgsql usecases +declare +rowcount int; +rowcount_big bigint; +spid bigint; +begin +spid := @@spid; +RAISE NOTICE '@@spid: %', spid; +execute 'select * from t1'; +rowcount := @@rowcount; +RAISE NOTICE '@@rowcount: %', rowcount; +execute 'select * from t1'; +rowcount_big := rowcount_big(); +RAISE NOTICE '@@rowcount_big: %', rowcount_big; +end; +/ + +-- pl/tsql usecases +CREATE OR REPLACE FUNCTION test_pltsql RETURNS INT AS +$$ +declare +rowcount int; +rowcount_big bigint; +spid bigint; +begin +spid := @@spid; +RAISE NOTICE '@@spid: %', spid; +execute 'select * from t1'; +rowcount := @@rowcount; +RAISE NOTICE '@@rowcount: %', rowcount; +execute 'select * from t1'; +rowcount_big := rowcount_big(); +RAISE NOTICE '@@rowcount_big: %', rowcount_big; +return 0; +end; +$$ +LANGUAGE 'pltsql'; + +select test_pltsql(); + +drop schema functions_test cascade; diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index 136f19e6e3..f1993459ea 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -2,4 +2,5 @@ %type tsql_stmt tsql_CreateProcedureStmt tsql_IndexStmt %token TSQL_CLUSTERED TSQL_NONCLUSTERED TSQL_COLUMNSTORE -%type tsql_opt_clustered tsql_opt_columnstore \ No newline at end of file +%type tsql_opt_clustered tsql_opt_columnstore +%token TSQL_ATAT_IDENT diff --git a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp index 791c4ebc23..b377406171 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp +++ b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp @@ -10,5 +10,14 @@ pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg) base_yyerror(yylloc, yyscanner, msg); } +/* TsqlSystemFuncName2() + * Build a properly-qualified reference to a tsql built-in function. + */ +List * +TsqlSystemFuncName2(char *name) +{ + return list_make2(makeString("sys"), makeString(name)); +} + #include "scan-backend.inc" #undef SCANINC diff --git a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h index 229b99807c..0a1f2a884a 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h @@ -1 +1,3 @@ static void pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg); + +List *TsqlSystemFuncName2(char *name); diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index b5c567372c..34764e7ffd 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -661,5 +661,18 @@ tsql_stmt : | ShrinkStmt | /*EMPTY*/ { $$ = NULL; } - | DelimiterStmt - ; \ No newline at end of file + | DelimiterStmt + ; +func_expr_common_subexpr: + TSQL_ATAT_IDENT + { + int len = strlen($1); + errno_t rc = EOK; + + char *name = (char *)palloc(len - 1); + rc = strncpy_s(name, len - 1, $1 + 2, len-2); + securec_check(rc, "\0", "\0"); + + $$ = (Node *)makeFuncCall(TsqlSystemFuncName2(name), NIL, @1); + } + ; diff --git a/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp b/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp index 9ad350ea4f..122956e473 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp +++ b/contrib/shark/src/backend_parser/scan-tsql-epilogue.l.cpp @@ -96,3 +96,21 @@ pgtsql_core_yyfree(void *ptr, core_yyscan_t yyscanner) } #define core_yyset_extra pgtsql_core_yyset_extra + +/* Determine whether a variable name is a predefined T-SQL global variable */ +bool IsTsqlAtatGlobalVar(const char* varname) +{ + size_t varname_len = strlen(varname); + + const size_t MIN_VARNAME_LEN = 6; + const size_t MAX_VARNAME_LEN = 14; + + if ((varname_len < MIN_VARNAME_LEN) || (varname_len > MAX_VARNAME_LEN)) { + return false; + } + + // List of all T-SQL global "@@" variables: + return ((pg_strcasecmp("@@FETCH_STATUS", varname) == 0) || + (pg_strcasecmp("@@ROWCOUNT", varname) == 0) || + (pg_strcasecmp("@@SPID", varname) == 0)); +} diff --git a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h index 02ca534523..3a5a687b22 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h +++ b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h @@ -37,3 +37,5 @@ const uint16 pgtsql_ScanKeywordTokens[] = { #undef YY_DECL #define YY_DECL int pgtsql_core_yylex \ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) + +extern bool IsTsqlAtatGlobalVar(const char *varname); diff --git a/contrib/shark/src/backend_parser/scan-tsql-rule.l b/contrib/shark/src/backend_parser/scan-tsql-rule.l index 9d02e9e1e6..2de41e31e8 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-rule.l +++ b/contrib/shark/src/backend_parser/scan-tsql-rule.l @@ -6,6 +6,7 @@ /* National character. * We will pass this along as a normal character string, * but preceded with an internally-generated "NCHAR". + * but preceded with an internally-generated "NCHAR". */ int kwnum; @@ -61,4 +62,20 @@ yyextra->is_hint_str = false; return IDENT; + } + +{set_identifier} { + SET_YYLLOC(); + char *set_ident = + downcase_truncate_identifier(yytext, yyleng, yyextra->warnOnTruncateIdent); + if (IsTsqlAtatGlobalVar(set_ident)) { + yylval->str = set_ident; + yyextra->ident_quoted = false; + return TSQL_ATAT_IDENT; + } else { + yyless(2); + yylval->str = pstrdup(yytext); + yyextra->is_hint_str = false; + return Op; + } } \ No newline at end of file diff --git a/src/common/backend/catalog/namespace.cpp b/src/common/backend/catalog/namespace.cpp index 9e5ac4238c..5607d6debd 100644 --- a/src/common/backend/catalog/namespace.cpp +++ b/src/common/backend/catalog/namespace.cpp @@ -4127,8 +4127,15 @@ void PushOverrideSearchPath(OverrideSearchPath* newpath, bool inProcedure) * the front, not the back; also notice that we do not check USAGE * permissions for these. */ - if (newpath->addCatalog) + if (newpath->addCatalog) { oidlist = lcons_oid(PG_CATALOG_NAMESPACE, oidlist); + if (DB_IS_CMPT(D_FORMAT)) { + Oid sys_oid = get_namespace_oid(SYS_NAMESPACE_NAME, true); + if (OidIsValid(sys_oid) && !list_member_oid(oidlist, sys_oid)) { + oidlist = lcons_oid(sys_oid, oidlist); + } + } + } if (newpath->addTemp && OidIsValid(u_sess->catalog_cxt.myTempNamespace)) oidlist = lcons_oid(u_sess->catalog_cxt.myTempNamespace, oidlist); diff --git a/src/common/pl/plpgsql/src/pl_comp.cpp b/src/common/pl/plpgsql/src/pl_comp.cpp index f935e11c76..60e78eefb0 100644 --- a/src/common/pl/plpgsql/src/pl_comp.cpp +++ b/src/common/pl/plpgsql/src/pl_comp.cpp @@ -1002,7 +1002,8 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, else func->fn_is_trigger = PLPGSQL_NOT_TRIGGER; - if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE) { + if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE || + proc_struct->pronamespace == get_namespace_oid("sys", true)) { current_searchpath = fetch_search_path(false); if (current_searchpath == NIL) { ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNDEFINED_SCHEMA), diff --git a/src/gausskernel/optimizer/commands/portalcmds.cpp b/src/gausskernel/optimizer/commands/portalcmds.cpp index 9204609046..46ac239576 100644 --- a/src/gausskernel/optimizer/commands/portalcmds.cpp +++ b/src/gausskernel/optimizer/commands/portalcmds.cpp @@ -158,6 +158,23 @@ void PerformCursorOpen(PlannedStmt* stmt, ParamListInfo params, const char* quer */ } +/** + * nprocessed = -1 if fetch error + */ +void cursorFetchEndHook(FetchStmt* stmt, int nprocessed) +{ + if (stmt->ismove) { + return; + } + + if (u_sess->hook_cxt.fetchStatusHook) { + ((FetchStatusHook)(u_sess->hook_cxt.fetchStatusHook))(nprocessed > 0 ? 0 : -1); + } + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(nprocessed > 0 ? nprocessed : 0); + } +} + /* * PerformPortalFetch * Execute SQL FETCH or MOVE command. @@ -178,12 +195,15 @@ void PerformPortalFetch(FetchStmt* stmt, DestReceiver* dest, char* completionTag * Disallow empty-string cursor name (conflicts with protocol-level * unnamed portal). */ - if (!stmt->portalname || stmt->portalname[0] == '\0') + if (!stmt->portalname || stmt->portalname[0] == '\0') { + cursorFetchEndHook(stmt, -1); ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_NAME), errmsg("invalid cursor name: must not be empty"))); + } /* get the portal from the portal name */ portal = GetPortalByName(stmt->portalname); if (!PortalIsValid(portal)) { + cursorFetchEndHook(stmt, -1); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("cursor \"%s\" does not exist", stmt->portalname))); return; /* keep compiler happy */ } @@ -196,7 +216,16 @@ void PerformPortalFetch(FetchStmt* stmt, DestReceiver* dest, char* completionTag bool needResetErrMsg = stp_disable_xact_and_set_err_msg(&savedIsAllowCommitRollback, STP_XACT_OPEN_FOR); /* Do it */ - nprocessed = PortalRunFetch(portal, stmt->direction, stmt->howMany, dest); + PG_TRY(); + { + nprocessed = PortalRunFetch(portal, stmt->direction, stmt->howMany, dest); + } + PG_CATCH(); + { + cursorFetchEndHook(stmt, -1); + PG_RE_THROW(); + } + PG_END_TRY(); stp_reset_xact_state_and_err_msg(savedIsAllowCommitRollback, needResetErrMsg); @@ -210,6 +239,7 @@ void PerformPortalFetch(FetchStmt* stmt, DestReceiver* dest, char* completionTag nprocessed); securec_check_ss(rc, "", ""); } + cursorFetchEndHook(stmt, nprocessed); } /* diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index 4c0e1bebed..17e7dfcef3 100755 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -1617,13 +1617,18 @@ void ProcessUtility(processutility_context* processutility_cxt, * Record the number of rows affected into the session, but only support * DML statement now, for DDL statement, always set to 0 */ - if(nodeTag(processutility_cxt->parse_tree) != T_ExecuteStmt) { + NodeTag nt = nodeTag(processutility_cxt->parse_tree); + if (nt != T_ExecuteStmt) { u_sess->statement_cxt.current_row_count = 0; u_sess->statement_cxt.last_row_count = u_sess->statement_cxt.current_row_count; - /* If it is an EXECUTE statement here, the PortalRun function will be + /* If it is an EXECUTE/FETCH statement here, the PortalRun function will be called twice nested, and the right data will be modified when it is first executed (Generally in function ExecutorRun), so there do nothing when it is called again to avoid overwriting */ + if ((nt != T_FetchStmt || ((FetchStmt*)(processutility_cxt->parse_tree))->ismove) && + u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(0); + } } } diff --git a/src/gausskernel/runtime/executor/execMain.cpp b/src/gausskernel/runtime/executor/execMain.cpp index e2dc9f4702..e0fa81011f 100755 --- a/src/gausskernel/runtime/executor/execMain.cpp +++ b/src/gausskernel/runtime/executor/execMain.cpp @@ -580,6 +580,9 @@ void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count) u_sess->statement_cxt.last_row_count = u_sess->statement_cxt.current_row_count; break; } + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(queryDesc->estate->es_processed); + } } u_sess->pcache_cxt.cur_stmt_name = old_stmt_name; diff --git a/src/gausskernel/runtime/opfusion/opfusion_delete.cpp b/src/gausskernel/runtime/opfusion/opfusion_delete.cpp index 640bca3197..e941cacfa2 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_delete.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_delete.cpp @@ -313,6 +313,11 @@ bool DeleteFusion::execute(long max_rows, char *completionTag) FreeExecutorStateForOpfusion(m_c_local.m_estate); u_sess->statement_cxt.current_row_count = nprocessed; u_sess->statement_cxt.last_row_count = u_sess->statement_cxt.current_row_count; + + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(nprocessed); + } + return success; } diff --git a/src/gausskernel/runtime/opfusion/opfusion_insert.cpp b/src/gausskernel/runtime/opfusion/opfusion_insert.cpp index ef4b6cfcbb..81be5e7430 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_insert.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_insert.cpp @@ -493,6 +493,11 @@ bool InsertFusion::execute(long max_rows, char* completionTag) FreeExecutorStateForOpfusion(m_c_local.m_estate); u_sess->statement_cxt.current_row_count = nprocessed; u_sess->statement_cxt.last_row_count = u_sess->statement_cxt.current_row_count; + + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(nprocessed); + } + return success; } diff --git a/src/gausskernel/runtime/opfusion/opfusion_select.cpp b/src/gausskernel/runtime/opfusion/opfusion_select.cpp index 75f3fd9283..6c82dbe1d0 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_select.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_select.cpp @@ -168,6 +168,10 @@ bool SelectFusion::execute(long max_rows, char* completionTag) /* instr unique sql - we assume that this is no nesting calling of Fusion::execute */ UniqueSQLStatCountReturnedRows(nprocessed); + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(nprocessed); + } + return success; } diff --git a/src/gausskernel/runtime/opfusion/opfusion_update.cpp b/src/gausskernel/runtime/opfusion/opfusion_update.cpp index ad8212b9bf..10aae0eadc 100644 --- a/src/gausskernel/runtime/opfusion/opfusion_update.cpp +++ b/src/gausskernel/runtime/opfusion/opfusion_update.cpp @@ -599,6 +599,10 @@ lreplace: bucketCloseRelation(bucket_rel); } + if (u_sess->hook_cxt.rowcountHook) { + ((RowcountHook)(u_sess->hook_cxt.rowcountHook))(nprocessed); + } + return nprocessed; } diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 257b0582ab..43782e0a80 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -3004,6 +3004,8 @@ typedef struct knl_u_hook_context { void *enableProcedureExecutementHook; void *plsqlCompileHook; void *checkVaildUserHook; + void *fetchStatusHook; + void *rowcountHook; } knl_u_hook_context; typedef struct knl_u_libsw_context { diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 804af8cbfc..9564a058ac 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -221,4 +221,7 @@ extern bool IsSchemaInDistribution(const Oid namespaceOid); extern Oid GetNamespaceIdbyRelId(const Oid relid); extern char *flatten_reloptions(Oid relid); extern void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf); +typedef void (*FetchStatusHook)(int fetchStatus); +typedef void (*RowcountHook)(int64 rowcount); + #endif /* UTILITY_H */ -- Gitee From 570c2266b75731dcbb34bc29d4e346703ed9a787 Mon Sep 17 00:00:00 2001 From: zhubin79 <18784715772@163.com> Date: Thu, 13 Mar 2025 20:54:25 +0800 Subject: [PATCH 02/11] =?UTF-8?q?D=E5=BA=93=E5=B8=B8=E7=94=A8=E8=A7=86?= =?UTF-8?q?=E5=9B=BE=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/basetest.out | 2 +- contrib/shark/expected/test_sysviews.out | 343 ++++++++++++++++ contrib/shark/parallel_schedule | 1 + contrib/shark/shark--1.0.sql | 494 ++++++++++++++++++++++- contrib/shark/sql/test_sysviews.sql | 145 +++++++ contrib/shark/src/pltsql/pl_comp.cpp | 3 +- src/common/backend/catalog/namespace.cpp | 3 - src/common/pl/plpgsql/src/pl_comp.cpp | 2 +- src/include/catalog/namespace.h | 2 + 9 files changed, 988 insertions(+), 7 deletions(-) create mode 100644 contrib/shark/expected/test_sysviews.out create mode 100644 contrib/shark/sql/test_sysviews.sql diff --git a/contrib/shark/expected/basetest.out b/contrib/shark/expected/basetest.out index c1d1230347..0426656ae3 100644 --- a/contrib/shark/expected/basetest.out +++ b/contrib/shark/expected/basetest.out @@ -17,7 +17,7 @@ NOTICE: The COLUMNSTORE option is currently ignored DO $$ BEGIN create columnstore index on t1 (a); -end $$ language pltsql; +end $$; NOTICE: The COLUMNSTORE option is currently ignored LINE 3: create columnstore index on t1 (a); ^ diff --git a/contrib/shark/expected/test_sysviews.out b/contrib/shark/expected/test_sysviews.out new file mode 100644 index 0000000000..c993d8a3c7 --- /dev/null +++ b/contrib/shark/expected/test_sysviews.out @@ -0,0 +1,343 @@ +create schema sys_view_test; +set search_path to sys_view_test; +-- show views struct +\d sys.sysobjects + View "sys.sysobjects" + Column | Type | Modifiers +------------------+--------------------------------+----------- + name | name | + id | oid | + xtype | character(2) | + uid | oid | + info | smallint | + status | integer | + base_schema_ver | integer | + replinfo | integer | + parent_obj | oid | + crdate | timestamp(3) without time zone | + ftcatid | smallint | + schema_ver | integer | + stats_schema_ver | integer | + type | character(2) | + userstat | smallint | + sysstat | smallint | + indexdel | smallint | + refdate | timestamp(3) without time zone | + version | integer | + deltrig | integer | + instrig | integer | + updtrig | integer | + seltrig | integer | + category | integer | + cache | smallint | + +\d sys.syscolumns + View "sys.syscolumns" + Column | Type | Modifiers +-------------+------------------------+----------- + name | name | + id | oid | + xtype | oid | + typestat | tinyint | + xusertype | oid | + length | smallint | + xprec | tinyint | + xscale | tinyint | + colid | smallint | + xoffset | smallint | + bitpos | tinyint | + reserved | tinyint | + colstat | smallint | + cdefault | integer | + domain | integer | + number | smallint | + colorder | smallint | + autoval | bytea | + offset | smallint | + collationid | oid | + status | tinyint | + type | oid | + usertype | oid | + printfmt | character varying(255) | + prec | smallint | + scale | integer | + iscomputed | integer | + isoutparam | integer | + isnullable | integer | + collation | name | + +\d sys.sysindexes + View "sys.sysindexes" + Column | Type | Modifiers +----------------+----------+----------- + id | oid | + status | integer | + first | bytea | + indid | oid | + root | bytea | + minlen | smallint | + keycnt | smallint | + groupid | smallint | + dpages | integer | + reserved | integer | + used | integer | + rowcnt | bigint | + rowmodctr | integer | + reserved3 | integer | + reserved4 | integer | + xmaxlen | integer | + maxirow | integer | + OrigFillFactor | integer | + StatVersion | tinyint | + reserved2 | integer | + FirstIAM | bytea | + impid | smallint | + lockflags | smallint | + pgmodctr | integer | + keys | bytea | + name | name | + statblob | bytea | + maxlen | integer | + rows | integer | + +\d sys.sysindexkeys + View "sys.sysindexkeys" + Column | Type | Modifiers +--------+----------+----------- + id | oid | + indid | oid | + colid | smallint | + keyno | smallint | + +-- test select +select * from sys.sysobjects order by id limit 1; + name | id | xtype | uid | info | status | base_schema_ver | replinfo | parent_obj | crdate | ftcatid | schema_ver | stats_schema_ver | type | userstat | sysstat | indexdel | refdate | version | deltrig | instrig | updtrig | seltrig | category | cache +----------+----+-------+-----+------+--------+-----------------+----------+------------+--------+---------+------------+------------------+------+----------+---------+----------+---------+---------+---------+---------+---------+---------+----------+------- + byteaout | 31 | FN | 11 | 0 | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | FN | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 +(1 row) + +select * from sys.syscolumns order by id limit 1; + name | id | xtype | typestat | xusertype | length | xprec | xscale | colid | xoffset | bitpos | reserved | colstat | cdefault | domain | number | colorder | autoval | offset | collationid | status | type | usertype | printfmt | prec | scale | iscomputed | isoutparam | isnullable | collation +----------+----+-------+----------+-----------+--------+-------+--------+-------+---------+--------+----------+---------+----------+--------+--------+----------+---------+--------+-------------+--------+------+----------+----------+------+-------+------------+------------+------------+----------- + byteaout | 31 | 17 | 0 | 17 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | | | 0 | 0 | | 0 | | 0 | 17 | 17 | | | | 0 | 0 | 1 | +(1 row) + +select * from sys.sysindexes order by id, indid limit 1; + id | status | first | indid | root | minlen | keycnt | groupid | dpages | reserved | used | rowcnt | rowmodctr | reserved3 | reserved4 | xmaxlen | maxirow | OrigFillFactor | StatVersion | reserved2 | FirstIAM | impid | lockflags | pgmodctr | keys | name | statblob | maxlen | rows +-----+--------+-------+-------+------+--------+--------+---------+--------+----------+------+--------+-----------+-----------+-----------+---------+---------+----------------+-------------+-----------+----------+-------+-----------+----------+------+-----------------------------------+----------+--------+------ + 826 | 0 | | 827 | | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | | pg_default_acl_role_nsp_obj_index | | 0 | 0 +(1 row) + +select * from sys.sysindexkeys order by id, indid limit 1; + id | indid | colid | keyno +-----+-------+-------+------- + 826 | 827 | 1 | 1 +(1 row) + +select "OrigFillFactor", "StatVersion", "FirstIAM" from sys.sysindexes order by id, indid limit 1; + OrigFillFactor | StatVersion | FirstIAM +----------------+-------------+---------- + 0 | 0 | +(1 row) + +-- prepare data +CREATE TABLE student +( + std_id INT PRIMARY KEY, + std_name VARCHAR(20) NOT NULL, + std_sex VARCHAR(6), + std_birth DATE, + std_in DATE NOT NULL, + std_address VARCHAR(100) +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "student_pkey" for table "student" +CREATE TABLE teacher +( + tec_id INT PRIMARY KEY, + tec_name VARCHAR(20) NOT NULL, + tec_job VARCHAR(15), + tec_sex VARCHAR(6), + tec_age INT default 20, + tec_in DATE NOT NULL +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "teacher_pkey" for table "teacher" +CREATE TABLE class +( + cla_id INT PRIMARY KEY, + cla_name VARCHAR(20) NOT NULL, + cla_teacher INT NOT NULL +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "class_pkey" for table "class" +ALTER TABLE class ADD CONSTRAINT fk_tec_id FOREIGN KEY (cla_teacher) REFERENCES teacher(tec_id) ON DELETE CASCADE; +CREATE TABLE school_department +( + depart_id INT PRIMARY KEY, + depart_name VARCHAR(30) NOT NULL, + depart_teacher INT NOT NULL +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "school_department_pkey" for table "school_department" +ALTER TABLE school_department ADD CONSTRAINT fk_depart_tec_id FOREIGN KEY (depart_teacher) REFERENCES teacher(tec_id) ON DELETE CASCADE; +CREATE TABLE course +( + cor_id INT PRIMARY KEY, + cor_name VARCHAR(30) NOT NULL, + cor_type VARCHAR(20), + credit DOUBLE PRECISION +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "course_pkey" for table "course" +create or replace view teacher_info as +select c.cla_name, t.tec_name, t.tec_job, t.tec_sex, t.tec_age +from teacher t +left join class c on c.cla_teacher = t.tec_id; +create table t_log (c1 int, c2 varchar(20), c3 timestamp); +create sequence if not exists t_seq + increment by 1 + nominvalue + nomaxvalue + start with 1 + nocycle; +select t_seq.nextval; + nextval +--------- + 1 +(1 row) + +create or replace function tg_log() returns trigger as +$$ +begin + insert into t_log values (new.std_id, new.std_name, SYSDATE); + return new; +end; +$$ language plpgsql; +create trigger log_student_after_insert +after insert on student +for each row +execute procedure tg_log(); +create or replace procedure test_sum(in a int, in b int, out c int) +as +begin + c = a + b; +end; +/ +create or replace function test_sub(num1 int, num2 int) +returns int as $$ +begin + return num1 - num2; +end; +$$ language plpgsql; +CREATE OR REPLACE SYNONYM syn_tbl FOR student; +CREATE OR REPLACE SYNONYM syn_tr FOR log_student_after_insert; +select obj.name, obj.xtype, obj.type from sys.sysobjects obj +left join pg_namespace s on s.oid = obj.uid +where s.nspname = 'sys_view_test' +order by id; + name | xtype | type +------------------------+-------+------ + student | U | U + student_pkey | PK | K + teacher | U | U + | D | D + teacher_pkey | PK | K + class | U | U + class_pkey | PK | K + fk_tec_id | F | F + school_department | U | U + school_department_pkey | PK | K + fk_depart_tec_id | F | F + course | U | U + course_pkey | PK | K + teacher_info | V | V + t_log | U | U + t_seq | SO | SO + tg_log | FN | FN + test_sum | P | P + test_sub | FN | FN + syn_tbl | SN | SN + syn_tr | SN | SN +(21 rows) + +select col.name, col.length, col.colid, col.status, col.prec, col.scale, col.iscomputed, col.isoutparam, col.isnullable, col.collation +from sys.syscolumns col +left join pg_class c on col.id = c.oid +left join pg_namespace s on s.oid = c.relnamespace +where s.nspname = 'sys_view_test' +order by id, colid; + name | length | colid | status | prec | scale | iscomputed | isoutparam | isnullable | collation +----------------+--------+-------+--------+------+-------+------------+------------+------------+----------- + std_id | 4 | 1 | 0 | 10 | | 0 | 0 | 1 | + std_name | 24 | 2 | 0 | 0 | 24 | 0 | 0 | 1 | default + std_sex | 10 | 3 | 8 | 0 | 10 | 0 | 0 | 0 | default + std_birth | 4 | 4 | 8 | 10 | | 0 | 0 | 0 | + std_in | 4 | 5 | 0 | 10 | | 0 | 0 | 1 | + std_address | 104 | 6 | 8 | 0 | 104 | 0 | 0 | 0 | default + tec_id | 4 | 1 | 0 | 10 | | 0 | 0 | 1 | + tec_name | 24 | 2 | 0 | 0 | 24 | 0 | 0 | 1 | default + tec_job | 19 | 3 | 8 | 0 | 19 | 0 | 0 | 0 | default + tec_sex | 10 | 4 | 8 | 0 | 10 | 0 | 0 | 0 | default + tec_age | 4 | 5 | 8 | 10 | | 0 | 0 | 0 | + tec_in | 4 | 6 | 0 | 10 | | 0 | 0 | 1 | + cla_id | 4 | 1 | 0 | 10 | | 0 | 0 | 1 | + cla_name | 24 | 2 | 0 | 0 | 24 | 0 | 0 | 1 | default + cla_teacher | 4 | 3 | 0 | 10 | | 0 | 0 | 1 | + depart_id | 4 | 1 | 0 | 10 | | 0 | 0 | 1 | + depart_name | 34 | 2 | 0 | 0 | 34 | 0 | 0 | 1 | default + depart_teacher | 4 | 3 | 0 | 10 | | 0 | 0 | 1 | + cor_id | 4 | 1 | 0 | 10 | | 0 | 0 | 1 | + cor_name | 34 | 2 | 0 | 0 | 34 | 0 | 0 | 1 | default + cor_type | 24 | 3 | 8 | 0 | 24 | 0 | 0 | 0 | default + credit | 8 | 4 | 8 | 0 | | 0 | 0 | 0 | + cla_name | 24 | 1 | 8 | 0 | 24 | 0 | 0 | 0 | default + tec_name | 24 | 2 | 8 | 0 | 24 | 0 | 0 | 0 | default + tec_job | 19 | 3 | 8 | 0 | 19 | 0 | 0 | 0 | default + tec_sex | 10 | 4 | 8 | 0 | 10 | 0 | 0 | 0 | default + tec_age | 4 | 5 | 8 | 10 | | 0 | 0 | 0 | + c1 | 4 | 1 | 8 | 10 | | 0 | 0 | 0 | + c2 | 24 | 2 | 8 | 0 | 24 | 0 | 0 | 0 | default + c3 | 8 | 3 | 8 | 26 | | 0 | 0 | 0 | +(30 rows) + +select ind.name, ind.keycnt, ind."OrigFillFactor", ind.rows from sys.sysindexes ind +left join pg_class c on c.oid = ind.indid +left join pg_namespace s on c.relnamespace = s.oid +where s.nspname = 'sys_view_test' +order by id, indid; + name | keycnt | OrigFillFactor | rows +------------------------+--------+----------------+------ + student_pkey | 0 | 0 | 0 + teacher_pkey | 0 | 0 | 0 + class_pkey | 0 | 0 | 0 + school_department_pkey | 0 | 0 | 0 + course_pkey | 0 | 0 | 0 +(5 rows) + +select c_tab.relname as tabname, c_ind.relname as indname, ind.colid, ind.keyno from sys.sysindexkeys ind +left join pg_class c_ind on c_ind.oid = ind.indid +left join pg_class c_tab on c_tab.oid = ind.id +left join pg_namespace s on c_ind.relnamespace = s.oid +where s.nspname = 'sys_view_test' +order by id, indid; + tabname | indname | colid | keyno +-------------------+------------------------+-------+------- + student | student_pkey | 1 | 1 + teacher | teacher_pkey | 1 | 1 + class | class_pkey | 1 | 1 + school_department | school_department_pkey | 1 | 1 + course | course_pkey | 1 | 1 +(5 rows) + +drop synonym syn_tr; +drop synonym syn_tbl; +drop function test_sub; +drop procedure test_sum; +drop table t_log; +drop view teacher_info; +drop table course; +drop table school_department; +drop table class; +drop table teacher; +drop table student; +reset search_path; +drop schema sys_view_test cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to sequence sys_view_test.t_seq +drop cascades to function sys_view_test.tg_log() diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index 4071912506..7744e7221e 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -3,3 +3,4 @@ test: init test: basetest test: clustered_index insert_stmt sbr_test test: functions +test: test_sysviews diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index 0b84288df7..8aa94dea08 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -30,4 +30,496 @@ create function rowcount_big() create function spid() returns bigint language sql as $$ select pg_current_sessid() $$; -reset search_path; \ No newline at end of file +-- sys view: sysobjects +create or replace view sys.sysobjects as +select + cast(t.relname as name) as name, + cast(t.oid as oid) as id, + cast(case t.relkind + when 'r' then + case s.nspname + when 'information_schema' then 'S' + when 'pg_catalog' then 'S' + else 'U' + end + when 'v' then 'V' + when 'm' then 'V' + else 'SO' + end as char(2)) as xtype, + cast(t.relnamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(0 as oid) as parent_obj, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast(case t.relkind + when 'r' then + case s.nspname + when 'information_schema' then 'S' + when 'pg_catalog' then 'S' + else 'U' + end + when 'r' then 'U' + when 'v' then 'V' + when 'm' then 'V' + else 'SO' + end as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_class t +inner join pg_namespace s on s.oid = t.relnamespace +where t.relpersistence in ('p', 'u', 't') +and t.relkind in ('r', 'v', 'm', 'S') +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT') +union all +select + cast(c.conname as name) as name, + cast(c.oid as oid) as id, + cast(case c.contype + when 'f' then 'F' + when 'c' then 'C' + when 'p' then 'PK' + when 'u' then 'UQ' + end as char(2) )as xtype, + cast(c.connamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(c.conrelid as int) as parent_obj, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast(case c.contype + when 'f' then 'F' + when 'c' then 'C' + when 'p' then 'K' + when 'u' then 'K' + end as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_constraint c +inner join pg_class t on c.conrelid = t.oid +inner join pg_namespace s on s.oid = c.connamespace +where c.contype in ('f', 'c', 'p', 'u') +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT') +union all +select + cast(null as name) as name, + cast(ad.oid as oid) as id, + cast('D' as char(2)) as xtype, + cast(c.relnamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(ad.adrelid as oid) as object_id, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast('D' as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_attrdef ad +inner join pg_class c on ad.adrelid = c.oid +inner join pg_namespace s on c.relnamespace = s.oid +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), 'SELECT') +union all +select + cast(p.proname as name) as name, + cast(p.oid as oid) as id, + cast(case p.prokind + when 'f' then + case p.proisagg when true then 'AF' else 'FN' end + else 'P' + end as char(2)) as xtype, + cast(p.pronamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(0 as int) as parent_obj, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast(case p.prokind + when 'f' then + case p.proisagg when true then 'AF' else 'FN' end + else 'P' + end as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +and has_function_privilege(p.oid, 'EXECUTE') +union all +select + cast(t.tgname as name) as name, + cast(t.oid as oid) as id, + cast('TR' as char(2)) as xtype, + cast(c.relnamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(0 as int) as parent_obj, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast('TR' as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_trigger t +inner join pg_class c on t.tgrelid = t.oid +inner join pg_namespace s on c.relnamespace = s.oid +where has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), 'SELECT,TRIGGER') +union all +select + cast(y.synname as name) as name, + cast(y.oid as oid) as id, + cast('SN' as char(2)) as xtype, + cast(y.synnamespace as oid) as uid, + cast(0 as smallint) as info, + cast(0 as int) as status, + cast(0 as int) as base_schema_ver, + cast(0 as int) as replinfo, + cast(0 as int) as parent_obj, + cast(null as timestamp(3)) as crdate, + cast(0 as smallint) as ftcatid, + cast(0 as int) as schema_ver, + cast(0 as int) as stats_schema_ver, + cast('SN' as char(2)) as type, + cast(0 as smallint) as userstat, + cast(0 as smallint) as sysstat, + cast(0 as smallint) as indexdel, + cast(null as timestamp(3)) as refdate, + cast(0 as int) as version, + cast(0 as int) as deltrig, + cast(0 as int) as instrig, + cast(0 as int) as updtrig, + cast(0 as int) as seltrig, + cast(0 as int) as category, + cast(0 as smallint) as cache +from pg_synonym y; +grant select on sys.sysobjects to public; + +create or replace function sys.tsql_type_max_length_helper(in type text, in typelen int, in typemod int) +returns smallint +as $$ +declare + max_length smallint; + precision int; +begin + max_length := -1; + + if typelen != -1 then + case + when lower(type) in ('numeric', 'decimal') then + precision := ((typemod - 4) >> 16) & 65535; + /* Each four bits (decimal bits) takes up two bytes and then adds an additional overhead of eight bytes to the entire data. */ + max_length := (ceil((precision / 4 + 1) * 2 + 8))::smallint; + else max_length := typelen; + end case; + return max_length; + end if; + + if typemod != -1 then + max_length = typemod; + end if; + return max_length; +end; +$$ language plpgsql immutable strict; + +create or replace function sys.tsql_type_precision_helper(in type text, in typemod int) returns smallint +as $$ +declare + precision int := -1; +begin + if type is null then + return -1; + end if; + + if typemod = -1 then + case lower(type) + when 'int1' then precision := 3; + when 'int2' then precision := 5; + when 'int4' then precision := 10; + when 'int8' then precision := 19; + when 'bit' then precision := 1; + when 'date' then precision := 10; + when 'time' then precision := 15; + when 'smalldatetime' then precision := 16; + when 'timestamp' then precision := 26; + when 'real' then precision := 24; + when 'float' then precision := 53; + when 'money' then precision := 19; + else precision := 0; + end case; + return precision; + end if; + + case lower(type) + when 'numeric' then precision := ((typemod - 4) >> 16) & 65535; + when 'decimal' then precision := ((typemod - 4) >> 16) & 65535; + when 'smalldatetime' then precision := 16; + when 'timestamp' then + case typemod + when 0 then precision := 19; + when 1 then precision := 21; + when 2 then precision := 22; + when 3 then precision := 23; + when 4 then precision := 24; + when 5 then precision := 25; + when 6 then precision := 26; + end case; + when 'time' then + case typemod + when 0 then precision := 8; + when 1 then precision := 10; + when 2 then precision := 11; + when 3 then precision := 12; + when 4 then precision := 13; + when 5 then precision := 14; + when 6 then precision := 15; + end case; + else precision := 0; + end case; + return precision; +end; +$$ language plpgsql immutable strict; + +create or replace function sys.tsql_type_scale_helper(in type text, in typemod int) returns int +as $$ +declare + scale int; +begin + if type is null then + return -1; + end if; + + if typemod != -1 then + return typemod; + end if; + + case lower(type) + when 'decimal' then scale = (typemod - 4) & 65535; + when 'numeric' then scale = (typemod - 4) & 65535; + else scale = null; + end case; + return scale; +end; +$$ language plpgsql immutable strict; + +-- sys view: syscolumns +create or replace view sys.syscolumns as +select + cast(a.attname as name) as name, + cast(c.oid as oid) as id, + cast(t.oid as oid) as xtype, + cast(0 as tinyint) as typestat, + cast(t.oid as oid) as xusertype, + cast(sys.tsql_type_max_length_helper(t.typname, a.attlen, a.atttypmod) as smallint) as length, + cast(0 as tinyint) as xprec, + cast(0 as tinyint) as xscale, + cast(a.attnum as smallint) as colid, + cast(0 as smallint) as xoffset, + cast(0 as tinyint) as bitpos, + cast(0 as tinyint) as reserved, + cast(0 as smallint) as colstat, + cast(d.oid as int) as cdefault, + cast(coalesce((select oid from pg_constraint where conrelid = c.oid + and contype = 'c' and a.attnum = any(conkey) limit 1), 0) + as int) as domain, + cast(0 as smallint) as number, + cast(0 as smallint) as colorder, + cast(null as bytea) as autoval, + cast(a.attnum as smallint) as offset, + cast(case when a.attcollation = 0 then null else a.attcollation end as oid) as collationid, + cast(case when not a.attnotnull then 8 else 0 end as tinyint) as status, + cast(t.oid as oid) as type, + cast(t.oid as oid) as usertype, + cast(null as varchar(255)) as printfmt, + cast(sys.tsql_type_precision_helper(t.typname, a.atttypmod) as smallint) as prec, + cast(sys.tsql_type_scale_helper(t.typname, a.atttypmod) as int) as scale, + cast(case when d.adgencol = 's' then 1 else 0 end as int) as iscomputed, + cast(0 as int) as isoutparam, + cast(a.attnotnull as int) as isnullable, + cast(coll.collname as name) as collation +from pg_attribute a +inner join pg_class c on c.oid = a.attrelid +inner join pg_type t on t.oid = a.atttypid +inner join pg_namespace sch on c.relnamespace = sch.oid +left join pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = a.attcollation +where not a.attisdropped +and a.attnum > 0 +and c.relkind in ('r', 'v', 'm', 'f', 'p') +and c.parttype = 'n' +and has_column_privilege(a.attrelid, a.attname, 'select') +union all +select + cast(pgproc.proname as name) as name, + cast(pgproc.oid as oid) as id, + cast(case when pgproc.proallargtypes is null then split_part(pgproc.proargtypes::varchar, ' ', params.ordinal_position) + else split_part(btrim(pgproc.proallargtypes::text,'{}'), ',', params.ordinal_position) end AS oid) as xtype, + cast(0 as tinyint) as typestat, + cast(xtype as oid) as xusertype, + cast(0 as smallint) as length, + cast(0 as tinyint) as xprec, + cast(0 as tinyint) as xscale, + cast(params.ordinal_position as smallint) as colid, + cast(0 as smallint) as offset, + cast(0 as tinyint) as bitpos, + cast(0 as tinyint) as reserved, + cast(0 as smallint) as colstat, + cast(null as int) as cdefault, + cast(null as int) as domain, + cast(0 as smallint) as number, + cast(0 as smallint) as colorder, + cast(null as bytea) as autoval, + cast(0 as smallint) as offset, + cast(case when params.collation_name is null then null else coll.oid end as oid) as collationid, + cast(case params.parameter_mode when 'OUT' then 64 when 'INOUT' then 64 else 0 end as tinyint) as status, + cast(case when pgproc.proallargtypes is null then split_part(pgproc.proargtypes::varchar, ' ', params.ordinal_position) + else split_part(btrim(pgproc.proallargtypes::text,'{}'), ',', params.ordinal_position) end AS oid) as type, + cast(type as oid) as usertype, + cast(null as varchar(255)) as printfmt, + cast(params.numeric_precision as smallint) as prec, + cast(params.numeric_scale as int) as scale, + cast(0 as int) as iscomputed, + cast(case params.parameter_mode when 'OUT' then 1 when 'INOUT' then 1 else 0 end as int) as iscomputed, + cast(1 as int) as isnullable, + cast(params.collation_name as name) as collation +from information_schema.routines routine +left join information_schema.parameters params + on routine.specific_schema = params.specific_schema + and routine.specific_name = params.specific_name +left join pg_collation coll on coll.collname = params.collation_name +/* routine.specific_name is constructed by concatenating procedure name and oid */ +left join pg_proc pgproc on routine.specific_name = concat(pgproc.proname, '_', pgproc.oid) +left join pg_namespace sch on sch.oid = pgproc.pronamespace +where has_function_privilege(pgproc.oid, 'EXECUTE'); +grant select on sys.syscolumns to public; + +create or replace function sys.tsql_relation_reloptions_helper(in reloptions text[], in targetKey text) +returns text as $$ + select split_part(entry, '=', 2) + from unnest(reloptions) as entry + where split_part(entry, '=', 1) = lower(targetKey) + limit 1; +$$ language sql; + +-- sys.sysindexes +create or replace view sys.sysindexes as +select + cast(i.indrelid as oid) as id, + cast(0 as int) as status, + cast(null as bytea) as first, + cast(i.indexrelid as oid) as indid, + cast(null as bytea) as root, + cast(0 as smallint) as minlen, + cast(0 as smallint) as keycnt, + cast(0 as smallint) as groupid, + cast(0 as int) as dpages, + cast(0 as int) as reserved, + cast(0 as int) as used, + cast(0 as bigint) as rowcnt, + cast(0 as int) as rowmodctr, + cast(0 as int) as reserved3, + cast(0 as int) as reserved4, + cast(0 as int) as xmaxlen, + cast(0 as int) as maxirow, + cast(case + when sys.tsql_relation_reloptions_helper(c.reloptions, 'fillfactor') is null then '0' + else sys.tsql_relation_reloptions_helper(c.reloptions, 'fillfactor') + end as int) as "OrigFillFactor", + cast(0 as tinyint) as "StatVersion", + cast(0 as int) as reserved2, + cast(null as bytea) as "FirstIAM", + cast(0 as smallint) as impid, + cast(0 as smallint) as lockflags, + cast(0 as int) as pgmodctr, + cast(null as bytea) as keys, + cast(c.relname as name) as name, + cast(null as bytea) as statblob, + cast(0 as int) as maxlen, + cast(0 as int) as rows +from pg_class c +inner join pg_namespace s on s.oid = c.relnamespace +inner join pg_index i on i.indexrelid = c.oid +where c.relkind = 'i' and i.indisenable and i.indisvalid and c.parttype = 'n' +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), 'SELECT'); +grant select on sys.sysindexes to public; + +-- sys.indexkey +create or replace view sys.sysindexkeys as +select + cast(i.indrelid as oid) as id, + cast(i.indexrelid as oid) as indid, + cast(i.indkey[idx.pos] as smallint) as colid, + cast((idx.pos + 1) as smallint) as keyno +from pg_index as i +inner join pg_class c_ind on c_ind.oid = i.indexrelid +inner join pg_class c_tab on c_tab.oid = i.indrelid +inner join pg_namespace s on s.oid = c_ind.relnamespace +join pg_class c on i.indexrelid = c.oid, +lateral ( + select generate_series(0, array_length(i.indkey::int2[], 1) - 1) as pos +) as idx +where has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c_tab.relname), 'SELECT'); +grant select on sys.sysindexkeys to public; + +reset search_path; diff --git a/contrib/shark/sql/test_sysviews.sql b/contrib/shark/sql/test_sysviews.sql new file mode 100644 index 0000000000..68e7cfb876 --- /dev/null +++ b/contrib/shark/sql/test_sysviews.sql @@ -0,0 +1,145 @@ +create schema sys_view_test; +set search_path to sys_view_test; + +-- show views struct +\d sys.sysobjects +\d sys.syscolumns +\d sys.sysindexes +\d sys.sysindexkeys + +-- test select +select * from sys.sysobjects order by id limit 1; +select * from sys.syscolumns order by id limit 1; +select * from sys.sysindexes order by id, indid limit 1; +select * from sys.sysindexkeys order by id, indid limit 1; +select "OrigFillFactor", "StatVersion", "FirstIAM" from sys.sysindexes order by id, indid limit 1; + +-- prepare data +CREATE TABLE student +( + std_id INT PRIMARY KEY, + std_name VARCHAR(20) NOT NULL, + std_sex VARCHAR(6), + std_birth DATE, + std_in DATE NOT NULL, + std_address VARCHAR(100) +); + +CREATE TABLE teacher +( + tec_id INT PRIMARY KEY, + tec_name VARCHAR(20) NOT NULL, + tec_job VARCHAR(15), + tec_sex VARCHAR(6), + tec_age INT default 20, + tec_in DATE NOT NULL +); + +CREATE TABLE class +( + cla_id INT PRIMARY KEY, + cla_name VARCHAR(20) NOT NULL, + cla_teacher INT NOT NULL +); +ALTER TABLE class ADD CONSTRAINT fk_tec_id FOREIGN KEY (cla_teacher) REFERENCES teacher(tec_id) ON DELETE CASCADE; + +CREATE TABLE school_department +( + depart_id INT PRIMARY KEY, + depart_name VARCHAR(30) NOT NULL, + depart_teacher INT NOT NULL +); +ALTER TABLE school_department ADD CONSTRAINT fk_depart_tec_id FOREIGN KEY (depart_teacher) REFERENCES teacher(tec_id) ON DELETE CASCADE; + +CREATE TABLE course +( + cor_id INT PRIMARY KEY, + cor_name VARCHAR(30) NOT NULL, + cor_type VARCHAR(20), + credit DOUBLE PRECISION +); + +create or replace view teacher_info as +select c.cla_name, t.tec_name, t.tec_job, t.tec_sex, t.tec_age +from teacher t +left join class c on c.cla_teacher = t.tec_id; + +create table t_log (c1 int, c2 varchar(20), c3 timestamp); + +create sequence if not exists t_seq + increment by 1 + nominvalue + nomaxvalue + start with 1 + nocycle; +select t_seq.nextval; + +create or replace function tg_log() returns trigger as +$$ +begin + insert into t_log values (new.std_id, new.std_name, SYSDATE); + return new; +end; +$$ language plpgsql; + +create trigger log_student_after_insert +after insert on student +for each row +execute procedure tg_log(); + +create or replace procedure test_sum(in a int, in b int, out c int) +as +begin + c = a + b; +end; +/ + +create or replace function test_sub(num1 int, num2 int) +returns int as $$ +begin + return num1 - num2; +end; +$$ language plpgsql; + +CREATE OR REPLACE SYNONYM syn_tbl FOR student; +CREATE OR REPLACE SYNONYM syn_tr FOR log_student_after_insert; + +select obj.name, obj.xtype, obj.type from sys.sysobjects obj +left join pg_namespace s on s.oid = obj.uid +where s.nspname = 'sys_view_test' +order by id; + +select col.name, col.length, col.colid, col.status, col.prec, col.scale, col.iscomputed, col.isoutparam, col.isnullable, col.collation +from sys.syscolumns col +left join pg_class c on col.id = c.oid +left join pg_namespace s on s.oid = c.relnamespace +where s.nspname = 'sys_view_test' +order by id, colid; + +select ind.name, ind.keycnt, ind."OrigFillFactor", ind.rows from sys.sysindexes ind +left join pg_class c on c.oid = ind.indid +left join pg_namespace s on c.relnamespace = s.oid +where s.nspname = 'sys_view_test' +order by id, indid; + +select c_tab.relname as tabname, c_ind.relname as indname, ind.colid, ind.keyno from sys.sysindexkeys ind +left join pg_class c_ind on c_ind.oid = ind.indid +left join pg_class c_tab on c_tab.oid = ind.id +left join pg_namespace s on c_ind.relnamespace = s.oid +where s.nspname = 'sys_view_test' +order by id, indid; + +drop synonym syn_tr; +drop synonym syn_tbl; +drop function test_sub; +drop procedure test_sum; +drop table t_log; +drop view teacher_info; +drop table course; +drop table school_department; +drop table class; +drop table teacher; +drop table student; + +reset search_path; +drop schema sys_view_test cascade; diff --git a/contrib/shark/src/pltsql/pl_comp.cpp b/contrib/shark/src/pltsql/pl_comp.cpp index f4f238bb80..d857e305c3 100644 --- a/contrib/shark/src/pltsql/pl_comp.cpp +++ b/contrib/shark/src/pltsql/pl_comp.cpp @@ -632,7 +632,8 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, else func->fn_is_trigger = PLPGSQL_NOT_TRIGGER; - if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE) { + if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE || + proc_struct->pronamespace == get_namespace_oid(SYS_NAMESPACE_NAME, true)) { current_searchpath = fetch_search_path(false); if (current_searchpath == NIL) { ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNDEFINED_SCHEMA), diff --git a/src/common/backend/catalog/namespace.cpp b/src/common/backend/catalog/namespace.cpp index 5607d6debd..6c81107b94 100644 --- a/src/common/backend/catalog/namespace.cpp +++ b/src/common/backend/catalog/namespace.cpp @@ -157,9 +157,6 @@ * Note: all data pointed to by these List variables is in t_thrd.top_mem_cxt. */ -/* Catalog schema that TSQL uses */ -char* SYS_NAMESPACE_NAME = "sys"; - /* Local functions */ static void InitTempTableNamespace(void); static void RemoveTempRelations(Oid tempNamespaceId); diff --git a/src/common/pl/plpgsql/src/pl_comp.cpp b/src/common/pl/plpgsql/src/pl_comp.cpp index 60e78eefb0..4173b97143 100644 --- a/src/common/pl/plpgsql/src/pl_comp.cpp +++ b/src/common/pl/plpgsql/src/pl_comp.cpp @@ -1003,7 +1003,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup, func->fn_is_trigger = PLPGSQL_NOT_TRIGGER; if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE || - proc_struct->pronamespace == get_namespace_oid("sys", true)) { + proc_struct->pronamespace == get_namespace_oid(SYS_NAMESPACE_NAME, true)) { current_searchpath = fetch_search_path(false); if (current_searchpath == NIL) { ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNDEFINED_SCHEMA), diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 13c57f4112..eddd496af5 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -26,6 +26,8 @@ #include "lib/stringinfo.h" static volatile uint32 gt_tempID_seed = 0; +/* Catalog schema that TSQL uses */ +constexpr const char* SYS_NAMESPACE_NAME = "sys"; /* * This structure holds a list of possible functions or operators -- Gitee From 748536a603073cb8ee0a60c1d7540c469327ef36 Mon Sep 17 00:00:00 2001 From: wangfeihuo Date: Fri, 14 Mar 2025 11:48:54 +0800 Subject: [PATCH 03/11] add dbcc function --- contrib/shark/Makefile | 2 +- contrib/shark/dbcc.cpp | 84 ++++ contrib/shark/expected/test_dbcc.out | 411 ++++++++++++++++++ contrib/shark/expected/test_dbcc_case_sen.out | 71 +++ contrib/shark/parallel_schedule | 1 + contrib/shark/shark--1.0.sql | 4 + contrib/shark/sql/test_dbcc.sql | 241 ++++++++++ contrib/shark/sql/test_dbcc_case_sen.sql | 46 ++ .../shark/src/backend_parser/gram-tsql-decl.y | 5 +- .../backend_parser/gram-tsql-epilogue.y.cpp | 48 ++ .../src/backend_parser/gram-tsql-prologue.y.h | 5 +- .../shark/src/backend_parser/gram-tsql-rule.y | 77 +++- contrib/shark/src/backend_parser/kwlist.h | 5 + contrib/shark/src/pltsql/gram.y | 58 +++ .../optimizer/commands/sequence/sequence.cpp | 233 ++++++++++ src/include/commands/sequence.h | 6 + 16 files changed, 1291 insertions(+), 6 deletions(-) create mode 100644 contrib/shark/dbcc.cpp create mode 100644 contrib/shark/expected/test_dbcc.out create mode 100644 contrib/shark/expected/test_dbcc_case_sen.out create mode 100644 contrib/shark/sql/test_dbcc.sql create mode 100644 contrib/shark/sql/test_dbcc_case_sen.sql diff --git a/contrib/shark/Makefile b/contrib/shark/Makefile index 120f922bc4..5851470ee4 100644 --- a/contrib/shark/Makefile +++ b/contrib/shark/Makefile @@ -5,7 +5,7 @@ PLDIR=src/pltsql DATA = shark--1.0.sql REGRESS = dummy -OBJS = shark.o +OBJS = shark.o dbcc.o OBJS += $(BEPARSERDIR)/parser.o OBJS += $(BEPARSERDIR)/gram-backend.o OBJS += $(BEPARSERDIR)/keywords.o diff --git a/contrib/shark/dbcc.cpp b/contrib/shark/dbcc.cpp new file mode 100644 index 0000000000..d4e064b9f0 --- /dev/null +++ b/contrib/shark/dbcc.cpp @@ -0,0 +1,84 @@ +#include "miscadmin.h" +#include "shark.h" +#include "commands/sequence.h" +#include "utils/builtins.h" + +#define DBCC_RESULT_MAX_LENGTH 256 + +extern void get_last_value_and_max_value(text* txt, int64* last_value, int64* current_max_value); +extern int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed); + +extern "C" Datum dbcc_check_ident_no_reseed(PG_FUNCTION_ARGS); +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); + +Datum dbcc_check_ident_no_reseed(PG_FUNCTION_ARGS) +{ + int64 last_value = 0; + int64 current_max_value = 0; + text* txt = PG_GETARG_TEXT_P(0); + char result[DBCC_RESULT_MAX_LENGTH] = {0}; + errno_t rc = EOK; + bool withmsg = true; + + if (!fcinfo->argnull[1]) { + withmsg = !PG_GETARG_BOOL(1); + } + + get_last_value_and_max_value(txt, &last_value, ¤t_max_value); + + 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); + securec_check_ss(rc, "\0", "\0"); + + ereport(NOTICE, (errmsg("\"%s\"", result))); + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + + + +Datum dbcc_check_ident_reseed(PG_FUNCTION_ARGS) +{ + int64 last_value = 0; + int64 new_seed = 0; + errno_t rc = EOK; + char result[DBCC_RESULT_MAX_LENGTH]; + bool withmsg = true; + + if (fcinfo->argnull[0]) { + ereport(ERROR, (errmsg("table name cannot be null."))); + } + + text* txt = PG_GETARG_TEXT_P(0); + bool need_reseed = !fcinfo->argnull[1]; + if (need_reseed) { + new_seed = PG_GETARG_INT64(1); + } + + if(!fcinfo->argnull[2]) { + withmsg = !PG_GETARG_BOOL(2); + } + + 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); + securec_check_ss(rc, "\0", "\0"); + + ereport(NOTICE, (errmsg("\"%s\"", result))); + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + diff --git a/contrib/shark/expected/test_dbcc.out b/contrib/shark/expected/test_dbcc.out new file mode 100644 index 0000000000..f059f1940c --- /dev/null +++ b/contrib/shark/expected/test_dbcc.out @@ -0,0 +1,411 @@ +create schema shark_test_dbcc; +set search_path = 'shark_test_dbcc'; +set d_format_behavior_compat_options = 'enable_sbr_identifier'; +-- part1: dbcc check NORESEED + CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_employeeid_seq" for serial column "employees.employeeid" +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees'); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees', NORESEED) WITH NO_INFOMSGS; + dbcc_check_ident_no_reseed +---------------------------- + +(1 row) + +insert into Employees(Name) values ('heqi'); +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '5', current column value '5'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '5', current column value '5'. +(1 row) + +DBCC CHECKIDENT ('Employees'); +NOTICE: "Checking identity information: current identity value '5', current column value '5'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '5', current column value '5'. +(1 row) + +DBCC CHECKIDENT ('Employees', NORESEED) WITH NO_INFOMSGS; + dbcc_check_ident_no_reseed +---------------------------- + +(1 row) + +delete from Employees where EmployeeID > 2; +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '5', current column value '2'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '5', current column value '2'. +(1 row) + +update Employees set employeeid = 100 where employeeid = 1; +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '5', current column value '100'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +---------------------------------------------------------------------------------------- + Checking identity information: current identity value '5', current column value '100'. +(1 row) + + +-- increment by is negative + CREATE TABLE Employees_ne ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_ne_employeeid_seq" for serial column "employees_ne.employeeid" +ALTER SEQUENCE employees_ne_employeeid_seq MINVALUE -1000; +ALTER SEQUENCE employees_ne_employeeid_seq INCREMENT BY -2; +insert into Employees_ne(Name) values ('zhangsan'); +insert into Employees_ne(Name) values ('lisi'); +insert into Employees_ne(Name) values ('wangwu'); +insert into Employees_ne(Name) values ('heliu'); +DBCC CHECKIDENT ('Employees_ne', NORESEED); +NOTICE: "Checking identity information: current identity value '-5', current column value '-5'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +---------------------------------------------------------------------------------------- + Checking identity information: current identity value '-5', current column value '-5'. +(1 row) + +delete from Employees where EmployeeID < -4; +DBCC CHECKIDENT ('Employees_ne', NORESEED); +NOTICE: "Checking identity information: current identity value '-5', current column value '-5'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +---------------------------------------------------------------------------------------- + Checking identity information: current identity value '-5', current column value '-5'. +(1 row) + +-- error case expect +DBCC CHECKIDENT ('Employees1', NORESEED); +ERROR: relation "employees1" does not exist +CONTEXT: referenced column: dbcc_check_ident_no_reseed +DBCC CHECKIDENT ('employees_employeeid_seq', NORESEED); +ERROR: relation "employees_employeeid_seq" does not exist +CONTEXT: referenced column: dbcc_check_ident_no_reseed +-- plsql +create or replace procedure test_procedure_test1(int) +as +begin + DBCC CHECKIDENT ('Employees', NORESEED); +end; +/ +call test_procedure_test1(1); +NOTICE: "Checking identity information: current identity value '5', current column value '100'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed +SQL statement "DBCC CHECKIDENT ('Employees', NORESEED)" +PL/pgSQL function test_procedure_test1(integer) line 2 at PERFORM + test_procedure_test1 +---------------------- + +(1 row) + +drop table Employees; +drop table Employees_ne; +drop procedure test_procedure_test1(int); +-- part1: dbcc check RESEED +CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_employeeid_seq" for serial column "employees.employeeid" +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees', RESEED, 20); +NOTICE: "Checking identity information: current identity value '4'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '4'. +(1 row) + +insert into Employees(Name) values ('heqi'); +insert into Employees(Name) values ('heba'); +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '22', current column value '22'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +---------------------------------------------------------------------------------------- + Checking identity information: current identity value '22', current column value '22'. +(1 row) + +select * from Employees order by 1, 2; + employeeid | name +------------+---------- + 1 | zhangsan + 2 | lisi + 3 | wangwu + 4 | heliu + 21 | heqi + 22 | heba +(6 rows) + +DBCC CHECKIDENT ('Employees', RESEED, 30) WITH NO_INFOMSGS; + dbcc_check_ident_reseed +------------------------- + +(1 row) + +insert into Employees(Name) values ('zhangqi'); +insert into Employees(Name) values ('zhangba'); +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '32', current column value '32'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +---------------------------------------------------------------------------------------- + Checking identity information: current identity value '32', current column value '32'. +(1 row) + +select * from Employees order by 1, 2; + employeeid | name +------------+---------- + 1 | zhangsan + 2 | lisi + 3 | wangwu + 4 | heliu + 21 | heqi + 22 | heba + 31 | zhangqi + 32 | zhangba +(8 rows) + +delete from Employees where EmployeeID > 2; +DBCC CHECKIDENT ('Employees', RESEED, 1); +NOTICE: "Checking identity information: current identity value '32'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------- + Checking identity information: current identity value '32'. +(1 row) + +insert into Employees(Name) values ('heqi'); +insert into Employees(Name) values ('heba'); +select * from Employees order by 1, 2; + employeeid | name +------------+---------- + 1 | zhangsan + 2 | heqi + 2 | lisi + 3 | heba +(4 rows) + +ALTER SEQUENCE employees_employeeid_seq MINVALUE -100; +DBCC CHECKIDENT ('Employees', RESEED); +NOTICE: "Checking identity information: current identity value '3'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '3'. +(1 row) + +DBCC CHECKIDENT ('Employees', RESEED, -2); +NOTICE: "Checking identity information: current identity value '3'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '3'. +(1 row) + +insert into Employees(Name) values ('liqi'); +insert into Employees(Name) values ('liba'); +select * from Employees order by 1, 2; + employeeid | name +------------+---------- + -1 | liqi + 0 | liba + 1 | zhangsan + 2 | heqi + 2 | lisi + 3 | heba +(6 rows) + +-- plsql +create or replace procedure test_procedure_test(int) +as +begin + DBCC CHECKIDENT ('Employees', RESEED, 1); +end; +/ +call test_procedure_test(1); +NOTICE: "Checking identity information: current identity value '0'." +CONTEXT: referenced column: dbcc_check_ident_reseed +SQL statement "DBCC CHECKIDENT ('Employees', RESEED, 1)" +PL/pgSQL function test_procedure_test(integer) line 2 at PERFORM + test_procedure_test +--------------------- + +(1 row) + +drop table Employees; +drop procedure test_procedure_test(int); +-- some error case +-- no serial col +CREATE TABLE Employees_no ( + EmployeeID int , + Name VARCHAR(100) NOT NULL + ); +insert into Employees_no(EmployeeID, Name) values (1, 'zhangsan'); +insert into Employees_no(EmployeeID, Name) values (2, 'lisi'); +insert into Employees_no(EmployeeID, Name) values (3, 'wangwu'); +insert into Employees_no(EmployeeID, Name) values (4, 'heliu'); +DBCC CHECKIDENT ('Employees_no', NORESEED); +ERROR: cannot not found the serial column for relation "Employees_no" +CONTEXT: referenced column: dbcc_check_ident_no_reseed +DBCC CHECKIDENT ('Employees_no', RESEED, 20); +ERROR: cannot not found the serial column for relation "Employees_no" +CONTEXT: referenced column: dbcc_check_ident_reseed +-- mul serial col +CREATE TABLE Employees_mu ( + EmployeeID serial , + EmployeeID1 serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_mu_employeeid_seq" for serial column "employees_mu.employeeid" +NOTICE: CREATE TABLE will create implicit sequence "employees_mu_employeeid1_seq" for serial column "employees_mu.employeeid1" +insert into Employees_mu(Name) values ('zhangsan'); +insert into Employees_mu(Name) values ('lisi'); +insert into Employees_mu(Name) values ('wangwu'); +insert into Employees_mu(Name) values ('heliu'); +DBCC CHECKIDENT ('Employees_mu', NORESEED); +ERROR: more than one serial in relation "Employees_mu" +CONTEXT: referenced column: dbcc_check_ident_no_reseed +DBCC CHECKIDENT ('Employees_mu', RESEED, 20); +ERROR: more than one serial in relation "Employees_mu" +CONTEXT: referenced column: dbcc_check_ident_reseed +-- serial at middle +CREATE TABLE Employees_mi ( + EmployeeID int , + EmployeeID1 serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_mi_employeeid1_seq" for serial column "employees_mi.employeeid1" +insert into Employees_mi(EmployeeID, Name) values (1, 'zhangsan'); +insert into Employees_mi(EmployeeID, Name) values (2, 'lisi'); +insert into Employees_mi(EmployeeID, Name) values (3, 'wangwu'); +insert into Employees_mi(EmployeeID, Name) values (4, 'heliu'); +DBCC CHECKIDENT ('Employees_mi', NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees_mi', RESEED, 20); +NOTICE: "Checking identity information: current identity value '4'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '4'. +(1 row) + +drop table Employees_no; +drop table Employees_mu; +drop table Employees_mi; +-- create table as +create table t2(id int, name int); +insert into t2 values (1, 1); +insert into t2 values (2, 2); +insert into t2 values (3, 3); +CREATE or replace PROCEDURE InsertIntoTempTable +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT * INTO new_table from dd; +END; +/ +call InsertIntoTempTable(); + insertintotemptable +--------------------- + +(1 row) + +select * from new_table; + id | name +----+------ + 1 | 1 + 2 | 2 + 3 | 3 +(3 rows) + +CREATE or replace PROCEDURE InsertIntoTempTable2 +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT 1 INTO new_table2; +END; +/ +call InsertIntoTempTable2(); + insertintotemptable2 +---------------------- + +(1 row) + +-- expect error +CREATE or replace PROCEDURE InsertIntoTempTable3 +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT * INTO new_table; +END; +/ +call InsertIntoTempTable3(); +ERROR: SELECT * with no tables specified is not valid +LINE 4: SELECT * INTO new_table + ^ +QUERY: WITH dd AS ( + SELECT * FROM t2 + ) + SELECT * INTO new_table +CONTEXT: PL/pgSQL function insertintotemptable3() line 2 at SQL statement +drop PROCEDURE insertintotemptable; +drop PROCEDURE InsertIntoTempTable2; +drop PROCEDURE InsertIntoTempTable3; +drop table new_table; +drop table new_table2; +drop table t2; +drop schema shark_test_dbcc cascade; diff --git a/contrib/shark/expected/test_dbcc_case_sen.out b/contrib/shark/expected/test_dbcc_case_sen.out new file mode 100644 index 0000000000..c5c6816545 --- /dev/null +++ b/contrib/shark/expected/test_dbcc_case_sen.out @@ -0,0 +1,71 @@ +create database "DbcC_test_Case_sen" with dbcompatibility 'D'; +\c "DbcC_test_Case_sen"; +create extension shark; +create schema "DbcC_test_Case_sen_S"; +set search_path = "DbcC_test_Case_sen_S"; +set d_format_behavior_compat_options = 'enable_sbr_identifier'; +-- part1: dbcc check NORESEED + CREATE TABLE "Employees" ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "Employees_employeeid_seq" for serial column "Employees.employeeid" +insert into "Employees"(Name) values ('zhangsan'); +insert into "Employees"(Name) values ('lisi'); +insert into "Employees"(Name) values ('wangwu'); +insert into "Employees"(Name) values ('heliu'); + CREATE TABLE "employees" ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_employeeid_seq" for serial column "employees.employeeid" +insert into "employees"(Name) values ('zhangsan'); +insert into "employees"(Name) values ('lisi'); +-- Case-insensitive +DBCC CHECKIDENT ('employees', NORESEED); +NOTICE: "Checking identity information: current identity value '2', current column value '2'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '2', current column value '2'. +(1 row) + +DBCC CHECKIDENT ('Employees', RESEED, 1); +NOTICE: "Checking identity information: current identity value '2'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '2'. +(1 row) + +-- Case-sensitive +DBCC CHECKIDENT ("employees", NORESEED); +NOTICE: "Checking identity information: current identity value '1', current column value '2'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '1', current column value '2'. +(1 row) + +DBCC CHECKIDENT ("Employees", NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ("Employees", RESEED, 1); +NOTICE: "Checking identity information: current identity value '4'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '4'. +(1 row) + +drop schema "DbcC_test_Case_sen_S" cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table "Employees" +drop cascades to table employees +\c contrib_regression; +drop database "DbcC_test_Case_sen"; diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index 7744e7221e..cd4d5ff496 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -3,4 +3,5 @@ test: init test: basetest test: clustered_index insert_stmt sbr_test test: functions +test: test_dbcc test_dbcc_case_sen test: test_sysviews diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index 8aa94dea08..f074f9a575 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -16,6 +16,10 @@ create trusted language pltsql inline pltsql_inline_handler validator pltsql_validator; + +CREATE FUNCTION dbcc_check_ident_no_reseed(varchar, boolean) RETURNS varchar as 'MODULE_PATHNAME', 'dbcc_check_ident_no_reseed' LANGUAGE C STRICT STABLE; +CREATE FUNCTION dbcc_check_ident_reseed(varchar, bigint, boolean) RETURNS varchar as 'MODULE_PATHNAME', 'dbcc_check_ident_reseed' LANGUAGE C STABLE; + grant usage on language pltsql to public; create function fetch_status() diff --git a/contrib/shark/sql/test_dbcc.sql b/contrib/shark/sql/test_dbcc.sql new file mode 100644 index 0000000000..7a638a7869 --- /dev/null +++ b/contrib/shark/sql/test_dbcc.sql @@ -0,0 +1,241 @@ +create schema shark_test_dbcc; +set search_path = 'shark_test_dbcc'; + +set d_format_behavior_compat_options = 'enable_sbr_identifier'; + +-- part1: dbcc check NORESEED + CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); + +DBCC CHECKIDENT ('Employees', NORESEED); + +DBCC CHECKIDENT ('Employees'); + +DBCC CHECKIDENT ('Employees', NORESEED) WITH NO_INFOMSGS; + +insert into Employees(Name) values ('heqi'); + +DBCC CHECKIDENT ('Employees', NORESEED); + +DBCC CHECKIDENT ('Employees'); + +DBCC CHECKIDENT ('Employees', NORESEED) WITH NO_INFOMSGS; + + +delete from Employees where EmployeeID > 2; + +DBCC CHECKIDENT ('Employees', NORESEED); + +update Employees set employeeid = 100 where employeeid = 1; + +DBCC CHECKIDENT ('Employees', NORESEED); + + +-- increment by is negative + CREATE TABLE Employees_ne ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +ALTER SEQUENCE employees_ne_employeeid_seq MINVALUE -1000; +ALTER SEQUENCE employees_ne_employeeid_seq INCREMENT BY -2; + +insert into Employees_ne(Name) values ('zhangsan'); +insert into Employees_ne(Name) values ('lisi'); +insert into Employees_ne(Name) values ('wangwu'); +insert into Employees_ne(Name) values ('heliu'); + +DBCC CHECKIDENT ('Employees_ne', NORESEED); + +delete from Employees where EmployeeID < -4; + +DBCC CHECKIDENT ('Employees_ne', NORESEED); + +-- error case expect +DBCC CHECKIDENT ('Employees1', NORESEED); +DBCC CHECKIDENT ('employees_employeeid_seq', NORESEED); + + +-- plsql +create or replace procedure test_procedure_test1(int) +as +begin + DBCC CHECKIDENT ('Employees', NORESEED); +end; +/ + +call test_procedure_test1(1); + +drop table Employees; +drop table Employees_ne; +drop procedure test_procedure_test1(int); + + +-- part1: dbcc check RESEED +CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); + + +DBCC CHECKIDENT ('Employees', NORESEED); +DBCC CHECKIDENT ('Employees', RESEED, 20); +insert into Employees(Name) values ('heqi'); +insert into Employees(Name) values ('heba'); +DBCC CHECKIDENT ('Employees', NORESEED); +select * from Employees order by 1, 2; + +DBCC CHECKIDENT ('Employees', RESEED, 30) WITH NO_INFOMSGS; +insert into Employees(Name) values ('zhangqi'); +insert into Employees(Name) values ('zhangba'); +DBCC CHECKIDENT ('Employees', NORESEED); +select * from Employees order by 1, 2; + +delete from Employees where EmployeeID > 2; +DBCC CHECKIDENT ('Employees', RESEED, 1); +insert into Employees(Name) values ('heqi'); +insert into Employees(Name) values ('heba'); +select * from Employees order by 1, 2; + +ALTER SEQUENCE employees_employeeid_seq MINVALUE -100; + +DBCC CHECKIDENT ('Employees', RESEED); + +DBCC CHECKIDENT ('Employees', RESEED, -2); + +insert into Employees(Name) values ('liqi'); +insert into Employees(Name) values ('liba'); + +select * from Employees order by 1, 2; + +-- plsql +create or replace procedure test_procedure_test(int) +as +begin + DBCC CHECKIDENT ('Employees', RESEED, 1); +end; +/ + +call test_procedure_test(1); + + +drop table Employees; +drop procedure test_procedure_test(int); + +-- some error case +-- no serial col + +CREATE TABLE Employees_no ( + EmployeeID int , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees_no(EmployeeID, Name) values (1, 'zhangsan'); +insert into Employees_no(EmployeeID, Name) values (2, 'lisi'); +insert into Employees_no(EmployeeID, Name) values (3, 'wangwu'); +insert into Employees_no(EmployeeID, Name) values (4, 'heliu'); + +DBCC CHECKIDENT ('Employees_no', NORESEED); +DBCC CHECKIDENT ('Employees_no', RESEED, 20); + +-- mul serial col + +CREATE TABLE Employees_mu ( + EmployeeID serial , + EmployeeID1 serial , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees_mu(Name) values ('zhangsan'); +insert into Employees_mu(Name) values ('lisi'); +insert into Employees_mu(Name) values ('wangwu'); +insert into Employees_mu(Name) values ('heliu'); + +DBCC CHECKIDENT ('Employees_mu', NORESEED); +DBCC CHECKIDENT ('Employees_mu', RESEED, 20); + +-- serial at middle +CREATE TABLE Employees_mi ( + EmployeeID int , + EmployeeID1 serial , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees_mi(EmployeeID, Name) values (1, 'zhangsan'); +insert into Employees_mi(EmployeeID, Name) values (2, 'lisi'); +insert into Employees_mi(EmployeeID, Name) values (3, 'wangwu'); +insert into Employees_mi(EmployeeID, Name) values (4, 'heliu'); + +DBCC CHECKIDENT ('Employees_mi', NORESEED); +DBCC CHECKIDENT ('Employees_mi', RESEED, 20); + + +drop table Employees_no; +drop table Employees_mu; +drop table Employees_mi; + +-- create table as +create table t2(id int, name int); +insert into t2 values (1, 1); +insert into t2 values (2, 2); +insert into t2 values (3, 3); + +CREATE or replace PROCEDURE InsertIntoTempTable +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT * INTO new_table from dd; +END; +/ + +call InsertIntoTempTable(); + +select * from new_table; + +CREATE or replace PROCEDURE InsertIntoTempTable2 +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT 1 INTO new_table2; +END; +/ + +call InsertIntoTempTable2(); + +-- expect error +CREATE or replace PROCEDURE InsertIntoTempTable3 +AS +BEGIN + WITH dd AS ( + SELECT * FROM t2 + ) + SELECT * INTO new_table; +END; +/ + +call InsertIntoTempTable3(); + +drop PROCEDURE insertintotemptable; +drop PROCEDURE InsertIntoTempTable2; +drop PROCEDURE InsertIntoTempTable3; +drop table new_table; +drop table new_table2; +drop table t2; + +drop schema shark_test_dbcc cascade; diff --git a/contrib/shark/sql/test_dbcc_case_sen.sql b/contrib/shark/sql/test_dbcc_case_sen.sql new file mode 100644 index 0000000000..0a134f8eaa --- /dev/null +++ b/contrib/shark/sql/test_dbcc_case_sen.sql @@ -0,0 +1,46 @@ +create database "DbcC_test_Case_sen" with dbcompatibility 'D'; + +\c "DbcC_test_Case_sen"; + +create extension shark; + +create schema "DbcC_test_Case_sen_S"; +set search_path = "DbcC_test_Case_sen_S"; + +set d_format_behavior_compat_options = 'enable_sbr_identifier'; + +-- part1: dbcc check NORESEED + CREATE TABLE "Employees" ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +insert into "Employees"(Name) values ('zhangsan'); +insert into "Employees"(Name) values ('lisi'); +insert into "Employees"(Name) values ('wangwu'); +insert into "Employees"(Name) values ('heliu'); + + + CREATE TABLE "employees" ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +insert into "employees"(Name) values ('zhangsan'); +insert into "employees"(Name) values ('lisi'); + + +-- Case-insensitive +DBCC CHECKIDENT ('employees', NORESEED); +DBCC CHECKIDENT ('Employees', RESEED, 1); + +-- Case-sensitive +DBCC CHECKIDENT ("employees", NORESEED); +DBCC CHECKIDENT ("Employees", NORESEED); +DBCC CHECKIDENT ("Employees", RESEED, 1); + +drop schema "DbcC_test_Case_sen_S" cascade; + +\c contrib_regression; + +drop database "DbcC_test_Case_sen"; diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index f1993459ea..d00edd8857 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -1,6 +1,7 @@ %type tsql_stmtmulti -%type tsql_stmt tsql_CreateProcedureStmt tsql_IndexStmt +%type DBCCCheckIdentStmt DBCCStmt tsql_stmt tsql_CreateProcedureStmt tsql_IndexStmt -%token TSQL_CLUSTERED TSQL_NONCLUSTERED TSQL_COLUMNSTORE +%token CHECKIDENT DBCC NO_INFOMSGS NORESEED RESEED TSQL_CLUSTERED TSQL_NONCLUSTERED TSQL_COLUMNSTORE %type tsql_opt_clustered tsql_opt_columnstore %token TSQL_ATAT_IDENT +%type opt_with_no_infomsgs diff --git a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp index b377406171..bf015b8692 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp +++ b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp @@ -19,5 +19,53 @@ TsqlSystemFuncName2(char *name) return list_make2(makeString("sys"), makeString(name)); } +static List* make_func_call_func(List* funcname, List* args) +{ + FuncCall *func = NULL; + ResTarget *restarget = NULL; + + func = (FuncCall*)makeNode(FuncCall); + func->funcname = funcname; + func->args = args; + func->agg_star = FALSE; + func->agg_distinct = FALSE; + func->location = -1; + func->call_func = false; + + restarget = makeNode(ResTarget); + restarget->name = NULL; + restarget->indirection = NIL; + restarget->val = (Node *)func; + restarget->location = -1; + + return (list_make1(restarget)); +} + +static List* make_no_reseed_func(char* table_name, bool with_no_msgs) +{ + List* funcname = list_make1(makeString("dbcc_check_ident_no_reseed")); + List* args = list_make2(makeStringConst(table_name, -1), makeBoolConst(with_no_msgs, false)); + return make_func_call_func(funcname, args); +} + + +static List* make_reseed_func(char* table_name, Node* new_seed, bool with_no_msgs) +{ + List* funcname = list_make1(makeString("dbcc_check_ident_reseed")); + Node* cast_node = makeTypeCast(new_seed, SystemTypeName("int8"), NULL, NULL, NULL, ((A_Const*)new_seed)->location); + List* args = list_make3(makeStringConst(table_name, -1), cast_node, makeBoolConst(with_no_msgs, false)); + return make_func_call_func(funcname, args); +} + + +static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner) +{ + if ((pg_yyget_extra(yyscanner))->core_yy_extra.ident_quoted) { + return pstrdup(quote_identifier((const char*)ident)); + } else { + return ident; + } +} + #include "scan-backend.inc" #undef SCANINC diff --git a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h index 0a1f2a884a..621c88131e 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h @@ -1,3 +1,6 @@ static void pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg); - List *TsqlSystemFuncName2(char *name); +static List* make_no_reseed_func(char* table_name, bool with_no_msgs); +static List* make_reseed_func(char* table_name, Node* new_seed, bool with_no_msgs); +static List* make_func_call_func(List* funcname, List* args); +static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner); \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index 34764e7ffd..1393e356dd 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -113,6 +113,10 @@ tsql_opt_clustered: | /*EMPTY*/ { $$ == NULL;} ; +opt_with_no_infomsgs: WITH NO_INFOMSGS {$$ = TRUE;} + | /*EMPTY*/ {$$ = FALSE;} + ; + tsql_IndexStmt: CREATE opt_unique tsql_opt_clustered tsql_opt_columnstore INDEX opt_concurrently opt_index_name ON qualified_name access_method_clause '(' index_params ')' @@ -459,9 +463,77 @@ tsql_CreateProcedureStmt: ; unreserved_keyword: - TSQL_CLUSTERED + CHECKIDENT + | DBCC + | NO_INFOMSGS + | NORESEED + | RESEED + | TSQL_CLUSTERED | TSQL_NONCLUSTERED ; + +DBCCCheckIdentStmt: + DBCC CHECKIDENT '(' ColId_or_Sconst ',' NORESEED ')' opt_with_no_infomsgs + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = NIL; + n->targetList = make_no_reseed_func(quote_identifier_wrapper($4, yyscanner), $8); + n->intoClause = NULL; + n->fromClause = NIL; + n->whereClause = NULL; + n->groupClause = NIL; + n->havingClause = NULL; + n->windowClause = NIL; + $$ = (Node*)n; + } + | DBCC CHECKIDENT '(' ColId_or_Sconst ')' opt_with_no_infomsgs + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = NIL; + n->targetList = make_no_reseed_func(quote_identifier_wrapper($4, yyscanner), $6); + n->intoClause = NULL; + n->fromClause = NIL; + n->whereClause = NULL; + n->groupClause = NIL; + n->havingClause = NULL; + n->windowClause = NIL; + $$ = (Node*)n; + } + | DBCC CHECKIDENT '(' ColId_or_Sconst ',' RESEED ',' SignedIconst ')' opt_with_no_infomsgs + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = NIL; + n->targetList = make_reseed_func(quote_identifier_wrapper($4, yyscanner), (Node*)makeIntConst($8, @8), $10); + n->intoClause = NULL; + n->fromClause = NIL; + n->whereClause = NULL; + n->groupClause = NIL; + n->havingClause = NULL; + n->windowClause = NIL; + $$ = (Node*)n; + } + | DBCC CHECKIDENT '(' ColId_or_Sconst ',' RESEED ')' opt_with_no_infomsgs + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = NIL; + n->targetList = make_reseed_func(quote_identifier_wrapper($4, yyscanner), makeNullAConst(@6), $8); + n->intoClause = NULL; + n->fromClause = NIL; + n->whereClause = NULL; + n->groupClause = NIL; + n->havingClause = NULL; + n->windowClause = NIL; + $$ = (Node*)n; + } + ; + +DBCCStmt: DBCCCheckIdentStmt + { + $$ = $1; + } + ; + + tsql_stmt : AlterAppWorkloadGroupMappingStmt | AlterCoordinatorStmt @@ -661,7 +733,8 @@ tsql_stmt : | ShrinkStmt | /*EMPTY*/ { $$ = NULL; } - | DelimiterStmt + | DelimiterStmt + | DBCCStmt ; func_expr_common_subexpr: TSQL_ATAT_IDENT diff --git a/contrib/shark/src/backend_parser/kwlist.h b/contrib/shark/src/backend_parser/kwlist.h index fbf6b3a6f1..63edcf0447 100644 --- a/contrib/shark/src/backend_parser/kwlist.h +++ b/contrib/shark/src/backend_parser/kwlist.h @@ -110,6 +110,7 @@ PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD) PG_KEYWORD("characterset", CHARACTERSET, UNRESERVED_KEYWORD) PG_KEYWORD("charset", CHARSET, UNRESERVED_KEYWORD) PG_KEYWORD("check", CHECK, RESERVED_KEYWORD) +PG_KEYWORD("checkident", CHECKIDENT, UNRESERVED_KEYWORD) PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD) PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD) PG_KEYWORD("class_origin", CLASS_ORIGIN, UNRESERVED_KEYWORD) @@ -192,6 +193,7 @@ PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD) PG_KEYWORD("day_hour", DAY_HOUR_P, UNRESERVED_KEYWORD) PG_KEYWORD("day_minute", DAY_MINUTE_P, UNRESERVED_KEYWORD) PG_KEYWORD("day_second", DAY_SECOND_P, UNRESERVED_KEYWORD) +PG_KEYWORD("dbcc", DBCC, UNRESERVED_KEYWORD) PG_KEYWORD("dbcompatibility", DBCOMPATIBILITY_P, UNRESERVED_KEYWORD) PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD) PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD) @@ -430,6 +432,7 @@ PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD) PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD) PG_KEYWORD("no", NO, UNRESERVED_KEYWORD) +PG_KEYWORD("no_infomsgs", NO_INFOMSGS, UNRESERVED_KEYWORD) PG_KEYWORD("nocompress", NOCOMPRESS, UNRESERVED_KEYWORD) PG_KEYWORD("nocycle", NOCYCLE, RESERVED_KEYWORD) #ifdef PGXC @@ -440,6 +443,7 @@ PG_KEYWORD("nomaxvalue", NOMAXVALUE, UNRESERVED_KEYWORD) PG_KEYWORD("nominvalue", NOMINVALUE, UNRESERVED_KEYWORD) PG_KEYWORD("nonclustered", TSQL_NONCLUSTERED, UNRESERVED_KEYWORD) PG_KEYWORD("none", NONE, COL_NAME_KEYWORD) +PG_KEYWORD("noreseed", NORESEED, UNRESERVED_KEYWORD) PG_KEYWORD("not", NOT, RESERVED_KEYWORD) PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD) PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD) @@ -552,6 +556,7 @@ PG_KEYWORD("repeat", REPEAT, UNRESERVED_KEYWORD) PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD) PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD) PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD) +PG_KEYWORD("reseed", RESEED, UNRESERVED_KEYWORD) PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD) PG_KEYWORD("resize", RESIZE, UNRESERVED_KEYWORD) PG_KEYWORD("resource", RESOURCE, UNRESERVED_KEYWORD) diff --git a/contrib/shark/src/pltsql/gram.y b/contrib/shark/src/pltsql/gram.y index 1442fada93..588d4da789 100644 --- a/contrib/shark/src/pltsql/gram.y +++ b/contrib/shark/src/pltsql/gram.y @@ -176,6 +176,7 @@ static PLpgSQL_expr *read_sql_expression2(int until, int until2, static PLpgSQL_expr *read_sql_stmt(const char *sqlstart); static PLpgSQL_type *read_datatype(int tok); static PLpgSQL_stmt *parse_lob_open_close(int location); +static PLpgSQL_stmt *transfrom_dbcc_into_perform_mode(int location); static PLpgSQL_stmt *make_execsql_stmt(int firsttoken, int location); static PLpgSQL_stmt_fetch *read_fetch_direction(void); static void complete_direction(PLpgSQL_stmt_fetch *fetch, @@ -5462,6 +5463,8 @@ stmt_execsql : K_ALTER && (pltsql_is_token_match2('.', K_OPEN) || pltsql_is_token_match2('.', K_CLOSE))) $$ = parse_lob_open_close(@1); + else if (0 == strcasecmp($1.ident, "DBCC")) + $$ = transfrom_dbcc_into_perform_mode(@1); else { tok = yylex(); @@ -12413,6 +12416,9 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict, int firstto *strict = true; #endif tok = yylex(); + if (tok == T_WORD) { + return true; + } if (tok == '@' || tok == SET_USER_IDENT) { return true; } @@ -15174,6 +15180,58 @@ parse_lob_open_close(int location) return NULL; } +/* + * Brief : transform dbcc into perfrom mode exec to void query has no destination for result data + * Description : dbcc is a select sql, if not transform into perform mode, will meet error is plpgsql + * Notes : + */ +static PLpgSQL_stmt * transfrom_dbcc_into_perform_mode(int location) +{ + StringInfoData func; + int tok = yylex(); + char *mode = NULL; + bool is_open = false; + PLpgSQL_expr *expr = NULL; + PLpgSQL_stmt_perform *perform = NULL; + int dbcc_sql_start_loc = location; + int dbcc_sql_end_loc = -1; + initStringInfo(&func); + + for (;;) { + tok = yylex(); + + if (tok == 0) + yyerror("unexpected end of function definition"); + + if (tok == ';') { + dbcc_sql_end_loc = yylloc; + break; + } + } + + plpgsql_append_source_text(&func, dbcc_sql_start_loc, dbcc_sql_end_loc); + + expr = (PLpgSQL_expr *)palloc0(sizeof(PLpgSQL_expr)); + expr->dtype = PLPGSQL_DTYPE_EXPR; + expr->query = pstrdup(func.data); + expr->plan = NULL; + expr->paramnos = NULL; + expr->ns = plpgsql_ns_top(); + expr->idx = (uint32)-1; + expr->out_param_dno = -1; + + perform = (PLpgSQL_stmt_perform*)palloc0(sizeof(PLpgSQL_stmt_perform)); + perform->cmd_type = PLPGSQL_STMT_PERFORM; + perform->lineno = plpgsql_location_to_lineno(location); + perform->expr = expr; + perform->sqlString = plpgsql_get_curline_query(); + + pfree_ext(func.data); + + return (PLpgSQL_stmt *)perform; +} + + static void raw_parse_package_function_callback(void *arg) { sql_error_callback_arg *cbarg = (sql_error_callback_arg*)arg; diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 6e72bdfa88..7edd6a9de1 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -31,6 +31,7 @@ #include "catalog/namespace.h" #include "catalog/pg_object.h" #include "catalog/pg_type.h" +#include "catalog/pg_attrdef.h" #include "commands/defrem.h" #include "commands/sequence.h" #include "commands/tablecmds.h" @@ -668,6 +669,30 @@ static int128 GetNextvalLocal(SeqTable elm, Relation seqrel) return result; } + +template +static T_Int GetLastAndIncrementValue(SeqTable elm, Relation seqrel, T_Int* increment_by) +{ + Buffer buf; + Page page; + HeapTupleData seqtuple; + T_Form seq; + GTM_UUID uuid; + T_Int last_value; + + /* lock page' buffer and read tuple */ + seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple, &uuid); + page = BufferGetPage(buf); + + AssignInt(&last_value, (int128)seq->last_value); + AssignInt(increment_by, (int128)seq->increment_by); + + UnlockReleaseBuffer(buf); + + return last_value; +} + + template static bool FetchNOverMaxBound(T_Int maxv, T_Int next, T_Int incby) { @@ -3087,3 +3112,211 @@ static char* Int8or16Out(T_Int num) } return ret; } + + +template +T_Int GetColumnMaxOrMinValue(char* column_name, char* full_table_name, bool is_min) +{ + T_Int current_max_value = 0; + char max_value_sql[FULL_TABLE_NAME_MAX_LENGTH] = {0}; + errno_t rc = EOK; + const char* target_type = large ? "int16" : "int8"; + const char* agg_func_name = is_min ? "min" : "max"; + int ret = 0; + bool isnull = false; + + rc = snprintf_s(max_value_sql, FULL_TABLE_NAME_MAX_LENGTH, FULL_TABLE_NAME_MAX_LENGTH - 1, + "select %s(%s)::%s from %s;", agg_func_name, column_name, target_type, full_table_name); + securec_check_ss(rc, "", ""); + + ereport(DEBUG5, (errcode(MOD_SEQ), errmsg("get current max value sql is \"%s\"", max_value_sql))); + if (SPI_OK_CONNECT != SPI_connect()) { + ereport(ERROR, + (errcode(ERRCODE_SPI_CONNECTION_FAILURE), + errmsg("Unable to connect to execute internal select max value."))); + } + ret = SPI_execute(max_value_sql, true, 1); + if (ret < 0) { + ereport(ERROR, + (errcode(ERRCODE_SPI_EXECUTE_FAILURE), + errmsg("Call SPI_execute execute interval select max value failed."))); + } + + if (SPI_processed != 1) { + ereport(ERROR, + (errcode(ERRCODE_SPI_EXECUTE_FAILURE), + errmsg("execute select max value but result is invalid."))); + } + + Datum res = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull); + if (isnull) { + ereport(ERROR, + (errcode(ERRCODE_SPI_EXECUTE_FAILURE), + errmsg("execute select max value but result is null."))); + } else { + if (large) { + current_max_value = DatumGetInt128(res); + } else { + current_max_value = DatumGetInt64(res); + } + } + SPI_finish(); + return current_max_value; +} + + +static inline void free_relation_resource(SysScanDesc adscan, Relation adrel, Relation rel) +{ + systable_endscan(adscan); + heap_close(adrel, AccessShareLock); + relation_close(rel, AccessShareLock); +} + + +static inline void check_relation_valid(Relation rel, char* table_name) +{ + if (rel->rd_rel->relkind != RELKIND_RELATION) { + relation_close(rel, AccessShareLock); + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", table_name))); + } + + if (rel->rd_att->constr->num_defval < 1) { + relation_close(rel, AccessShareLock); + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot not found the serial column for relation \"%s\"", table_name))); + } +} + +static Oid adbin_to_relid(char* adbin) +{ + Oid seqoid = InvalidOid; + if (adbin == NULL || adbin[0] == '\0') { + return InvalidOid; + } + Node* expr = (Node*)stringToNode(adbin); + if (!IsA(expr, FuncExpr)) { + return InvalidOid ; + } + find_nextval_seqoid_walker(expr, &seqoid); + + return seqoid; +} + +char* get_serial_column_and_seq_table(List* range_var, char* table_name, Oid* seq_table_oid) +{ + Relation rel = NULL; + ScanKeyData skey; + HeapTuple htup; + char* serial_column_name = NULL; + Oid seqoid = InvalidOid; + + rel = HeapOpenrvExtended(makeRangeVarFromNameList(range_var), AccessShareLock, false, true); + check_relation_valid(rel, table_name); + + ScanKeyInit(&skey, Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(rel))); + Relation adrel = heap_open(AttrDefaultRelationId, AccessShareLock); + SysScanDesc adscan = systable_beginscan(adrel, AttrDefaultIndexId, true, NULL, 1, &skey); + + while (HeapTupleIsValid(htup = systable_getnext(adscan))) { + Datum val; + bool isnull = false; + Datum adnum; + + val = fastgetattr(htup, Anum_pg_attrdef_adbin, adrel->rd_att, &isnull); + if (isnull) { + continue; + } + + char* adbin_str = TextDatumGetCString(val); + Oid seqoid_temp = adbin_to_relid(adbin_str); + if (OidIsValid(seqoid_temp) && OidIsValid(seqoid)) { + free_relation_resource(adscan, adrel, rel); + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("more than one serial in relation \"%s\"", table_name))); + } + if (!OidIsValid(seqoid_temp) && !OidIsValid(seqoid)) { + continue; + } + if (OidIsValid(seqoid_temp) && !OidIsValid(seqoid)) { + seqoid = seqoid_temp; + adnum = fastgetattr(htup, Anum_pg_attrdef_adnum, adrel->rd_att, &isnull); + int16 adnum_int16 = DatumGetInt16(adnum) - 1; + if (adnum_int16 < 0) { + free_relation_resource(adscan, adrel, rel); + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("adnum is not defined in pg_attrdef"))); + } + serial_column_name = pstrdup(NameStr(rel->rd_att->attrs[adnum_int16].attname)); + } + } + + if (!OidIsValid(seqoid) || serial_column_name == NULL) { + free_relation_resource(adscan, adrel, rel); + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("cannot not found the serial table for relation \"%s\"", table_name))); + } + + free_relation_resource(adscan, adrel, rel); + *seq_table_oid = seqoid; + return serial_column_name; +} + + +void get_last_value_and_max_value(text* txt, int64* last_value, int64* current_max_value) +{ + int64 increasement_by = 0; + Oid relid = 0; + SeqTable elm = NULL; + Relation seqrel; + char* serial_column_name = NULL; + char* table_name = TextDatumGetCString(txt); + List* range_var = textToQualifiedNameList(txt); + + serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid); + + /* open and lock sequence */ + init_sequence(relid, &elm, &seqrel); + *last_value = GetLastAndIncrementValue(elm, seqrel, &increasement_by); + relation_close(seqrel, NoLock); + + /* get current max value by execute select max (xx) from xxx */ + bool is_min = increasement_by < 0 ? true : false; + *current_max_value = GetColumnMaxOrMinValue(serial_column_name, table_name, is_min); + + pfree(serial_column_name); + pfree(table_name); + list_free(range_var); +} + + +int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed) +{ + int64 last_value = 0; + Oid relid = 0; + int64 increasement_by = 0; + SeqTable elm = NULL; + Relation seqrel; + char* serial_column_name = NULL; + + List* range_var = textToQualifiedNameList(txt); + char* table_name = TextDatumGetCString(txt); + + serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid); + + /* open and lock sequence */ + init_sequence(relid, &elm, &seqrel); + last_value = GetLastAndIncrementValue(elm, seqrel, &increasement_by); + relation_close(seqrel, NoLock); + + // set new reseed + if (need_reseed) { + do_setval(relid, new_value, true); + } + + pfree(serial_column_name); + pfree(table_name); + list_free(range_var); + + return last_value; +} diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 9fbf008523..66d8655f76 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -228,6 +228,12 @@ typedef enum { NDE_BIGINT /* expected bigint nextval */ } nextval_default_expr_type_enum; + +#define FULL_TABLE_NAME_MAX_LENGTH 256 +extern void get_last_value_and_max_value(text* txt, int64* last_value, int64* current_max_value); +extern int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed); + + extern void delete_global_seq(Oid relid, Relation seqrel); /* Sequence callbacks on GTM */ extern void register_sequence_rename_cb(const char* oldseqname, const char* newseqname); -- Gitee From 07d5e65834fcb5bdac128c6c4cbde28d1bec9551 Mon Sep 17 00:00:00 2001 From: wangfeihuo Date: Fri, 14 Mar 2025 16:08:54 +0800 Subject: [PATCH 04/11] support rotate and not rotate function --- contrib/shark/Makefile | 7 +- contrib/shark/expected/rotate-test-part2.out | 857 ++++++++++++++++++ .../shark/expected/rotate-test-part2_ci.out | 798 ++++++++++++++++ contrib/shark/input/rotate_part2_dump.source | 60 ++ contrib/shark/output/rotate_part2_dump.source | 116 +++ contrib/shark/parallel_schedule | 1 + contrib/shark/smartmatch.pl | 583 ++++++++++++ contrib/shark/sql/rotate-test-part2.sql | 327 +++++++ contrib/shark/sql/rotate-test-part2_ci.sql | 304 +++++++ .../shark/src/backend_parser/gram-tsql-rule.y | 39 + contrib/shark/src/backend_parser/kwlist.h | 3 - src/bin/gs_guc/cluster_guc.conf | 1 + src/common/backend/parser/gram.y | 81 +- src/common/backend/parser/parse_clause.cpp | 7 +- src/common/backend/parser/parse_expr.cpp | 20 + src/common/backend/utils/misc/guc.cpp | 1 + src/common/backend/utils/misc/guc/guc_sql.cpp | 55 +- .../knl/knl_guc/knl_session_attr_sql.h | 1 + src/include/nodes/parsenodes_common.h | 2 + src/include/postgres.h | 2 + 20 files changed, 3243 insertions(+), 22 deletions(-) create mode 100644 contrib/shark/expected/rotate-test-part2.out create mode 100644 contrib/shark/expected/rotate-test-part2_ci.out create mode 100644 contrib/shark/input/rotate_part2_dump.source create mode 100644 contrib/shark/output/rotate_part2_dump.source create mode 100644 contrib/shark/smartmatch.pl create mode 100644 contrib/shark/sql/rotate-test-part2.sql create mode 100644 contrib/shark/sql/rotate-test-part2_ci.sql diff --git a/contrib/shark/Makefile b/contrib/shark/Makefile index 5851470ee4..c6e9201328 100644 --- a/contrib/shark/Makefile +++ b/contrib/shark/Makefile @@ -102,4 +102,9 @@ $(PLDIR)/pl_reserved_kwlist_d.h: $(PLDIR)/pl_reserved_kwlist.h $(GEN_KEYWORDLIST $(GEN_KEYWORDLIST) --varname ReservedPLKeywords $< $(PLDIR)/pl_unreserved_kwlist_d.h: $(PLDIR)/pl_unreserved_kwlist.h $(GEN_KEYWORDLIST_DEPS) - $(GEN_KEYWORDLIST) --varname UnreservedPLKeywords $< \ No newline at end of file + $(GEN_KEYWORDLIST) --varname UnreservedPLKeywords $< + + + +all: + chmod +x ./smartmatch.pl diff --git a/contrib/shark/expected/rotate-test-part2.out b/contrib/shark/expected/rotate-test-part2.out new file mode 100644 index 0000000000..8cc2fd10cd --- /dev/null +++ b/contrib/shark/expected/rotate-test-part2.out @@ -0,0 +1,857 @@ +create schema shark_rotate_test_part2; +set search_path = 'shark_rotate_test_part2'; +set d_format_behavior_compat_options = 'enable_sbr_identifier'; +-- part1: pivot +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)); +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, a) +) as pivot; + year | A | B | a +------+---+---+--- + 2021 | 1 | 1 | 0 + 2020 | 1 | 1 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN ([A], [B], "A", "B", C) +) as pivot; + year | A | B | A | B | C +------+---+---+---+---+--- + 2021 | 1 | 1 | 1 | 1 | 0 + 2020 | 1 | 1 | 1 | 1 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + year | A | B +------+---+--- + 2021 | 1 | 1 + 2020 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + year | A | B +------+---+--- + 2021 | 1 | 1 + 2020 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + year | A | B | A | SSS | 1 | 2 | 2.3 | 1011 +------+---+---+---+-----+---+---+-----+------ + 2021 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 + 2020 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + year | A | B +------+---+--- + 2020 | 1 | 1 + 2021 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; +ERROR: missing FROM-clause entry for table "source_table" +LINE 4: ) as pivot_table where source_table.year > 1; + ^ +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +CALL proc1(param1:='123'); +NOTICE: (2021,150.00,250.00) +NOTICE: (2020,100.00,200.00) + proc1 +------- + +(1 row) + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + mergedocid | ItemAssetCategory_Code | ItemCostCategory_Code | ItemCreditCategory_Code | ItemMRPCategory_Code | ItemPriceCategory_Code | ItemProductionCategory_Code | ItemPurchaseCategory_Code | ItemSaleCategory_Code | ItemStockCategory_Code | ItemAssetCategory_Name | ItemCostCategory_Name | ItemCreditCategory_Name | ItemMRPCategory_Name | ItemPriceCategory_Name | ItemProductionCategory_Name | ItemPurchaseCategory_Name | ItemSaleCategory_Name | ItemStockCategory_Name +------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------ +(0 rows) + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; +select * from v1; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +-- part2: unpivot +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, [sale3], [sale4]) +) unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +CALL proc2(param1:='123'); +NOTICE: (2020,A,100.00,1,sale1,1) +NOTICE: (2020,B,200.00,2,sale1,2) +NOTICE: (2021,A,150.00,3,sale1,3) +NOTICE: (2021,B,250.00,4,sale1,4) +NOTICE: (2022,C,250.00,5,sale1,5) +NOTICE: (2020,A,100.00,1,sale2,1) +NOTICE: (2020,B,200.00,2,sale2,2) +NOTICE: (2021,A,150.00,3,sale2,3) +NOTICE: (2021,B,250.00,4,sale2,4) +NOTICE: (2022,C,250.00,5,sale2,5) +NOTICE: (2020,A,100.00,1,sale3,1) +NOTICE: (2020,B,200.00,2,sale3,2) +NOTICE: (2021,A,150.00,3,sale3,3) +NOTICE: (2021,B,250.00,4,sale3,4) +NOTICE: (2022,C,250.00,5,sale3,5) +NOTICE: (2020,A,100.00,1,sale4,1) +NOTICE: (2020,B,200.00,2,sale4,2) +NOTICE: (2021,A,150.00,3,sale4,3) +NOTICE: (2021,B,250.00,4,sale4,4) +NOTICE: (2022,C,250.00,5,sale4,5) + proc2 +------- + +(1 row) + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; +select * from v2; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +set enable_ignore_case_in_dquotes on; +WARNING: Please avoid turn on this param when already created +uppercase named objects or using double quotes in PL. +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + year | sale5 | a | b | sale | sale_all +------+-------+--------+--------+-------+---------- + 2020 | 1 | 100.00 | | sale4 | 1 + 2020 | 1 | 100.00 | | sale1 | 1 + 2020 | 1 | 100.00 | | sale2 | 1 + 2020 | 1 | 100.00 | | sale3 | 1 + 2020 | 2 | | 200.00 | sale3 | 2 + 2020 | 2 | | 200.00 | sale4 | 2 + 2020 | 2 | | 200.00 | sale1 | 2 + 2020 | 2 | | 200.00 | sale2 | 2 + 2021 | 3 | 150.00 | | sale1 | 3 + 2021 | 3 | 150.00 | | sale2 | 3 + 2021 | 3 | 150.00 | | sale3 | 3 + 2021 | 3 | 150.00 | | sale4 | 3 + 2021 | 4 | | 250.00 | sale2 | 4 + 2021 | 4 | | 250.00 | sale3 | 4 + 2021 | 4 | | 250.00 | sale4 | 4 + 2021 | 4 | | 250.00 | sale1 | 4 + 2022 | 5 | | | sale3 | 5 + 2022 | 5 | | | sale2 | 5 + 2022 | 5 | | | sale4 | 5 + 2022 | 5 | | | sale1 | 5 +(20 rows) + +set enable_ignore_case_in_dquotes off; +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; + ?column? +---------- + +(1 row) + +select 1 = NULL; + ?column? +---------- + +(1 row) + +select NULL <> NULL; + ?column? +---------- + +(1 row) + +select 1 <> NULL; + ?column? +---------- + +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + +(1 row) + +select NULL != NULL; + ?column? +---------- + +(1 row) + +set ANSI_NULLS off; +select NULL = NULL; + ?column? +---------- + t +(1 row) + +select 1 = NULL; + ?column? +---------- + f +(1 row) + +select NULL <> NULL; + ?column? +---------- + f +(1 row) + +select 1 <> NULL; + ?column? +---------- + t +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + t +(1 row) + +select NULL != NULL; + ?column? +---------- + f +(1 row) + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; + a +--- +(0 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- +(0 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- +(0 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +set d_format_behavior_compat_options 'enable_sbr_identifier'; +set vacuum_cost_page_dirty 20; +set cpu_tuple_cost 0.02; +set effective_cache_size '128MB'; +reset vacuum_cost_page_dirty; +reset cpu_tuple_cost; +reset effective_cache_size; +set ansi_nulls on; +show ansi_nulls; + ansi_nulls +------------ + on +(1 row) + +show transform_null_equals; + transform_null_equals +----------------------- + off +(1 row) + +set transform_null_equals on; +show transform_null_equals; + transform_null_equals +----------------------- + on +(1 row) + +show ansi_nulls; + ansi_nulls +------------ + off +(1 row) + +set ansi_nulls = off; +show ansi_nulls; + ansi_nulls +------------ + off +(1 row) + +show transform_null_equals; + transform_null_equals +----------------------- + on +(1 row) + +set transform_null_equals = off; +show transform_null_equals; + transform_null_equals +----------------------- + off +(1 row) + +show ansi_nulls; + ansi_nulls +------------ + on +(1 row) + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + body +------ + body +(1 row) + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + rownum +-------- + rownum +(1 row) + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + pivot +------- + pivot +(1 row) + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + unpivot +--------- + unpivot +(1 row) + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; +drop schema shark_rotate_test_part2 cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function proc1(character) +drop cascades to function proc2(character) diff --git a/contrib/shark/expected/rotate-test-part2_ci.out b/contrib/shark/expected/rotate-test-part2_ci.out new file mode 100644 index 0000000000..2c764545d3 --- /dev/null +++ b/contrib/shark/expected/rotate-test-part2_ci.out @@ -0,0 +1,798 @@ +create schema shark_rotate_test_part2_ci; +set search_path = 'shark_rotate_test_part2_ci'; +set d_format_behavior_compat_options = 'enable_sbr_identifier'; +-- part1: pivot +set enable_ignore_case_in_dquotes on; +WARNING: Please avoid turn on this param when already created +uppercase named objects or using double quotes in PL. +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)) collate utf8_general_ci; +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, a) +) as pivot; + year | A | B | a +------+---+---+--- + 2021 | 1 | 1 | 1 + 2020 | 1 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN ([A], [B], "A", "B", C) +) as pivot; + year | A | B | A | B | C +------+---+---+---+---+--- + 2021 | 1 | 1 | 1 | 1 | 0 + 2020 | 1 | 1 | 1 | 1 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + year | A | B +------+---+--- + 2021 | 1 | 1 + 2020 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + year | A | B +------+---+--- + 2021 | 1 | 1 + 2020 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + year | A | B | A | SSS | 1 | 2 | 2.3 | 1011 +------+---+---+---+-----+---+---+-----+------ + 2021 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 + 2020 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + year | A | B +------+---+--- + 2020 | 1 | 1 + 2021 | 1 | 1 +(2 rows) + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; +ERROR: missing FROM-clause entry for table "source_table" +LINE 4: ) as pivot_table where source_table.year > 1; + ^ +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +CALL proc1(param1:='123'); +NOTICE: (2021,150.00,250.00) +NOTICE: (2020,100.00,200.00) + proc1 +------- + +(1 row) + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + mergedocid | ItemAssetCategory_Code | ItemCostCategory_Code | ItemCreditCategory_Code | ItemMRPCategory_Code | ItemPriceCategory_Code | ItemProductionCategory_Code | ItemPurchaseCategory_Code | ItemSaleCategory_Code | ItemStockCategory_Code | ItemAssetCategory_Name | ItemCostCategory_Name | ItemCreditCategory_Name | ItemMRPCategory_Name | ItemPriceCategory_Name | ItemProductionCategory_Name | ItemPurchaseCategory_Name | ItemSaleCategory_Name | ItemStockCategory_Name +------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------+------------------------+-----------------------+-------------------------+----------------------+------------------------+-----------------------------+---------------------------+-----------------------+------------------------ +(0 rows) + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; +select * from v1; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +-- part2: unpivot +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +) collate utf8_general_ci; +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, [sale3], [sale4]) +) unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2022 | C | 250.00 | 5 | sale1 | 5 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 +(20 rows) + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ +CALL proc2(param1:='123'); +NOTICE: (2020,A,100.00,1,sale1,1) +NOTICE: (2020,B,200.00,2,sale1,2) +NOTICE: (2021,A,150.00,3,sale1,3) +NOTICE: (2021,B,250.00,4,sale1,4) +NOTICE: (2022,C,250.00,5,sale1,5) +NOTICE: (2020,A,100.00,1,sale2,1) +NOTICE: (2020,B,200.00,2,sale2,2) +NOTICE: (2021,A,150.00,3,sale2,3) +NOTICE: (2021,B,250.00,4,sale2,4) +NOTICE: (2022,C,250.00,5,sale2,5) +NOTICE: (2020,A,100.00,1,sale3,1) +NOTICE: (2020,B,200.00,2,sale3,2) +NOTICE: (2021,A,150.00,3,sale3,3) +NOTICE: (2021,B,250.00,4,sale3,4) +NOTICE: (2022,C,250.00,5,sale3,5) +NOTICE: (2020,A,100.00,1,sale4,1) +NOTICE: (2020,B,200.00,2,sale4,2) +NOTICE: (2021,A,150.00,3,sale4,3) +NOTICE: (2021,B,250.00,4,sale4,4) +NOTICE: (2022,C,250.00,5,sale4,5) + proc2 +------- + +(1 row) + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; +select * from v2; + year | product | amount | sale5 | sale | sale_all +------+---------+--------+-------+-------+---------- + 2020 | A | 100.00 | 1 | sale1 | 1 + 2020 | A | 100.00 | 1 | sale2 | 1 + 2020 | A | 100.00 | 1 | sale3 | 1 + 2020 | A | 100.00 | 1 | sale4 | 1 + 2020 | B | 200.00 | 2 | sale1 | 2 + 2020 | B | 200.00 | 2 | sale4 | 2 + 2020 | B | 200.00 | 2 | sale2 | 2 + 2020 | B | 200.00 | 2 | sale3 | 2 + 2021 | A | 150.00 | 3 | sale4 | 3 + 2021 | A | 150.00 | 3 | sale2 | 3 + 2021 | A | 150.00 | 3 | sale3 | 3 + 2021 | A | 150.00 | 3 | sale1 | 3 + 2021 | B | 250.00 | 4 | sale1 | 4 + 2021 | B | 250.00 | 4 | sale2 | 4 + 2021 | B | 250.00 | 4 | sale4 | 4 + 2021 | B | 250.00 | 4 | sale3 | 4 + 2022 | C | 250.00 | 5 | sale4 | 5 + 2022 | C | 250.00 | 5 | sale3 | 5 + 2022 | C | 250.00 | 5 | sale2 | 5 + 2022 | C | 250.00 | 5 | sale1 | 5 +(20 rows) + +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + year | sale5 | a | b | sale | sale_all +------+-------+--------+--------+-------+---------- + 2020 | 1 | 100.00 | | sale4 | 1 + 2020 | 1 | 100.00 | | sale1 | 1 + 2020 | 1 | 100.00 | | sale2 | 1 + 2020 | 1 | 100.00 | | sale3 | 1 + 2020 | 2 | | 200.00 | sale3 | 2 + 2020 | 2 | | 200.00 | sale4 | 2 + 2020 | 2 | | 200.00 | sale1 | 2 + 2020 | 2 | | 200.00 | sale2 | 2 + 2021 | 3 | 150.00 | | sale1 | 3 + 2021 | 3 | 150.00 | | sale2 | 3 + 2021 | 3 | 150.00 | | sale3 | 3 + 2021 | 3 | 150.00 | | sale4 | 3 + 2021 | 4 | | 250.00 | sale2 | 4 + 2021 | 4 | | 250.00 | sale3 | 4 + 2021 | 4 | | 250.00 | sale4 | 4 + 2021 | 4 | | 250.00 | sale1 | 4 + 2022 | 5 | | | sale3 | 5 + 2022 | 5 | | | sale2 | 5 + 2022 | 5 | | | sale4 | 5 + 2022 | 5 | | | sale1 | 5 +(20 rows) + +set enable_ignore_case_in_dquotes off; +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; + ?column? +---------- + +(1 row) + +select 1 = NULL; + ?column? +---------- + +(1 row) + +select NULL <> NULL; + ?column? +---------- + +(1 row) + +select 1 <> NULL; + ?column? +---------- + +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + +(1 row) + +select NULL != NULL; + ?column? +---------- + +(1 row) + +set ANSI_NULLS off; +select NULL = NULL; + ?column? +---------- + t +(1 row) + +select 1 = NULL; + ?column? +---------- + f +(1 row) + +select NULL <> NULL; + ?column? +---------- + f +(1 row) + +select 1 <> NULL; + ?column? +---------- + t +(1 row) + +select NULL > NULL; + ?column? +---------- + +(1 row) + +select 1 > NULL; + ?column? +---------- + +(1 row) + +select NULL IS NULL; + ?column? +---------- + t +(1 row) + +select 1 IS NULL; + ?column? +---------- + f +(1 row) + +select NULL IS NOT NULL; + ?column? +---------- + f +(1 row) + +select 1 IS NOT NULL; + ?column? +---------- + t +(1 row) + +select 1 != NULL; + ?column? +---------- + t +(1 row) + +select NULL != NULL; + ?column? +---------- + f +(1 row) + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; + a +--- +(0 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- +(0 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- +(0 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 = NULL; + a +--- +(0 rows) + +select * from test1 where NULL <> NULL; + a +--- +(0 rows) + +select * from test1 where 1 <> NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL > NULL; + a +--- +(0 rows) + +select * from test1 where 1 > NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 IS NULL; + a +--- +(0 rows) + +select * from test1 where NULL IS NOT NULL; + a +--- +(0 rows) + +select * from test1 where 1 IS NOT NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where 1 != NULL; + a +--- + + 0 + 1 +(3 rows) + +select * from test1 where NULL != NULL; + a +--- +(0 rows) + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + body +------ + body +(1 row) + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + rownum +-------- + rownum +(1 row) + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + pivot +------- + pivot +(1 row) + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + unpivot +--------- + unpivot +(1 row) + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; +drop schema shark_rotate_test_part2_ci cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function proc1(character) +drop cascades to function proc2(character) diff --git a/contrib/shark/input/rotate_part2_dump.source b/contrib/shark/input/rotate_part2_dump.source new file mode 100644 index 0000000000..9533500068 --- /dev/null +++ b/contrib/shark/input/rotate_part2_dump.source @@ -0,0 +1,60 @@ +create database shark_rotate_part2_dump dbcompatibility 'D';; +\c shark_rotate_part2_dump +create extension shark; +create schema shark_rotate_part2_dump; +set search_path to shark_rotate_part2_dump; + +set enable_ignore_case_in_dquotes on; + +CREATE TABLE sales (year INT, product VARCHAR(50) collate utf8_general_ci, amount DECIMAL(10, 2)); + +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); + + +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50) collate utf8_general_ci, + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); + +-- view +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + + +create view v2 as +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + + +\! @abs_bindir@/gs_dump shark_rotate_part2_dump -p @portstring@ -f @abs_bindir@/shark_rotate_part2_dump.sql -n shark_rotate_part2_dump -w >/dev/null 2>&1; echo $? +drop schema shark_rotate_part2_dump cascade; +\! @abs_bindir@/gsql -dshark_rotate_part2_dump -p @portstring@ -f "@abs_bindir@/shark_rotate_part2_dump.sql"; + +-- rotate check + +select * from v1; +select *from v2; + +drop schema shark_rotate_part2_dump cascade; +\c postgres +drop database shark_rotate_part2_dump; diff --git a/contrib/shark/output/rotate_part2_dump.source b/contrib/shark/output/rotate_part2_dump.source new file mode 100644 index 0000000000..bb40b79d8e --- /dev/null +++ b/contrib/shark/output/rotate_part2_dump.source @@ -0,0 +1,116 @@ +create database shark_rotate_part2_dump dbcompatibility 'D';; +\c shark_rotate_part2_dump +create extension shark; +create schema shark_rotate_part2_dump; +set search_path to shark_rotate_part2_dump; +set enable_ignore_case_in_dquotes on; +WARNING: Please avoid turn on this param when already created +uppercase named objects or using double quotes in PL. +CREATE TABLE sales (year INT, product VARCHAR(50) collate utf8_general_ci, amount DECIMAL(10, 2)); +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50) collate utf8_general_ci, + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); +-- view +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; +create view v2 as +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; +--?.* +0 +drop schema shark_rotate_part2_dump cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table sales +drop cascades to table sales2 +drop cascades to view v1 +drop cascades to view v2 +--?.* +SET +SET +SET +SET +SET +SET +SET +SET +SET +SET +SET +CREATE SCHEMA +ALTER SCHEMA +SET +SET +SET +CREATE TABLE +ALTER TABLE +CREATE TABLE +ALTER TABLE +CREATE VIEW +ALTER VIEW +CREATE VIEW +ALTER VIEW +--?.* +-- rotate check +select * from v1; + year | amount | A | B +------+--------+---+--- + 2021 | 250.00 | 0 | 1 + 2021 | 150.00 | 1 | 0 + 2020 | 200.00 | 0 | 1 + 2020 | 100.00 | 1 | 0 +(4 rows) + +select *from v2; + year | sale5 | a | b | sale | sale_all +------+-------+--------+--------+-------+---------- + 2020 | 1 | 100.00 | | sale4 | 1 + 2020 | 1 | 100.00 | | sale1 | 1 + 2020 | 1 | 100.00 | | sale2 | 1 + 2020 | 1 | 100.00 | | sale3 | 1 + 2020 | 2 | | 200.00 | sale3 | 2 + 2020 | 2 | | 200.00 | sale4 | 2 + 2020 | 2 | | 200.00 | sale1 | 2 + 2020 | 2 | | 200.00 | sale2 | 2 + 2021 | 3 | 150.00 | | sale1 | 3 + 2021 | 3 | 150.00 | | sale2 | 3 + 2021 | 3 | 150.00 | | sale3 | 3 + 2021 | 3 | 150.00 | | sale4 | 3 + 2021 | 4 | | 250.00 | sale2 | 4 + 2021 | 4 | | 250.00 | sale3 | 4 + 2021 | 4 | | 250.00 | sale4 | 4 + 2021 | 4 | | 250.00 | sale1 | 4 + 2022 | 5 | | | sale3 | 5 + 2022 | 5 | | | sale2 | 5 + 2022 | 5 | | | sale4 | 5 + 2022 | 5 | | | sale1 | 5 +(20 rows) + +drop schema shark_rotate_part2_dump cascade; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to table sales +drop cascades to table sales2 +drop cascades to view v1 +drop cascades to view v2 +\c postgres +drop database shark_rotate_part2_dump; diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index cd4d5ff496..e10575f458 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -2,6 +2,7 @@ test: init test: basetest test: clustered_index insert_stmt sbr_test +test: rotate-test-part2 rotate-test-part2_ci test: functions test: test_dbcc test_dbcc_case_sen test: test_sysviews diff --git a/contrib/shark/smartmatch.pl b/contrib/shark/smartmatch.pl new file mode 100644 index 0000000000..e99dc8113c --- /dev/null +++ b/contrib/shark/smartmatch.pl @@ -0,0 +1,583 @@ +#!/usr/bin/perl + + +# smartmatch: +# +# This script is extracted from Gurjeet Singh ( singh.gurjeet@gmail.com ) NEUROdiff patch. +# +# 04 Apr 2013 : First implementation + +use strict; +use warnings; + +sub usage +{ + print "Usage: smartmatch.pl \n"; + return; +} + +# file handles for expected and results files +my $EXPECTED; +my $RESULT; +my $NEW_EXPECTED; + +my $expected; # line iterator for EXPECTED file +my $result; # line iterator for RESULT file + +my $re; # the Regular Expression part of a line which starts with ? + +my $insideuo; # boolean, representing if we are INSIDE an UnOrdered set of lines + +my $bFirstLine; # Indicates whether the line going to be printed is the first or not + +my $iuo; # counter I for counting lines within an UnOrdered set +my $seenspecialinuo; # Seen special marker inside unordered group +my $smartmatch; # seen any special match syntax + +my $rc = 0; # Return Code + +my @earr = ( [], [] ); # 2-dimensional ARRay to keep Expected file's unmatched lines from an unordered set +my @rarr = ( [], [] ); # 2-dimensional ARRay to keep Result file's unmatched lines from unordered set + +my @searr = ( [], [] ); # 2-dimensional ARRay to keep Expected file's sorted lines from an unordered set +my @srarr = ( [], [] ); # 2-dimensional ARRay to keep Result file's sorted lines from unordered set + +# we require exactly 3 arguments +if( @ARGV != 3 ) +{ + usage(); + exit(2); +} + +# initialize (almost) everything +open $EXPECTED , "<", $ARGV[0] or die $!; +open $RESULT , "<", $ARGV[1] or die $!; +open $NEW_EXPECTED , ">", $ARGV[2] or die $!; + +$insideuo = 0; +$iuo = 0; +$smartmatch = 0; + +$bFirstLine = 1; + +# process all lines from both the files +while( 1 ) +{ + undef $!; + + my $matched = 1; + + $expected = <$EXPECTED>; + + undef $!; + + $result = <$RESULT>; + + + # one file finished but not the other + if( ( !defined( $expected ) || !defined( $result ) ) + && ( defined( $expected ) || defined( $result ) ) ) + { + $rc = 2; + + if( defined( $expected ) ) + { + if( $bFirstLine ) + { + print $NEW_EXPECTED "$expected"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$expected"; + } + } + + last; # while( 1 ) + } + + # both files finished + if( !defined( $expected ) && !defined( $result ) ) + { + last; # while( 1 ) + } + + # chomp away... + # Apart from getting rid of extra newlines in messages, this will also help + # us be agnostic about platform specific newline sequences. + # + # Correction: Apparently the above assumption is not true (found the hard + # way :( ). + # If the file was generated on Windows (CRLF), the Linux version of chomp + # will trim only \n and leave \r. Had to use dos2unix on the out files to + # make this script work. + chomp( $expected ); + chomp( $result ); + + # if the line from expected file starts with a ?, treat it specially + if( $expected =~ /^--\?.*/ ) + { + $smartmatch=1; + + # extract the Regular Expression + $re = substr $expected, 3; + + # If this is the beginning of an UnOrdered set of lines + if( $re eq 'unordered: start' ) + { + if( $insideuo ) + { + + if( $bFirstLine ) + { + print $NEW_EXPECTED "Nesting of 'unordered: start' blocks is not allowed"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\nNesting of 'unordered: start' blocks is not allowed"; + } + + exit( 2 ); + } + + # reset the variables for the UO set. + $iuo = 0; + $insideuo = 1; + $seenspecialinuo = 0; + + if( $bFirstLine ) + { + print $NEW_EXPECTED "$expected"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$expected"; + } + + next; + } + + # end of an UnOrderd set of lines + if( $re eq 'unordered: end' ) + { + if( !$insideuo ) + { + print $NEW_EXPECTED "'unordered: end' line found without a matching 'unordered: start' line\n"; + exit( 2 ); + } + + $insideuo = 0; + + # If there were some lines containing RE, do comparison the hard way + if( $seenspecialinuo ) + { + # begin the (m*n) processing of the two arrays. These arrays + # contain the set of unmatched lines from respective files + foreach my $eelemref ( @earr ) + { + my $i = 0; + + my $eelem = $eelemref->[0]; + + foreach my $relemref ( @rarr ) + { + my $relem = $relemref->[0]; + + $matched = 1; + + # treat these lines the same as we threat the others; + # that is, if an 'expected' line starts with a '?', we + # perform Regular Expression match, else we perform + # normal comparison. + + if( $eelem =~ /^--\?.*/ ) + { + my $tmpre = substr $eelem, 3; + + if( $relem !~ /^$tmpre$/ ) + { + $matched = 0; + } + else + { + if( $bFirstLine ) + { + print $NEW_EXPECTED "$relem"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$relem"; + } + + last; + } + } + elsif( $eelem ne $relem ) + { + $matched = 0; + } + else + { + if( $bFirstLine ) + { + print $NEW_EXPECTED "$relem"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$relem"; + } + + last; + } + + ++$i; + } # foreach @rarr + + if( !$matched ) + { + $rc = 2; + if( $bFirstLine ) + { + print $NEW_EXPECTED "$eelem"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$eelem"; + } + + } + else + { + splice @rarr, $i, 0; + } + } # foreach @earr + } + else # if there's no line containing an RE in this UO group, + # do it efficiently + { + # sort both arrays based on the text. + @searr = sort { $a->[0] cmp $b->[0] } @earr; + @srarr = sort { $a->[0] cmp $b->[0] } @rarr; + + my $min_len = (scalar(@searr) <= scalar(@srarr) ? scalar(@searr) : scalar(@srarr) ); + my $i; + $matched = 1; + + for( $i = 0; $i < $min_len; ++$i ) + { + my $eelem = $searr[$i][0]; + my $relem = $srarr[$i][0]; + + # treat these lines the same as we threat the others; that is, if an + # 'expected' line starts with a '?', we perform Regular Expression + # match, else we perform normal comparison. + + if( $eelem =~ /^--\?.*/ ) + { + my $tmpre = substr $eelem, 3; + + if( $relem !~ /^$tmpre$/ ) + { + $matched = 0; + } + } + elsif( $eelem ne $relem ) + { + $matched = 0; + } + } + + if ((scalar(@searr) > $i) || (scalar(@srarr) > $i)) + { + $matched = 0; + } + + if ( !$matched ) + { + $rc = 2; + for( my $i = 0; $i < scalar(@earr); ++$i ) + { + if( $bFirstLine ) + { + print $NEW_EXPECTED "$earr[$i][0]"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$earr[$i][0]"; + } + } + } + else + { + for( my $i = 0; $i < scalar(@rarr); ++$i ) + { + if( $bFirstLine ) + { + print $NEW_EXPECTED "$rarr[$i][0]"; + $bFirstLine = 0; + } + else + { + print $NEW_EXPECTED "\n$rarr[$i][0]"; + } + } + } + + $matched = 0; + } # else part of if( $seenspecialinuo ) + + if( $bFirstLine ) + { + $bFirstLine = 0; + print $NEW_EXPECTED "$expected"; + } + else + { + print $NEW_EXPECTED "\n$expected"; + } + + # reset the array variables to reclaim memory + @searr = @srarr = (); + @earr = @rarr = (); + + next; # while( 1 ) + + } # if re == 'unordered: end' + + # it is not an 'unordered' marker, so do regular Regular Expression match + else + { + my $re_1; + + if ($result !~ /^$re/) + { + if ($re =~ /(.*)datanode.*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*)\(cost=.*/ ) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*)\(actual time=.*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*)\(CPU:.*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*)\(RoughCheck CU:.*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*)Buffers:.*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /[.*]/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /(.*).*/) + { + $re_1 = quotemeta($1); + if ($result !~ /$re_1.*/) + { + $matched = 0; + } + } + elsif ($re =~ /^\s*Sort\s+Method.*/) + { + if ($result !~ /^\s*Sort\s+Method.*/) + { + $matched = 0; + } + } + + + elsif ($re =~ /Total runtime:.*/) + { + if ($result !~ /^\s*Total runtime:.*/) + { + $matched = 0; + } + } + elsif ($re =~ /^\s*QUERY PLAN\s*$/) + { + if ($result !~ /^\s*QUERY PLAN\s*$/) + { + $matched = 0; + } + } + elsif ($re =~ /^\-+$/) + { + if ($result !~ /^\-+$/) + { + $matched = 0; + } + } + else + { + $matched = 0; + } + } + } + + } # if $expected like ?.* + + # $expected doesn't begin with the special marker, so do normal comparison + elsif( $expected ne $result ) + { + $matched = 0; + } + + if( !$matched || $insideuo ) + { + # if the lines did not match, and if we are comparing an unordered set of lines, + # then save the lines for processing later. + if( $insideuo ) + { + $earr[$iuo][0] = $expected; + $rarr[$iuo][0] = $result; + + + if( !$seenspecialinuo && $expected =~ /^--\?.*/ ) + { + $seenspecialinuo = 1; + } + + ++$iuo; + } + else # print out the difference + { + $rc = 2; + if( $bFirstLine ) + { + $bFirstLine = 0; + print $NEW_EXPECTED "$expected"; + } + else + { + print $NEW_EXPECTED "\n$expected"; + } + } + } + else + { + if( $bFirstLine ) + { + $bFirstLine = 0; + print $NEW_EXPECTED "$result"; + } + else + { + print $NEW_EXPECTED "\n$result"; + } + + } +} + +close $EXPECTED; +close $RESULT; +close $NEW_EXPECTED; + +exit( $rc + $smartmatch ); diff --git a/contrib/shark/sql/rotate-test-part2.sql b/contrib/shark/sql/rotate-test-part2.sql new file mode 100644 index 0000000000..df3b5c3f8c --- /dev/null +++ b/contrib/shark/sql/rotate-test-part2.sql @@ -0,0 +1,327 @@ +create schema shark_rotate_test_part2; +set search_path = 'shark_rotate_test_part2'; + +set d_format_behavior_compat_options = 'enable_sbr_identifier'; + +-- part1: pivot +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)); + +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, a) +) as pivot; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN ([A], [B], "A", "B", C) +) as pivot; + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; + + +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +CALL proc1(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + +select * from v1; + +-- part2: unpivot + +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +); + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, [sale3], [sale4]) +) unpivot; + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); + +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + + +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +CALL proc2(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ + + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; + +select * from v2; + +set enable_ignore_case_in_dquotes on; +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + +set enable_ignore_case_in_dquotes off; + +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + +set ANSI_NULLS off; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + +set d_format_behavior_compat_options 'enable_sbr_identifier'; +set vacuum_cost_page_dirty 20; +set cpu_tuple_cost 0.02; +set effective_cache_size '128MB'; + +reset vacuum_cost_page_dirty; +reset cpu_tuple_cost; +reset effective_cache_size; + +set ansi_nulls on; +show ansi_nulls; +show transform_null_equals; +set transform_null_equals on; +show transform_null_equals; +show ansi_nulls; + +set ansi_nulls = off; +show ansi_nulls; +show transform_null_equals; +set transform_null_equals = off; +show transform_null_equals; +show ansi_nulls; + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; + +drop schema shark_rotate_test_part2 cascade; diff --git a/contrib/shark/sql/rotate-test-part2_ci.sql b/contrib/shark/sql/rotate-test-part2_ci.sql new file mode 100644 index 0000000000..06c37bd5ac --- /dev/null +++ b/contrib/shark/sql/rotate-test-part2_ci.sql @@ -0,0 +1,304 @@ +create schema shark_rotate_test_part2_ci; +set search_path = 'shark_rotate_test_part2_ci'; + +set d_format_behavior_compat_options = 'enable_sbr_identifier'; +-- part1: pivot +set enable_ignore_case_in_dquotes on; + +CREATE TABLE sales (year INT, product VARCHAR(50), amount DECIMAL(10, 2)) collate utf8_general_ci; + +INSERT INTO sales (year, product, amount) VALUES +(2020, 'A', 100), +(2020, 'B', 200), +(2021, 'A', 150), +(2021, 'B', 250); + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, a) +) as pivot; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN ([A], [B], "A", "B", C) +) as pivot; + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ); + + +SELECT * +FROM ( SELECT year, product, amount FROM sales) AS source_table +rotate ( count(amount) FOR product IN (A, B) ) pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B, 'A', 'SSS', 1, 2, 2.3, 1011) +) as pivot_table; + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(amount) FOR product IN (A, B) +) as pivot order by year; + + +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + + +-- expect error +SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where source_table.year > 1; + + +CREATE PROCEDURE proc1(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN ('A', 'B')) ; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +CALL proc1(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'A'; + con2 = 'B'; + sql1 = 'SELECT * FROM (SELECT year, product, amount FROM sales) AS source_table rotate (SUM(amount) FOR product IN (''' || con1 || ''',''' || con2 || '''))'; + EXECUTE IMMEDIATE sql1; +end; +/ + + create table CategoryTable2 ( + MergeDocID bigint, + CategoryFieldName nvarchar(100), + CategoryFieldValue nvarchar(255) + ); + + select * + from CategoryTable2 rotate (max(CategoryFieldValue ) + for CategoryFieldName + in (ItemAssetCategory_Code, ItemCostCategory_Code, ItemCreditCategory_Code, ItemMRPCategory_Code, ItemPriceCategory_Code, ItemProductionCategory_Code, ItemPurchaseCategory_Code, ItemSaleCategory_Code, ItemStockCategory_Code, ItemAssetCategory_Name, ItemCostCategory_Name, ItemCreditCategory_Name, ItemMRPCategory_Name, ItemPriceCategory_Name, ItemProductionCategory_Name, ItemPurchaseCategory_Name, ItemSaleCategory_Name, ItemStockCategory_Name)); + +create view v1 as SELECT * +FROM ( SELECT year, product, amount FROM sales ) AS source_table +rotate (count(*) FOR product IN (A, B) +) as pivot_table where pivot_table.year > 1; + +select * from v1; + +-- part2: unpivot + +CREATE TABLE sales2 ( + year INT, + product VARCHAR(50), + amount DECIMAL(10, 2), + sale1 int, + sale2 int, + sale3 int, + sale4 int, + sale5 int +) collate utf8_general_ci; + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES +(2020, 'A', 100, 1, 1, 1, 1, 1), +(2020, 'B', 200, 2, 2, 2, 2, 2), +(2021, 'A', 150, 3, 3, 3, 3, 3), +(2021, 'B', 250, 4, 4, 4, 4, 4), +(2022, 'C', 250, 5, 5, 5, 5, 5); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) as unpivot; + + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, [sale3], [sale4]) +) unpivot; + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +); + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) unpivot; + +INSERT INTO sales2 (year, product, amount, sale1, sale2, sale3, sale4, sale5) VALUES (2021, 'A', 150, NULL, NULL, NULL, NULL, NULL), (2021, 'B', 250, NULL, NULL, NULL, NULL, NULL), (2022, 'C', 250, NULL, NULL, NULL, NULL, NULL); + +SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) as unpvt; + +create table aaa as SELECT * +FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + + +CREATE PROCEDURE proc2(param1 CHAR(200)) +AS +DECLARE + cur refcursor; + row record; +BEGIN + open cur for SELECT * FROM sales2 not rotate(sale_all For sale IN (sale1, sale2, sale3, sale4)) unpvt; + LOOP + FETCH NEXT FROM cur INTO row; + EXIT WHEN NOT FOUND; + RAISE NOTICE '%', row; + END LOOP; +END; +/ + +CALL proc2(param1:='123'); + + +declare +con1 varchar; +con2 varchar; +sql1 varchar; +begin + con1 = 'sale1'; + con2 = 'sale2'; + sql1 = 'SELECT * FROM sales2 not rotate(sale_all For sale IN (' || con1 || ',' || con2 || ')) unpvt'; + EXECUTE IMMEDIATE sql1; +end; +/ + + +SELECT * +FROM sales2 +not rotate( + sale_all For sale IN (sale1, sale2, sale3, sale4) +) order by 1,2,3; + + +create view v2 as SELECT * FROM sales2 not rotate( sale_all For sale IN (sale1, sale2, sale3, sale4)) order by 1,2,3; + +select * from v2; + +select * from sales2 as source1 +rotate(sum(amount) for product in ('A', 'B')) as source2 +not rotate(sale_all for sale in (sale1, sale2, sale3, sale4)) as unpivot_table order by 1,2,3; + +set enable_ignore_case_in_dquotes off; + +-- part3: ANSI_NULLS +set ANSI_NULLS on; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + +set ANSI_NULLS off; +select NULL = NULL; +select 1 = NULL; +select NULL <> NULL; +select 1 <> NULL; +select NULL > NULL; +select 1 > NULL; +select NULL IS NULL; +select 1 IS NULL; +select NULL IS NOT NULL; +select 1 IS NOT NULL; +select 1 != NULL; +select NULL != NULL; + + +CREATE TABLE test1 (a INT NULL); +INSERT INTO test1 values (NULL),(0),(1); +set ANSI_NULLS on; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + + +set ANSI_NULLS off; +select * from test1 where NULL = NULL; +select * from test1 where 1 = NULL; +select * from test1 where NULL <> NULL; +select * from test1 where 1 <> NULL; +select * from test1 where NULL > NULL; +select * from test1 where 1 > NULL; +select * from test1 where NULL IS NULL; +select * from test1 where 1 IS NULL; +select * from test1 where NULL IS NOT NULL; +select * from test1 where 1 IS NOT NULL; +select * from test1 where 1 != NULL; +select * from test1 where NULL != NULL; + +-- part3 : body and rownum +create table body(body varchar); +insert into body values ('body'); +select body from body; + +create table rownum(rownum varchar); +insert into rownum values ('rownum'); +select rownum from rownum; + +create table pivot(pivot varchar); +insert into pivot values ('pivot'); +select pivot from pivot; + +create table unpivot(unpivot varchar); +insert into unpivot values ('unpivot'); +select unpivot from unpivot; + +drop table sales; +drop table categorytable2; +drop view v1; +drop table sales2; +drop table aaa; +drop view v2; +drop table test1; +drop table body; +drop table rownum; +drop table pivot; +drop table unpivot; + +drop schema shark_rotate_test_part2_ci cascade; diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index 1393e356dd..3d4c9784fb 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -462,6 +462,45 @@ tsql_CreateProcedureStmt: } ; +rotate_clause: + ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' alias_clause %prec ROTATE + { + RotateClause *n = makeNode(RotateClause); + n->aggregateFuncCallList = $3; + n->forColName = $4; + n->inExprList = $5; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char* raw_parse_query_string = yyextra->core_yy_extra.scanbuf; + n->inExprList = TransformToConstStrNode(n->inExprList, raw_parse_query_string); + n->alias = $7; + $$ = n; + } + ; + +unrotate_clause: + NOT ROTATE include_exclude_null_clause '(' unrotate_name_list rotate_for_clause unrotate_in_clause ')' alias_clause %prec ROTATE + { + UnrotateClause *n = makeNode(UnrotateClause); + n->includeNull = $3; + n->colNameList = $5; + n->forColName = $6; + n->inExprList = $7; + $$ = n; + } + ; + +VariableSetStmt: + SET IDENT var_value + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; + n->name = $2; + n->args = list_make1($3); + n->is_local = false; + $$ = (Node *) n; + } + ; + unreserved_keyword: CHECKIDENT | DBCC diff --git a/contrib/shark/src/backend_parser/kwlist.h b/contrib/shark/src/backend_parser/kwlist.h index 63edcf0447..870b65c556 100644 --- a/contrib/shark/src/backend_parser/kwlist.h +++ b/contrib/shark/src/backend_parser/kwlist.h @@ -579,9 +579,6 @@ PG_KEYWORD("rotate", ROTATE, UNRESERVED_KEYWORD) PG_KEYWORD("rotation", ROTATION, UNRESERVED_KEYWORD) PG_KEYWORD("row", ROW, COL_NAME_KEYWORD) PG_KEYWORD("row_count", ROW_COUNT, UNRESERVED_KEYWORD) -#ifndef ENABLE_MULTIPLE_NODES -PG_KEYWORD("rownum", ROWNUM, RESERVED_KEYWORD) -#endif PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD) PG_KEYWORD("rowtype", ROWTYPE_P, UNRESERVED_KEYWORD) PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD) diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index e5e2ca0eb3..9cb3e37687 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -578,6 +578,7 @@ try_vector_engine_strategy|enum|off,force,optimal|NULL|NULL plog_merge_age|int|0,2147483647|ms|how long to aggregate profile logs.0 disable logging. suggest setting value is 1000 times.| fault_mon_timeout|int|0,1440|min|how many miniutes to monitor lwlock. 0 will disable that.| transform_null_equals|bool|0,0|NULL|This only affects 'expr=NULL', not other comparison operators or other expressions involving some of the equality operator computing (such as IN).| +ansi_nulls|bool|0,0|NULL|Contrary to the transform_null_equals parameter.| udf_memory_limit|int|204800,2147483647|kB|NULL| uncontrolled_memory_context|string|0,0|NULL|NULL| unix_socket_directory|string|0,0|NULL|NULL| diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 21053751e4..376a9cd108 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -310,6 +310,7 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm static Node* MakeNoArgFunctionCall(List* funcName, int location); static char* IdentResolveToChar(char *ident, core_yyscan_t yyscanner); static void contain_unsupport_node(Node* node, bool* has_unsupport_default_node); +static List* TransformToConstStrNode(List *inExprList, char* raw_str); /* Please note that the following line will be replaced with the contents of given file name even if with starting with a comment */ /*$$include "gram-tsql-prologue.y.h"*/ @@ -26535,14 +26536,20 @@ opt_alias_clause: alias_clause { $$ = $1; } rotate_clause: ROTATE '(' func_application_list rotate_for_clause rotate_in_clause ')' %prec ROTATE { - if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT ) + if (!DB_IS_CMPT_AD) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("rotate clause is supported only in A_FORMAT database."))); + errmsg("rotate clause is supported only in A or D FORMAT database."))); RotateClause *n = makeNode(RotateClause); n->aggregateFuncCallList = $3; n->forColName = $4; - n->inExprList = $5; + base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); + char* raw_parse_query_string = yyextra->core_yy_extra.scanbuf; + if (DB_IS_CMPT(D_FORMAT)) { + n->inExprList = TransformToConstStrNode($5, raw_parse_query_string); + } else { + n->inExprList = $5; + } $$ = n; } ; @@ -26564,10 +26571,10 @@ func_application_list: unrotate_clause: NOT ROTATE include_exclude_null_clause '(' unrotate_name_list rotate_for_clause unrotate_in_clause ')' %prec ROTATE { - if( u_sess->attr.attr_sql.sql_compatibility != A_FORMAT ) + if (!DB_IS_CMPT_AD) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("not rotate clause is supported only in A_FORMAT database."))); + errmsg("not rotate clause is supported only in A or D FORMAT database."))); UnrotateClause *n = makeNode(UnrotateClause); n->includeNull = $3; n->colNameList = $5; @@ -34940,6 +34947,70 @@ void contain_unsupport_node(Node* node, bool* has_unsupport_default_node) } +static List* TransformToConstStrNode(List *inExprList, char* raw_str) +{ + ListCell* cell = NULL; + ListCell *exprCell = NULL; + ResTarget *resTarget = NULL; + errno_t rc; + + foreach (cell, inExprList) + { + RotateInCell *rotateinCell = (RotateInCell *)lfirst(cell); + foreach (exprCell, rotateinCell->rotateInExpr) { + resTarget = (ResTarget *)lfirst(exprCell); + if (NULL == rotateinCell->aliasname && IsA(resTarget->val, ColumnRef)) { + ColumnRef* column_ref = (ColumnRef*)resTarget->val; + // column_ref info has been convert to lower case, so we need to extact the not convert lower case info in raw str + char * lower_column_name = strVal(linitial(column_ref->fields)); + int len = strlen(lower_column_name); + pfree(lower_column_name); + char *raw_col_name = (char *)palloc(len + 1); + raw_col_name[len] = '\0'; + errno_t rc = EOK; + int column_offset = 0; + if (raw_str[column_ref->location] == '[' || raw_str[column_ref->location] == '"') { + column_offset++; + } + rc = strncpy_s(raw_col_name, len + 1, raw_str + column_ref->location + column_offset, len); + securec_check(rc, "\0", "\0"); + Node* const_node = makeStringConst(raw_col_name, column_ref->location); + resTarget->val = const_node; + } if (NULL == rotateinCell->aliasname && IsA(resTarget->val, A_Const)) { + const Value *val = &((A_Const *)resTarget->val)->val; + char * column_to_const_str = NULL; + switch (val->type) { + case T_Integer: { + char* new_col_name = (char*)palloc(NAMEDATALEN); + rc = memset_s(new_col_name, NAMEDATALEN, 0, NAMEDATALEN); + securec_check_c(rc, "\0", "\0"); + rc = snprintf_s(new_col_name, NAMEDATALEN, NAMEDATALEN - 1, "%ld", intVal(val)); + securec_check_ss(rc, "\0", "\0"); + column_to_const_str = new_col_name; + break; + } + + case T_Float: + case T_String: + case T_BitString: + column_to_const_str = strVal(val); + break; + + default: + break; + } + if (column_to_const_str != NULL) { + Node* const_node = makeStringConst(column_to_const_str, ((A_Const *)resTarget)->location); + resTarget->val = const_node; + } + } + } + } + return inExprList; +} + + + /* * Must undefine this stuff before including scan.c, since it has different * definitions for these macros. diff --git a/src/common/backend/parser/parse_clause.cpp b/src/common/backend/parser/parse_clause.cpp index eca48eb029..a9ed2fe5a9 100644 --- a/src/common/backend/parser/parse_clause.cpp +++ b/src/common/backend/parser/parse_clause.cpp @@ -822,10 +822,15 @@ static RangeTblEntry* transformRangeSubselect(ParseState* pstate, RangeSubselect (errcode(ERRCODE_UNEXPECTED_NODE_STATE), errmsg("unexpected non-SELECT command in subquery in FROM"))); } + Alias* subquery_alias = r->alias; + if (DB_IS_CMPT(D_FORMAT) && r->rotate != NULL && r->rotate->alias != NULL) { + subquery_alias = r->rotate->alias; + } + /* * OK, build an RTE for the subquery. */ - rte = addRangeTableEntryForSubquery(pstate, query, r->alias, r->lateral, true); + rte = addRangeTableEntryForSubquery(pstate, query, subquery_alias, r->lateral, true); return rte; } diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp index a675487957..2220c26c4b 100644 --- a/src/common/backend/parser/parse_expr.cpp +++ b/src/common/backend/parser/parse_expr.cpp @@ -1452,6 +1452,16 @@ static bool exprIsNullConstant(Node* arg) return false; } + + +static inline bool is_not_null_operator(const char * operator_name) +{ + if (operator_name == NULL) { + return false; + } + return strcmp(operator_name, "!=") == 0 || strcmp(operator_name, "<>") == 0; +} + static Node* transformAExprOp(ParseState* pstate, A_Expr* a) { Node* lexpr = a->lexpr; @@ -1474,6 +1484,16 @@ static Node* transformAExprOp(ParseState* pstate, A_Expr* a) n->arg = exprIsNullConstant(lexpr) ? (Expr *)rexpr : (Expr *)lexpr; + result = transformExprRecurse(pstate, (Node*)n); + } else if (DB_IS_CMPT(D_FORMAT) && u_sess->attr.attr_sql.Transform_null_equals && list_length(a->name) == 1 && + is_not_null_operator(strVal(linitial(a->name))) && (exprIsNullConstant(lexpr) || exprIsNullConstant(rexpr)) && + (!IsA(lexpr, CaseTestExpr) && !IsA(rexpr, CaseTestExpr))) { + NullTest* n = makeNode(NullTest); + + n->nulltesttype = IS_NOT_NULL; + + n->arg = exprIsNullConstant(lexpr) ? (Expr *)rexpr : (Expr *)lexpr; + result = transformExprRecurse(pstate, (Node*)n); } else if (lexpr && IsA(lexpr, RowExpr) && rexpr && IsA(rexpr, SubLink) && ((SubLink*)rexpr)->subLinkType == EXPR_SUBLINK) { diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 73608efd2e..2f5f35c69e 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -353,6 +353,7 @@ const char* sync_guc_variable_namelist[] = {"work_mem", "standard_conforming_strings", "synchronize_seqscans", "transform_null_equals", + "ansi_nulls", "exit_on_error", #ifdef ENABLE_MULTIPLE_NODES "gtm_backup_barrier", diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index f30e2d559f..3e961a735c 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -170,6 +170,8 @@ static bool parse_query_dop(int* newval, void** extra, GucSource source); static void AssignQueryDop(int newval, void* extra); +static void AssignAnsiNulls(bool newval, void* extra); +static void AssignTransformNullEquals(bool newval, void* extra); static bool check_job_max_workers(int* newval, void** extra, GucSource source); static bool check_statement_max_mem(int* newval, void** extra, GucSource source); static bool check_statement_mem(int* newval, void** extra, GucSource source); @@ -1134,19 +1136,31 @@ static void InitSqlConfigureNamesBool() &u_sess->attr.attr_sql.Transform_null_equals, false, NULL, + AssignTransformNullEquals, + NULL}, + {{"ansi_nulls", + PGC_USERSET, + NODE_ALL, + COMPAT_OPTIONS_CLIENT, + gettext_noop("Contrary to the transform_null_equals parameter."), + gettext_noop("When turned on, The transform_null_equals will be set to off." + "When turned off, The transform_null_equals will be set to on.")}, + &u_sess->attr.attr_sql.ansi_nulls, + true, + NULL, + AssignAnsiNulls, + NULL}, + {{"transform_to_numeric_operators", + PGC_USERSET, + NODE_SINGLENODE, + QUERY_TUNING_METHOD, + gettext_noop("When turn on, choose numeric (op) numeric for varchar (op) int."), + NULL}, + &u_sess->attr.attr_sql.transform_to_numeric_operators, + false, + NULL, NULL, NULL}, - {{"transform_to_numeric_operators", - PGC_USERSET, - NODE_SINGLENODE, - QUERY_TUNING_METHOD, - gettext_noop("When turn on, choose numeric (op) numeric for varchar (op) int."), - NULL}, - &u_sess->attr.attr_sql.transform_to_numeric_operators, - false, - NULL, - NULL, - NULL}, {{"check_function_bodies", PGC_USERSET, NODE_ALL, @@ -4755,4 +4769,21 @@ static bool init_parameterized_query_context(bool* newval, void** exttra, GucSou ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); } return true; -} \ No newline at end of file +} + +/* + * @Description: assign new value to ansi_nulls. + * + * @param[IN] newval: new value + * @param[IN] extra: N/A + * @return: void + */ +static void AssignAnsiNulls(bool newval, void* extra) +{ + u_sess->attr.attr_sql.Transform_null_equals = !newval; +} + +static void AssignTransformNullEquals(bool newval, void* extra) +{ + u_sess->attr.attr_sql.ansi_nulls = !newval; +} diff --git a/src/include/knl/knl_guc/knl_session_attr_sql.h b/src/include/knl/knl_guc/knl_session_attr_sql.h index 0b482311b5..2dd32ffbe6 100644 --- a/src/include/knl/knl_guc/knl_session_attr_sql.h +++ b/src/include/knl/knl_guc/knl_session_attr_sql.h @@ -111,6 +111,7 @@ typedef struct knl_session_attr_sql { bool enable_autoanalyze; bool SQL_inheritance; bool Transform_null_equals; + bool ansi_nulls; bool check_function_bodies; bool Array_nulls; bool default_with_oids; diff --git a/src/include/nodes/parsenodes_common.h b/src/include/nodes/parsenodes_common.h index 61b72bcbb0..f89e1d564c 100644 --- a/src/include/nodes/parsenodes_common.h +++ b/src/include/nodes/parsenodes_common.h @@ -696,6 +696,7 @@ typedef struct UnrotateClause { List *colNameList; List *forColName; List *inExprList; + Alias *alias; /* function aliases */ } UnrotateClause; typedef struct UnrotateInCell { @@ -1877,6 +1878,7 @@ typedef struct RotateClause { List *forColName; List *inExprList; List *aggregateFuncCallList; + Alias *alias; /* function aliases */ } RotateClause; typedef struct RotateInCell { diff --git a/src/include/postgres.h b/src/include/postgres.h index 6eb375c135..d3b8b5b5d0 100644 --- a/src/include/postgres.h +++ b/src/include/postgres.h @@ -264,6 +264,8 @@ typedef enum { #define IS_CMPT(cmpt, flag) (((uint32)cmpt & (uint32)(flag)) != 0) #define DB_IS_CMPT(flag) IS_CMPT(u_sess->attr.attr_sql.sql_compatibility, (flag)) #define DB_IS_CMPT_BD (DB_IS_CMPT(B_FORMAT) || DB_IS_CMPT(D_FORMAT)) +#define DB_IS_CMPT_AD (DB_IS_CMPT(A_FORMAT) || DB_IS_CMPT(D_FORMAT)) + #endif /* HAVE_DATABASE_TYPE */ -- Gitee From 33252fa9bec8350f9f6d5341c18a86193b78969e Mon Sep 17 00:00:00 2001 From: wangpingyun <2418191738@qq.com> Date: Sat, 15 Mar 2025 15:46:56 +0800 Subject: [PATCH 05/11] =?UTF-8?q?D=E5=85=BC=E5=AE=B9=E6=80=A7=E5=B8=B8?= =?UTF-8?q?=E7=94=A8=E5=87=BD=E6=95=B0=E5=AE=9E=E7=8E=B0Part1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/Makefile | 2 +- contrib/shark/expected/day_test.out | 186 ++++ contrib/shark/expected/objectproperty.out | 870 +++++++++++++++ contrib/shark/expected/rand_test.out | 89 ++ contrib/shark/parallel_schedule | 2 + contrib/shark/shark--1.0.sql | 33 + contrib/shark/sql/day_test.sql | 55 + contrib/shark/sql/objectproperty.sql | 205 ++++ contrib/shark/sql/rand_test.sql | 28 + contrib/shark/varlena.cpp | 1184 +++++++++++++++++++++ 10 files changed, 2653 insertions(+), 1 deletion(-) create mode 100644 contrib/shark/expected/day_test.out create mode 100644 contrib/shark/expected/objectproperty.out create mode 100644 contrib/shark/expected/rand_test.out create mode 100644 contrib/shark/sql/day_test.sql create mode 100644 contrib/shark/sql/objectproperty.sql create mode 100644 contrib/shark/sql/rand_test.sql create mode 100644 contrib/shark/varlena.cpp diff --git a/contrib/shark/Makefile b/contrib/shark/Makefile index c6e9201328..2e2a25a75c 100644 --- a/contrib/shark/Makefile +++ b/contrib/shark/Makefile @@ -5,7 +5,7 @@ PLDIR=src/pltsql DATA = shark--1.0.sql REGRESS = dummy -OBJS = shark.o dbcc.o +OBJS = shark.o dbcc.o varlena.o OBJS += $(BEPARSERDIR)/parser.o OBJS += $(BEPARSERDIR)/gram-backend.o OBJS += $(BEPARSERDIR)/keywords.o diff --git a/contrib/shark/expected/day_test.out b/contrib/shark/expected/day_test.out new file mode 100644 index 0000000000..87333de074 --- /dev/null +++ b/contrib/shark/expected/day_test.out @@ -0,0 +1,186 @@ +-- 测试不同日期格式 +SELECT DAY('2023-10-01') AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-12-31') AS DayPart; -- 预期结果:31 + daypart +--------- + 31 +(1 row) + +SELECT DAY('2023-02-28') AS DayPart; -- 预期结果:28 + daypart +--------- + 28 +(1 row) + +SELECT DAY('2024-02-29') AS DayPart; -- 预期结果:29 (闰年) + daypart +--------- + 29 +(1 row) + +-- 测试边界值 +SELECT DAY('1753-01-01') AS DayPart; -- 预期结果:1 (SQL Server 的最小日期) + daypart +--------- + 1 +(1 row) + +SELECT DAY('9999-12-31') AS DayPart; -- 预期结果:31 (SQL Server 的最大日期) + daypart +--------- + 31 +(1 row) + +-- 测试 NULL 值 +SELECT DAY(NULL) AS DayPart; -- 预期结果:NULL + daypart +--------- + +(1 row) + +-- 测试非日期类型 +SELECT DAY('2023-10-01'::date) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01'::smalldatetime) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01'::timestamp) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01'::timestamptz) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01'::abstime) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01'::timestamp(0) with time zone) AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +-- 测试时间部分 +SELECT DAY('2023-10-01 12:34:56') AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SELECT DAY('2023-10-01 23:59:59.997') AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +-- 测试不同的区域设置 +SET DateStyle to MDY; +SELECT DAY('10/01/2023') AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +SET DateStyle to DMY; +SELECT DAY('01/10/2023') AS DayPart; -- 预期结果:10 + daypart +--------- + 1 +(1 row) + +SET DateStyle to YMD; +SELECT DAY('2023-10-01') AS DayPart; -- 预期结果:1 + daypart +--------- + 1 +(1 row) + +-- 测试动态日期 +SELECT DAY(CURRENT_DATE) AS DayPart; -- 预期结果:当前日期的天数部分 + daypart +--------- + 9 +(1 row) + +SELECT DAY(CURRENT_STAMP) AS DayPart; -- 预期结果:当前日期的天数部分 +ERROR: column "current_stamp" does not exist +LINE 1: SELECT DAY(CURRENT_STAMP) AS DayPart; + ^ +CONTEXT: referenced column: daypart +-- 异常测试 +SELECT DAY(CURRENT_TIME) AS DayPart; +ERROR: function day(time with time zone) does not exist +LINE 1: SELECT DAY(CURRENT_TIME) AS DayPart; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: daypart +SELECT DAY('20:12:12') AS DayPart; +ERROR: invalid input syntax for type timestamp with time zone: "20:12:12" +LINE 1: SELECT DAY('20:12:12') AS DayPart; + ^ +CONTEXT: referenced column: daypart +SELECT DAY(NULL) AS DayPart; + daypart +--------- + +(1 row) + +SELECT DAY(12345) AS DayPart; +ERROR: function day(integer) does not exist +LINE 1: SELECT DAY(12345) AS DayPart; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: daypart +SELECT DAY('abc') AS DayPart; +ERROR: invalid input syntax for type timestamp with time zone: "abc" +LINE 1: SELECT DAY('abc') AS DayPart; + ^ +CONTEXT: referenced column: daypart +SELECT DAY('2023-13-01') AS DayPart; +ERROR: date/time field value out of range: "2023-13-01" +LINE 1: SELECT DAY('2023-13-01') AS DayPart; + ^ +HINT: Perhaps you need a different "datestyle" setting. +CONTEXT: referenced column: daypart +SELECT DAY('2023-02-30') AS DayPart; +ERROR: date/time field value out of range: "2023-02-30" +LINE 1: SELECT DAY('2023-02-30') AS DayPart; + ^ +CONTEXT: referenced column: daypart +SELECT DAY('2023-04-31') AS DayPart; +ERROR: date/time field value out of range: "2023-04-31" +LINE 1: SELECT DAY('2023-04-31') AS DayPart; + ^ +CONTEXT: referenced column: daypart +SELECT DAY('2023-00-01') AS DayPart; +ERROR: date/time field value out of range: "2023-00-01" +LINE 1: SELECT DAY('2023-00-01') AS DayPart; + ^ +HINT: Perhaps you need a different "datestyle" setting. +CONTEXT: referenced column: daypart +SELECT DAY('2023-01-00') AS DayPart; +ERROR: date/time field value out of range: "2023-01-00" +LINE 1: SELECT DAY('2023-01-00') AS DayPart; + ^ +HINT: Perhaps you need a different "datestyle" setting. +CONTEXT: referenced column: daypart diff --git a/contrib/shark/expected/objectproperty.out b/contrib/shark/expected/objectproperty.out new file mode 100644 index 0000000000..869e90df3e --- /dev/null +++ b/contrib/shark/expected/objectproperty.out @@ -0,0 +1,870 @@ +CREATE TABLE sys.students ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + age INT, + grade DECIMAL(5, 2) +); +NOTICE: CREATE TABLE will create implicit sequence "students_id_seq" for serial column "students.id" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students" +CREATE VIEW sys.student_grades AS +SELECT name, grade +FROM students; +CREATE OR REPLACE FUNCTION sys.calculate_total_grade() +RETURNS DECIMAL(10, 2) AS $$ +DECLARE + total_grade DECIMAL(10, 2) := 0; +BEGIN + SELECT SUM(grade) INTO total_grade FROM students; + RETURN total_grade; +END; +$$ LANGUAGE plpgsql; +CREATE OR REPLACE PROCEDURE sys.insert_student( + student_name VARCHAR(100), + student_age INT, + student_grade DECIMAL(5, 2) +) AS +BEGIN + INSERT INTO students (name, age, grade) VALUES (student_name, student_age, student_grade); +END; +/ +CREATE OR REPLACE FUNCTION sys.update_total_grade() +RETURNS TRIGGER AS $$ +BEGIN + RAISE NOTICE 'Total grade updated: %', calculate_total_grade(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER trigger_update_total_grade +AFTER INSERT OR UPDATE OR DELETE ON students +FOR EACH STATEMENT EXECUTE PROCEDURE update_total_grade(); +select object_id('sys.students'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.students_pkey'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.student_grades'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.calculate_total_grade'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.insert_student'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.trigger_update_total_grade'); + object_id +----------- +--?.* +(1 row) + +set search_path = 'sys'; +select object_id('students', 'U'); + object_id +----------- +--?.* +(1 row) + +select object_id('students_pkey', 'PK'); + object_id +----------- +--?.* +(1 row) + +select object_id('student_grades', 'V'); + object_id +----------- +--?.* +(1 row) + +select object_id('calculate_total_grade', 'FN'); + object_id +----------- +--?.* +(1 row) + +select object_id('insert_student', 'P'); + object_id +----------- +--?.* +(1 row) + +select object_id('trigger_update_total_grade', 'TR'); + object_id +----------- +--?.* +(1 row) + +select object_id('sys.students'); + object_id +----------- +--?.* +(1 row) + +select object_id('contrib_regression.sys.students'); +ERROR: Can only do lookup in current database. +CONTEXT: referenced column: object_id +select objectproperty(object_id('students'), 'istable') as istable; + istable +--------- + 1 +(1 row) + +select objectproperty(object_id('students'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('students'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + +(1 row) + +select objectproperty(object_id('students'), 'isschemabound') as isschemabound; + isschemabound +--------------- + +(1 row) + +select objectproperty(object_id('students'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + +(1 row) + +select objectproperty(object_id('students'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('students'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + +(1 row) + +select objectproperty(object_id('students'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'isview') as isview; + isview +-------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'isusertable') as isusertable; + isusertable +------------- + 1 +(1 row) + +select objectproperty(object_id('students'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('students'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('students'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'isindexed') as isindexed; + isindexed +----------- + 1 +(1 row) + +select objectproperty(object_id('students'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'istrigger') as istrigger; + istrigger +----------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'istable') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('student_grades'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + 1 +(1 row) + +select objectproperty(object_id('student_grades'), 'isschemabound') as isschemabound; + isschemabound +--------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + 1 +(1 row) + +select objectproperty(object_id('student_grades'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + +(1 row) + +select objectproperty(object_id('student_grades'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + +(1 row) + +select objectproperty(object_id('student_grades'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('student_grades'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + +(1 row) + +select objectproperty(object_id('student_grades'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isview') as isview; + isview +-------- + 1 +(1 row) + +select objectproperty(object_id('student_grades'), 'isusertable') as isusertable; + isusertable +------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isindexed') as isindexed; + isindexed +----------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('student_grades'), 'istrigger') as istrigger; + istrigger +----------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'istable') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + 1 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isschemabound') as isschemabound; + isschemabound +--------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + 1 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isview') as isview; + isview +-------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isusertable') as isusertable; + isusertable +------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 1 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isindexed') as isindexed; + isindexed +----------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('calculate_total_grade'), 'istrigger') as istrigger; + istrigger +----------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'istable') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('insert_student'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + 1 +(1 row) + +select objectproperty(object_id('insert_student'), 'isschemabound') as isschemabound; + isschemabound +--------------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + 1 +(1 row) + +select objectproperty(object_id('insert_student'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + +(1 row) + +select objectproperty(object_id('insert_student'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + +(1 row) + +select objectproperty(object_id('insert_student'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('insert_student'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + +(1 row) + +select objectproperty(object_id('insert_student'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 1 +(1 row) + +select objectproperty(object_id('insert_student'), 'isview') as isview; + isview +-------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isusertable') as isusertable; + isusertable +------------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isindexed') as isindexed; + isindexed +----------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('insert_student'), 'istrigger') as istrigger; + istrigger +----------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'istable') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isschemabound') as isschemabound; + isschemabound +--------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isview') as isview; + isview +-------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isusertable') as isusertable; + isusertable +------------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isindexed') as isindexed; + isindexed +----------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('trigger_update_total_grade'), 'istrigger') as istrigger; + istrigger +----------- + 1 +(1 row) + +--异常用例 +CREATE TEMP TABLE sys.temp_sales ( + product_name VARCHAR(255), + sale_amount NUMERIC(10, 2), + sale_date DATE +); +ERROR: temporary tables cannot specify a schema name +select object_id('temp_sales'); + object_id +----------- + +(1 row) + +select objectproperty(object_id('temp_sales'), 'istable') as istable; + istable +--------- + +(1 row) + +select object_id(); +ERROR: function object_id() does not exist +LINE 1: select object_id(); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: object_id +select object_id('[]'); + object_id +----------- + +(1 row) + +select object_id('student'); + object_id +----------- + +(1 row) + +select object_id('', 'U'); + object_id +----------- + +(1 row) + +select object_id('students', ''); + object_id +----------- + 16414 +(1 row) + +select object_id('students', 'FN'); + object_id +----------- + +(1 row) + +select object_id('othersys.students'); + object_id +----------- + +(1 row) + +select object_id('otherdb.sys.students'); +ERROR: Can only do lookup in current database. +CONTEXT: referenced column: object_id +select objectproperty('', 'istable') as istable; + istable +--------- + +(1 row) + +select objectproperty('students', 'istable') as istable; +ERROR: invalid input syntax for integer: "students" +LINE 1: select objectproperty('students', 'istable') as istable; + ^ +CONTEXT: referenced column: istable +select objectproperty(object_id('students'), '') as istable; + istable +--------- + +(1 row) + +select objectproperty('', '') as istable; + istable +--------- + +(1 row) + +select objectproperty(object_id('student'), 'istable') as istable; + istable +--------- + +(1 row) + +select objectproperty(object_id('students'), 'isview') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('students'), 'ssr') as istable; + istable +--------- + +(1 row) + +create user object_user identified by 'Test@123'; +SET SESSION AUTHORIZATION object_user PASSWORD 'Test@123'; +create schema object_schema; +ERROR: permission denied for database contrib_regression +DETAIL: N/A +create table object_schema.t1 (n1 int); +ERROR: schema "object_schema" does not exist +RESET SESSION AUTHORIZATION; +select object_id('object_schema.t1'); + object_id +----------- + +(1 row) + diff --git a/contrib/shark/expected/rand_test.out b/contrib/shark/expected/rand_test.out new file mode 100644 index 0000000000..3baeb7ec7e --- /dev/null +++ b/contrib/shark/expected/rand_test.out @@ -0,0 +1,89 @@ +DO $$ +DECLARE + counter SMALLINT := 1; +BEGIN + WHILE counter < 5 LOOP + RAISE NOTICE '%', RAND(); + counter := counter + 1; + END LOOP; +END $$; +--?.* +--?.* +--?.* +--?.* +SELECT rand(1); + rand +------------------- + .0416303444653749 +(1 row) + +SELECT rand(-1); + rand +------------------ + .300025727134198 +(1 row) + +SELECT rand(1::SMALLINT); + rand +------------------- + .0416303444653749 +(1 row) + +SELECT rand(-1::SMALLINT); + rand +------------------ + .300025727134198 +(1 row) + +SELECT rand(1::tinyint); + rand +------------------- + .0416303444653749 +(1 row) + +SELECT rand(-1::tinyint); + rand +------------------ + .300025727134198 +(1 row) + +drop table if exists t1; +NOTICE: table "t1" does not exist, skipping +create table t1(a1 int); +insert into t1 values(floor((100 + RAND() * 100))); +select * from t1; + a1 +----- +--?.* +(1 row) + +select RAND(null); + rand +------------------ + .170828036032617 +(1 row) + +select RAND(2147483647); + rand +------------------ + .800025727134198 +(1 row) + +select RAND(2147483648); +ERROR: function rand(bigint) does not exist +LINE 1: select RAND(2147483648); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: rand +select RAND(-2147483648); + rand +------------------ + .670828036032617 +(1 row) + +select RAND(-2147483649); +ERROR: function rand(bigint) does not exist +LINE 1: select RAND(-2147483649); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +CONTEXT: referenced column: rand diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index e10575f458..578e0def9f 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -1,6 +1,8 @@ # init must be first test: init test: basetest +test: day_test rand_test +test: objectproperty test: clustered_index insert_stmt sbr_test test: rotate-test-part2 rotate-test-part2_ci test: functions diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index f074f9a575..7b1d04d6d3 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -11,6 +11,39 @@ create function pltsql_validator(oid) create function pltsql_inline_handler(internal) returns void as 'MODULE_PATHNAME' language C; +CREATE OR REPLACE FUNCTION sys.day (timestamptz) RETURNS float8 LANGUAGE SQL IMMUTABLE STRICT as 'select pg_catalog.date_part(''day'', $1)'; +CREATE OR REPLACE FUNCTION sys.day (abstime) RETURNS float8 LANGUAGE SQL IMMUTABLE STRICT as 'select pg_catalog.date_part(''day'', $1)'; +CREATE OR REPLACE FUNCTION sys.day (date) RETURNS float8 LANGUAGE SQL IMMUTABLE STRICT as 'select pg_catalog.date_part(''day'', $1)'; +CREATE OR REPLACE FUNCTION sys.day (timestamp(0) with time zone) RETURNS float8 LANGUAGE SQL IMMUTABLE STRICT as 'select pg_catalog.date_part(''day'', $1)'; + +CREATE OR REPLACE FUNCTION sys.rand() +returns double precision +as +$$ +begin + return (select random()); +end; +$$ +language plpgsql; + +CREATE OR REPLACE FUNCTION sys.rand(int) returns double precision LANGUAGE C volatile as '$libdir/shark', 'rand_seed'; +CREATE OR REPLACE FUNCTION sys.rand(smallint) returns double precision LANGUAGE SQL volatile as 'select rand($1::int)'; +CREATE OR REPLACE FUNCTION sys.rand(tinyint) returns double precision LANGUAGE SQL volatile as 'select rand($1::int)'; + + +-- Return the object ID given the object name. Can specify optional type. +CREATE OR REPLACE FUNCTION sys.object_id(IN object_name VARCHAR, IN object_type VARCHAR DEFAULT '') +RETURNS integer AS '$libdir/shark', 'object_id_internal' +LANGUAGE C STABLE STRICT; + +CREATE OR REPLACE FUNCTION objectproperty( + id INT, + property VARCHAR + ) +RETURNS INT AS +'$libdir/shark', 'objectproperty_internal' +LANGUAGE C STABLE; + create trusted language pltsql handler pltsql_call_handler inline pltsql_inline_handler diff --git a/contrib/shark/sql/day_test.sql b/contrib/shark/sql/day_test.sql new file mode 100644 index 0000000000..df1e973be4 --- /dev/null +++ b/contrib/shark/sql/day_test.sql @@ -0,0 +1,55 @@ + +-- 测试不同日期格式 +SELECT DAY('2023-10-01') AS DayPart; -- 预期结果:1 +SELECT DAY('2023-12-31') AS DayPart; -- 预期结果:31 +SELECT DAY('2023-02-28') AS DayPart; -- 预期结果:28 +SELECT DAY('2024-02-29') AS DayPart; -- 预期结果:29 (闰年) + +-- 测试边界值 +SELECT DAY('1753-01-01') AS DayPart; -- 预期结果:1 (SQL Server 的最小日期) +SELECT DAY('9999-12-31') AS DayPart; -- 预期结果:31 (SQL Server 的最大日期) + +-- 测试 NULL 值 +SELECT DAY(NULL) AS DayPart; -- 预期结果:NULL + +-- 测试非日期类型 +SELECT DAY('2023-10-01'::date) AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01'::smalldatetime) AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01'::timestamp) AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01'::timestamptz) AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01'::abstime) AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01'::timestamp(0) with time zone) AS DayPart; -- 预期结果:1 + +-- 测试时间部分 +SELECT DAY('2023-10-01 12:34:56') AS DayPart; -- 预期结果:1 +SELECT DAY('2023-10-01 23:59:59.997') AS DayPart; -- 预期结果:1 + +-- 测试不同的区域设置 +SET DateStyle to MDY; +SELECT DAY('10/01/2023') AS DayPart; -- 预期结果:1 + +SET DateStyle to DMY; +SELECT DAY('01/10/2023') AS DayPart; -- 预期结果:10 + +SET DateStyle to YMD; +SELECT DAY('2023-10-01') AS DayPart; -- 预期结果:1 + +-- 测试动态日期 +SELECT DAY(CURRENT_DATE) AS DayPart; -- 预期结果:当前日期的天数部分 +SELECT DAY(CURRENT_STAMP) AS DayPart; -- 预期结果:当前日期的天数部分 + + +-- 异常测试 +SELECT DAY(CURRENT_TIME) AS DayPart; +SELECT DAY('20:12:12') AS DayPart; +SELECT DAY(NULL) AS DayPart; +SELECT DAY(12345) AS DayPart; +SELECT DAY('abc') AS DayPart; + +SELECT DAY('2023-13-01') AS DayPart; +SELECT DAY('2023-02-30') AS DayPart; +SELECT DAY('2023-04-31') AS DayPart; +SELECT DAY('2023-00-01') AS DayPart; +SELECT DAY('2023-01-00') AS DayPart; + + diff --git a/contrib/shark/sql/objectproperty.sql b/contrib/shark/sql/objectproperty.sql new file mode 100644 index 0000000000..cb98d571f2 --- /dev/null +++ b/contrib/shark/sql/objectproperty.sql @@ -0,0 +1,205 @@ +CREATE TABLE sys.students ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + age INT, + grade DECIMAL(5, 2) +); + +CREATE VIEW sys.student_grades AS +SELECT name, grade +FROM students; + +CREATE OR REPLACE FUNCTION sys.calculate_total_grade() +RETURNS DECIMAL(10, 2) AS $$ +DECLARE + total_grade DECIMAL(10, 2) := 0; +BEGIN + SELECT SUM(grade) INTO total_grade FROM students; + RETURN total_grade; +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE PROCEDURE sys.insert_student( + student_name VARCHAR(100), + student_age INT, + student_grade DECIMAL(5, 2) +) AS +BEGIN + INSERT INTO students (name, age, grade) VALUES (student_name, student_age, student_grade); +END; +/ + +CREATE OR REPLACE FUNCTION sys.update_total_grade() +RETURNS TRIGGER AS $$ +BEGIN + RAISE NOTICE 'Total grade updated: %', calculate_total_grade(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_update_total_grade +AFTER INSERT OR UPDATE OR DELETE ON students +FOR EACH STATEMENT EXECUTE PROCEDURE update_total_grade(); + +select object_id('sys.students'); +select object_id('sys.students_pkey'); +select object_id('sys.student_grades'); +select object_id('sys.calculate_total_grade'); +select object_id('sys.insert_student'); +select object_id('sys.trigger_update_total_grade'); + +set search_path = 'sys'; + +select object_id('students', 'U'); +select object_id('students_pkey', 'PK'); +select object_id('student_grades', 'V'); +select object_id('calculate_total_grade', 'FN'); +select object_id('insert_student', 'P'); +select object_id('trigger_update_total_grade', 'TR'); + +select object_id('sys.students'); +select object_id('contrib_regression.sys.students'); + +select objectproperty(object_id('students'), 'istable') as istable; +select objectproperty(object_id('students'), 'ownerid') as ownerid; +select objectproperty(object_id('students'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('students'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('students'), 'isschemabound') as isschemabound; +select objectproperty(object_id('students'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('students'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('students'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('students'), 'issysshipped') as issysshipped; +select objectproperty(object_id('students'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('students'), 'isprocedure') asisprocedure; +select objectproperty(object_id('students'), 'isview') as isview; +select objectproperty(object_id('students'), 'isusertable') as isusertable; +select objectproperty(object_id('students'), 'istablefunction') as istablefunction; +select objectproperty(object_id('students'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('students'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('students'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('students'), 'isindexed') as isindexed; +select objectproperty(object_id('students'), 'isdefault') as isdefault; +select objectproperty(object_id('students'), 'isrule') as isrule; +select objectproperty(object_id('students'), 'istrigger') as istrigger; + +select objectproperty(object_id('student_grades'), 'istable') as istable; +select objectproperty(object_id('student_grades'), 'ownerid') as ownerid; +select objectproperty(object_id('student_grades'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('student_grades'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('student_grades'), 'isschemabound') as isschemabound; +select objectproperty(object_id('student_grades'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('student_grades'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('student_grades'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('student_grades'), 'issysshipped') as issysshipped; +select objectproperty(object_id('student_grades'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('student_grades'), 'isprocedure') asisprocedure; +select objectproperty(object_id('student_grades'), 'isview') as isview; +select objectproperty(object_id('student_grades'), 'isusertable') as isusertable; +select objectproperty(object_id('student_grades'), 'istablefunction') as istablefunction; +select objectproperty(object_id('student_grades'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('student_grades'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('student_grades'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('student_grades'), 'isindexed') as isindexed; +select objectproperty(object_id('student_grades'), 'isdefault') as isdefault; +select objectproperty(object_id('student_grades'), 'isrule') as isrule; +select objectproperty(object_id('student_grades'), 'istrigger') as istrigger; + +select objectproperty(object_id('calculate_total_grade'), 'istable') as istable; +select objectproperty(object_id('calculate_total_grade'), 'ownerid') as ownerid; +select objectproperty(object_id('calculate_total_grade'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('calculate_total_grade'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('calculate_total_grade'), 'isschemabound') as isschemabound; +select objectproperty(object_id('calculate_total_grade'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('calculate_total_grade'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('calculate_total_grade'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('calculate_total_grade'), 'issysshipped') as issysshipped; +select objectproperty(object_id('calculate_total_grade'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('calculate_total_grade'), 'isprocedure') asisprocedure; +select objectproperty(object_id('calculate_total_grade'), 'isview') as isview; +select objectproperty(object_id('calculate_total_grade'), 'isusertable') as isusertable; +select objectproperty(object_id('calculate_total_grade'), 'istablefunction') as istablefunction; +select objectproperty(object_id('calculate_total_grade'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('calculate_total_grade'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('calculate_total_grade'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('calculate_total_grade'), 'isindexed') as isindexed; +select objectproperty(object_id('calculate_total_grade'), 'isdefault') as isdefault; +select objectproperty(object_id('calculate_total_grade'), 'isrule') as isrule; +select objectproperty(object_id('calculate_total_grade'), 'istrigger') as istrigger; + +select objectproperty(object_id('insert_student'), 'istable') as istable; +select objectproperty(object_id('insert_student'), 'ownerid') as ownerid; +select objectproperty(object_id('insert_student'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('insert_student'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('insert_student'), 'isschemabound') as isschemabound; +select objectproperty(object_id('insert_student'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('insert_student'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('insert_student'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('insert_student'), 'issysshipped') as issysshipped; +select objectproperty(object_id('insert_student'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('insert_student'), 'isprocedure') asisprocedure; +select objectproperty(object_id('insert_student'), 'isview') as isview; +select objectproperty(object_id('insert_student'), 'isusertable') as isusertable; +select objectproperty(object_id('insert_student'), 'istablefunction') as istablefunction; +select objectproperty(object_id('insert_student'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('insert_student'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('insert_student'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('insert_student'), 'isindexed') as isindexed; +select objectproperty(object_id('insert_student'), 'isdefault') as isdefault; +select objectproperty(object_id('insert_student'), 'isrule') as isrule; +select objectproperty(object_id('insert_student'), 'istrigger') as istrigger; + +select objectproperty(object_id('trigger_update_total_grade'), 'istable') as istable; +select objectproperty(object_id('trigger_update_total_grade'), 'ownerid') as ownerid; +select objectproperty(object_id('trigger_update_total_grade'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('trigger_update_total_grade'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('trigger_update_total_grade'), 'isschemabound') as isschemabound; +select objectproperty(object_id('trigger_update_total_grade'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('trigger_update_total_grade'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('trigger_update_total_grade'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('trigger_update_total_grade'), 'issysshipped') as issysshipped; +select objectproperty(object_id('trigger_update_total_grade'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('trigger_update_total_grade'), 'isprocedure') asisprocedure; +select objectproperty(object_id('trigger_update_total_grade'), 'isview') as isview; +select objectproperty(object_id('trigger_update_total_grade'), 'isusertable') as isusertable; +select objectproperty(object_id('trigger_update_total_grade'), 'istablefunction') as istablefunction; +select objectproperty(object_id('trigger_update_total_grade'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('trigger_update_total_grade'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('trigger_update_total_grade'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('trigger_update_total_grade'), 'isindexed') as isindexed; +select objectproperty(object_id('trigger_update_total_grade'), 'isdefault') as isdefault; +select objectproperty(object_id('trigger_update_total_grade'), 'isrule') as isrule; +select objectproperty(object_id('trigger_update_total_grade'), 'istrigger') as istrigger; + +--异常用例 +CREATE TEMP TABLE sys.temp_sales ( + product_name VARCHAR(255), + sale_amount NUMERIC(10, 2), + sale_date DATE +); +select object_id('temp_sales'); +select objectproperty(object_id('temp_sales'), 'istable') as istable; + +select object_id(); +select object_id('[]'); +select object_id('student'); +select object_id('', 'U'); +select object_id('students', ''); +select object_id('students', 'FN'); +select object_id('othersys.students'); +select object_id('otherdb.sys.students'); + +select objectproperty('', 'istable') as istable; +select objectproperty('students', 'istable') as istable; +select objectproperty(object_id('students'), '') as istable; +select objectproperty('', '') as istable; +select objectproperty(object_id('student'), 'istable') as istable; +select objectproperty(object_id('students'), 'isview') as istable; +select objectproperty(object_id('students'), 'ssr') as istable; + +create user object_user identified by 'Test@123'; +SET SESSION AUTHORIZATION object_user PASSWORD 'Test@123'; +create schema object_schema; +create table object_schema.t1 (n1 int); + +RESET SESSION AUTHORIZATION; +select object_id('object_schema.t1'); diff --git a/contrib/shark/sql/rand_test.sql b/contrib/shark/sql/rand_test.sql new file mode 100644 index 0000000000..c317b1b181 --- /dev/null +++ b/contrib/shark/sql/rand_test.sql @@ -0,0 +1,28 @@ + +DO $$ +DECLARE + counter SMALLINT := 1; +BEGIN + WHILE counter < 5 LOOP + RAISE NOTICE '%', RAND(); + counter := counter + 1; + END LOOP; +END $$; + +SELECT rand(1); +SELECT rand(-1); +SELECT rand(1::SMALLINT); +SELECT rand(-1::SMALLINT); +SELECT rand(1::tinyint); +SELECT rand(-1::tinyint); + +drop table if exists t1; +create table t1(a1 int); +insert into t1 values(floor((100 + RAND() * 100))); +select * from t1; + +select RAND(null); +select RAND(2147483647); +select RAND(2147483648); +select RAND(-2147483648); +select RAND(-2147483649); \ No newline at end of file diff --git a/contrib/shark/varlena.cpp b/contrib/shark/varlena.cpp new file mode 100644 index 0000000000..f5daaa580f --- /dev/null +++ b/contrib/shark/varlena.cpp @@ -0,0 +1,1184 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * -------------------------------------------------------------------------------------- + * + * varlena.c + * Functions in common use. + * + * IDENTIFICATION + * contrib/shark/varlena.c + * + * -------------------------------------------------------------------------------------- + */ +#include "knl/knl_variable.h" + +#include "postgres.h" +#include "miscadmin.h" +#include "knl/knl_instance.h" +#include +#include + +#include "knl/knl_variable.h" +#include "commands/extension.h" +#include "commands/dbcommands.h" +#include "nodes/execnodes.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/fmgroids.h" +#include "parser/scansup.h" +#include "tcop/ddldeparse.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_attrdef.h" +#include "catalog/indexing.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_trigger.h" + +typedef enum +{ + OBJECT_TYPE_AGGREGATE_FUNCTION = 1, + OBJECT_TYPE_CHECK_CONSTRAINT, + OBJECT_TYPE_DEFAULT_CONSTRAINT, + OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT, + OBJECT_TYPE_TSQL_SCALAR_FUNCTION, + OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION, + OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_INTERNAL_TABLE, + OBJECT_TYPE_TSQL_STORED_PROCEDURE, + OBJECT_TYPE_ASSEMBLY_STORED_PROCEDURE, + OBJECT_TYPE_PLAN_GUIDE, + OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT, + OBJECT_TYPE_RULE, + OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE, + OBJECT_TYPE_SYSTEM_BASE_TABLE, + OBJECT_TYPE_SYNONYM, + OBJECT_TYPE_SEQUENCE_OBJECT, + OBJECT_TYPE_SERVICE_QUEUE, + OBJECT_TYPE_ASSEMBLY_DML_TRIGGER, + OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_TSQL_DML_TRIGGER, + OBJECT_TYPE_TABLE_TYPE, + OBJECT_TYPE_TABLE, + OBJECT_TYPE_UNIQUE_CONSTRAINT, + OBJECT_TYPE_VIEW, + OBJECT_TYPE_MATERIALIZED_VIEW, + OBJECT_TYPE_EXTENDED_STORED_PROCEDURE +} PropertyType; + +Oid tsql_get_proc_nsp_oid(Oid object_id); +Oid tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id); + +static char* get_physical_schema_name(char *db_name, const char *schema_name); +static bool is_shared_schema(const char *name); +static char* get_current_physical_schema_name(char* schema_name); +static Oid search_oid_in_proc(char* obj_name, Oid schema_oid); +static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid); +static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type); +static int search_type_in_class(Oid* schema_id, Oid object_id, char* object_name); +static int search_type_in_proc(Oid* schema_id, Oid object_id, char* object_name); +static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name); +static int search_type_in_cons(Oid* schema_id, Oid object_id, char* object_name); +static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_name); +static int dealwith_property(int type, Oid schema_id, Oid object_id, char* property); +static inline Oid search_oid_in_nsp(int cacheId, char* obj_name, Oid schema_oid); +static inline int dealwith_type_ownerid(int type, Oid schema_id); +static inline int dealwith_type_defcnst(int type); +static inline int dealwith_type_exec_bound(int type, char* property); +static inline int dealwith_type_status_format(int type); +static inline int dealwith_type_issysshipped(int type, Oid schema_id); +static inline int dealwith_type_dete(int type, Oid object_id); +static inline int dealwith_type_procedure(int type); +static inline int dealwith_type_table(int type); +static inline int dealwith_type_view(int type); +static inline int dealwith_type_usertable(int type, Oid schema_id); +static inline int dealwith_type_tablefunc(int type); +static inline int dealwith_type_inlinefunc(int type); +static inline int dealwith_type_scalarfunc(int type); +static inline int dealwith_type_pk(int type); +static inline int dealwith_type_indexed(int type, Oid object_id); +static inline int dealwith_type_trigger(int type); + + +static Oid search_oid_in_proc(char* obj_name, Oid schema_oid) +{ + Oid id = InvalidOid; + CatCList* catlist = NULL; + HeapTuple tuple; + Form_pg_proc procform; +#ifndef ENABLE_MULTIPLE_NODES + if (t_thrd.proc->workingVersionNum < 92470) { + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(obj_name)); + } else { + catlist = SearchSysCacheList1(PROCALLARGS, CStringGetDatum(obj_name)); + } +#else + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(obj_name)); +#endif + + for (int i = 0; i < catlist->n_members; i++) { + tuple = t_thrd.lsc_cxt.FetchTupleFromCatCList(catlist, i); + procform = (Form_pg_proc)GETSTRUCT(tuple); + if (procform->pronamespace != schema_oid) { + continue; + } + id = HeapTupleGetOid(tuple); + break; + } + ReleaseSysCacheList(catlist); + return id; +} + +static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid) +{ + Oid id = InvalidOid; + Relation tgrel; + ScanKeyData keys[1]; + SysScanDesc tgscan; + HeapTuple tuple; + + ScanKeyInit(&keys[0], Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(obj_name)); + + tgrel = heap_open(TriggerRelationId, AccessShareLock); + tgscan = systable_beginscan(tgrel, TriggerNameIndexId, true, SnapshotNow, 1, keys); + if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { + id = HeapTupleGetOid(tuple); + } + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + return id; +} + +static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type) +{ + Oid schema_oid = InvalidOid; + if (schema_name != NULL && strlen(schema_name) > 0) + { + schema_oid = get_namespace_oid(schema_name, true); + if (!OidIsValid(schema_oid)) + return InvalidOid; + if (!pg_namespace_ownercheck(schema_oid, GetUserId())) + { + ereport(NOTICE, + (errmsg("Permission denied for schema %s", schema_name))); + return InvalidOid; + } + } else { + char *token, *saveptr; + char* search_path = pstrdup(u_sess->attr.attr_common.namespace_search_path); + token = strtok_r(search_path, ",", &saveptr); + if (strcmp(token, "\"$user\"") == 0) { + token = strtok_r(NULL, ",", &saveptr); + } + schema_oid = SchemaNameGetSchemaOid(token, false); + } + + Oid id = InvalidOid; + if (object_type != NULL && strlen(object_type) > 0) + { + char* type_name = pg_strtoupper(object_type); + if (strcmp(type_name, "S") == 0 || strcmp(type_name, "U") == 0 || strcmp(type_name, "V") == 0 || + strcmp(type_name, "SO") == 0) + { + id = search_oid_in_nsp(RELNAMENSP, obj_name, schema_oid); + } else if (strcmp(type_name, "C") == 0 || strcmp(type_name, "D") == 0 || strcmp(type_name, "F") == 0 || + strcmp(type_name, "PK") == 0 || strcmp(type_name, "UQ") == 0) { + id = search_oid_in_nsp(CONNAMENSP, obj_name, schema_oid); + } else if (strcmp(type_name, "AF") == 0 || strcmp(type_name, "FN") == 0 || + strcmp(type_name, "P") == 0 || strcmp(type_name, "PC") == 0) { + id = search_oid_in_proc(obj_name, schema_oid); + } else if (strcmp(type_name, "TR") == 0) { + id = search_oid_in_trigger(obj_name, schema_oid); + } else { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported object type"))); + } + } else { + if (id == InvalidOid) { + id = search_oid_in_nsp(RELNAMENSP, obj_name, schema_oid); + } + if (id == InvalidOid) { + id = search_oid_in_nsp(CONNAMENSP, obj_name, schema_oid); + } + if (id == InvalidOid) { + id = search_oid_in_proc(obj_name, schema_oid); + } + if (id == InvalidOid) { + id = search_oid_in_trigger(obj_name, schema_oid); + } + } + return id; +} + +static int search_type_in_class(Oid* schema_id, Oid object_id, char* object_name) +{ + int type; + HeapTuple tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_class pg_class = (Form_pg_class) GETSTRUCT(tuple); + + object_name = NameStr(pg_class->relname); + + if (pg_class_aclcheck(object_id, GetUserId(), ACL_SELECT) == ACLCHECK_OK) + *schema_id = get_rel_namespace(object_id); + + /* + * Get the type of the object + */ + if ((pg_class->relpersistence == 'p' || pg_class->relpersistence == 'u' || pg_class->relpersistence == 't' || + pg_class->relpersistence == 'g') && (pg_class->relkind == 'r')) + { + /* + * Check whether it is a Table type (TT) object. + * The reltype of the pg_class object should be there in pg_type. The pg_type object found + * should be of composite type (c) and the type of dependency should be DEPENDENCY_INTERNAL (i). + * We scan pg_depend catalog to find the type of the dependency. + */ + HeapTuple tp; + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(pg_class->reltype)); + if(HeapTupleIsValid(tp)) + { + Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp); + + if (typform->typtype == 'c') + { + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(typform->typrelid)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(HeapTupleGetOid(tp))); + + scan = systable_beginscan(depRel, InvalidOid, false, + NULL, 2, key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->deptype == 'i') + type = OBJECT_TYPE_TABLE_TYPE; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + } + ReleaseSysCache(tp); + } + /* + * If the object is not of Table type (TT), it should be user defined table (U) + */ + if (type == 0 || type != OBJECT_TYPE_TABLE_TYPE) + type = OBJECT_TYPE_TABLE; + } + else if (pg_class->relkind == 'v') + type = OBJECT_TYPE_VIEW; + else if (pg_class->relkind == 'm') + type = OBJECT_TYPE_MATERIALIZED_VIEW; + else if (pg_class->relkind == 's') + type = OBJECT_TYPE_SEQUENCE_OBJECT; + + ReleaseSysCache(tuple); + } + return type; +} + +static int search_type_in_proc(Oid* schema_id, Oid object_id, char* object_name) +{ + int type; + HeapTuple tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + if (pg_proc_aclcheck(object_id, GetUserId(), ACL_EXECUTE) == ACLCHECK_OK) + { + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple); + + object_name = NameStr(procform->proname); + + *schema_id = tsql_get_proc_nsp_oid(object_id); + + char prokind = get_func_prokind(HeapTupleGetOid(tuple)); + if (prokind == 'p') + type = OBJECT_TYPE_TSQL_STORED_PROCEDURE; + else if (prokind == 'a') + type = OBJECT_TYPE_AGGREGATE_FUNCTION; + else + { + /* + * Check whether the object is SQL DML trigger(TR), SQL table-valued-function (TF), + * SQL inline table-valued function (IF), SQL scalar function (FN). + */ + char *temp = format_type_with_typemod(procform->prorettype, -1); + /* + * If the prorettype of the pg_proc object is "trigger", then the type of the object is "TR" + */ + if (pg_strcasecmp(temp, "trigger") == 0) + type = OBJECT_TYPE_TSQL_DML_TRIGGER; + /* + * For SQL table-valued-functions and SQL inline table-valued functions, re-implement the existing SQL. + */ + else if (procform->proretset) + { + HeapTuple tp; + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procform->prorettype)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typeform = (Form_pg_type) GETSTRUCT(tuple); + + if (typeform->typtype == 'c') + type = OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION; + else + type = OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION; + + ReleaseSysCache(tp); + } + } + else + type = OBJECT_TYPE_TSQL_SCALAR_FUNCTION; + + pfree_ext(temp); + } + } + ReleaseSysCache(tuple); + } + return type; +} + +static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name) +{ + Relation attrdefrel; + ScanKeyData key; + SysScanDesc attrscan; + int type; + + attrdefrel = table_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&key, + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object_id)); + + attrscan = systable_beginscan(attrdefrel, AttrDefaultOidIndexId, false, + NULL, 1, &key); + + HeapTuple tuple = systable_getnext(attrscan); + if (HeapTupleIsValid(tuple)) + { + /* + * scan pg_attribute catalog to find the corresponding row. + * This pg_attribute pbject will be helpful to check whether the object is DEFAULT (D) + * and to find the schema_id. + */ + Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tuple); + Relation attrRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + Oid user_id = GetUserId(); + if (pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_SELECT) && + pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_INSERT) && + pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_UPDATE) && + pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_REFERENCES)) + { + attrRel = table_open(AttributeRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(atdform->adrelid)); + ScanKeyInit(&key[1], + Anum_pg_attribute_attnum, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(atdform->adnum)); + + scan = systable_beginscan(attrRel, AttributeRelidNumIndexId, true, + NULL, 2, key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_attribute attrform = (Form_pg_attribute) GETSTRUCT(tup); + + if (attrform->atthasdef && !atdform->adgencol) + { + object_name = NameStr(attrform->attname); + type = OBJECT_TYPE_DEFAULT_CONSTRAINT; + if (pg_class_aclcheck(atdform->adrelid, user_id, ACL_SELECT) == ACLCHECK_OK) + *schema_id = get_rel_namespace(atdform->adrelid); + } + } + + systable_endscan(scan); + + table_close(attrRel, RowExclusiveLock); + } + + } + systable_endscan(attrscan); + table_close(attrdefrel, AccessShareLock); + return type; +} + +static int search_type_in_cons(Oid* schema_id, Oid object_id, char* object_name) +{ + int type; + HeapTuple tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + object_name = NameStr(con->conname); + *schema_id = tsql_get_constraint_nsp_oid(object_id, GetUserId()); + /* + * If the contype is 'f' on the pg_constraint object, then it is a Foreign key constraint + */ + if (con->contype == 'f') + type = OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT; + /* + * If the contype is 'p' on the pg_constraint object, then it is a Primary key constraint + */ + else if (con->contype == 'p') + type = OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT; + /* + * Reimplemented the existing SQL . + * If the contype is 'c' and conrelid is 0 on the pg_constraint object, then it is a Check constraint + */ + else if (con->contype == 'c' && con->conrelid != 0) + type = OBJECT_TYPE_CHECK_CONSTRAINT; + + ReleaseSysCache(tuple); + } + return type; +} + +static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_name) +{ + Relation trigDesc; + HeapTuple tup; + Form_pg_trigger trig; + int type; + + trigDesc = table_open(TriggerRelationId, AccessShareLock); + tup = get_catalog_object_by_oid(trigDesc, object_id); + if (HeapTupleIsValid(tup)) { + trig = (Form_pg_trigger) GETSTRUCT(tup); + object_name = NameStr(trig->tgname); + *schema_id = get_rel_namespace(trig->tgrelid); + type = OBJECT_TYPE_ASSEMBLY_DML_TRIGGER; + } + + table_close(trigDesc, AccessShareLock); + return type; +} + +static inline Oid search_oid_in_nsp(int cache_id, char* obj_name, Oid schema_oid) +{ + Oid id = InvalidOid; + HeapTuple relTuple = SearchSysCache2(cache_id, PointerGetDatum(obj_name), ObjectIdGetDatum(schema_oid)); + if (HeapTupleIsValid(relTuple)) { + id = HeapTupleGetOid(relTuple); + ReleaseSysCache(relTuple); + } + return id; +} + +extern "C" Datum rand_seed(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(rand_seed); +Datum rand_seed(PG_FUNCTION_ARGS) +{ + int64 n = PG_GETARG_INT64(0); + + gs_srandom((unsigned int)n); + float8 result; + /* result [0.0 - 1.0) */ + result = (double)gs_random() / ((double)MAX_RANDOM_VALUE + 1); + + PG_RETURN_FLOAT8(result); +} + +extern "C" Datum object_id_internal(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(object_id_internal); +Datum +object_id_internal(PG_FUNCTION_ARGS) +{ + if (PG_ARGISNULL(0)) { + PG_RETURN_NULL(); + } + char *object_name = text_to_cstring(PG_GETARG_TEXT_P(0)); + char *object_type = text_to_cstring(PG_GETARG_TEXT_P(1)); + + if (strlen(object_name) < 1) { + PG_RETURN_NULL(); + } + + List* nameList = stringToQualifiedNameList(object_name); + + char* db_name = NULL; + char* schema_name = NULL; + char* obj_name = NULL; + switch (list_length(nameList)) + { + case 1: + obj_name = strVal(linitial(nameList)); + break; + case 2: + obj_name = strVal(lsecond(nameList)); + schema_name = get_current_physical_schema_name(strVal(linitial(nameList))); + break; + case 3: + obj_name = strVal(lthird(nameList)); + schema_name = get_current_physical_schema_name(strVal(lsecond(nameList))); + db_name = strVal(linitial(nameList)); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper qualified name (too many dotted names): %s", NameListToString(nameList)))); + break; + } + + if (obj_name == NULL || strlen(obj_name) < 1) { + PG_RETURN_NULL(); + } + + if (db_name != NULL && db_name != get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true)) { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("Can only do lookup in current database."))); + } + Oid id = search_oid_in_schema(schema_name, obj_name, object_type); + if (id == InvalidOid) { + PG_RETURN_NULL(); + } + PG_RETURN_OID(id); +} + +extern "C" Datum objectproperty_internal(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(objectproperty_internal); +Datum +objectproperty_internal(PG_FUNCTION_ARGS) +{ + Oid object_id; + Oid schema_id = InvalidOid; + char *property; + Oid user_id = GetUserId(); + int type = 0; + char *object_name = NULL; + char *nspname = NULL; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + else + { + object_id = (Oid) PG_GETARG_INT32(0); + property = text_to_cstring(PG_GETARG_TEXT_P(1)); + if (strlen(property) < 1 || object_id == InvalidOid) { + PG_RETURN_NULL(); + } + property = downcase_truncate_identifier(property, strlen(property), true); + property = remove_trailing_spaces(property); + } + + /* + * Search for the object_id in pg_class, pg_proc, pg_attrdef, pg_constraint. + * If the object_id is not found in any of the above catalogs, return NULL. + * Else, get the object name, type of the object and the schema_id in which + * the object is present. + */ + + /* pg_class */ + type = search_type_in_class(&schema_id, object_id, object_name); + /* pg_proc */ + if (!schema_id) + { + type = search_type_in_proc(&schema_id, object_id, object_name); + } + /* pg_attrdef */ + if (!schema_id) + { + type = search_type_in_attr(&schema_id, object_id, object_name); + } + /* pg_constraint */ + if (!schema_id) + { + type = search_type_in_cons(&schema_id, object_id, object_name); + } + /* pg_trigger */ + if (!schema_id) + { + type = search_type_in_trigger(&schema_id, object_id, object_name); + } + + /* + * If the object_id is not found or user does not have enough privileges on the object and schema, + * Return NULL. + */ + if (!schema_id || !pg_namespace_ownercheck(schema_id, user_id)) + { + pfree_ext(property); + PG_RETURN_NULL(); + } + + /* + * schema_id found should be in sys.schemas view except 'sys'. + */ + nspname = get_namespace_name(schema_id); + + if (!(nspname && pg_strcasecmp(nspname, "sys") == 0) && + (!nspname || pg_strcasecmp(nspname, "pg_catalog") == 0 || + pg_strcasecmp(nspname, "pg_toast") == 0 || + pg_strcasecmp(nspname, "public") == 0)) + { + pfree_ext(property); + if (nspname) + pfree_ext(nspname); + + PG_RETURN_NULL(); + } + + pfree_ext(nspname); + + int result = dealwith_property(type, schema_id, object_id, property); + + if (property) + pfree_ext(property); + if (result == -1) { + PG_RETURN_NULL(); + } else { + PG_RETURN_INT32(result); + } +} + +static int dealwith_property(int type, Oid schema_id, Oid object_id, char* property) +{ + int result = -1; + /* OwnerId */ + if (pg_strcasecmp(property, "ownerid") == 0) + { + result = dealwith_type_ownerid(type, schema_id); + } + /* IsDefaultCnst */ + else if (pg_strcasecmp(property, "isdefaultcnst") == 0) + { + result = dealwith_type_defcnst(type); + } + /* ExecIsQuotedIdentOn, IsSchemaBound, ExecIsAnsiNullsOn */ + else if (pg_strcasecmp(property, "execisquotedidenton") == 0 || + pg_strcasecmp(property, "isschemabound") == 0 || + pg_strcasecmp(property, "execisansinullson") == 0) + { + result = dealwith_type_exec_bound(type, property); + + } + /* TableFullTextPopulateStatus, TableHasVarDecimalStorageFormat */ + else if (pg_strcasecmp(property, "tablefulltextpopulatestatus") == 0 || + pg_strcasecmp(property, "tablehasvardecimalstorageformat") == 0) + { + result = dealwith_type_status_format(type); + } + /* IsSYSShipped*/ + else if (pg_strcasecmp(property, "issysshipped") == 0) + { + result = dealwith_type_issysshipped(type, schema_id); + } + /* IsDeterministic */ + else if (pg_strcasecmp(property, "isdeterministic") == 0) + { + result = dealwith_type_dete(type, object_id); + } + /* IsProcedure */ + else if (pg_strcasecmp(property, "isprocedure") == 0) + { + result = dealwith_type_procedure(type); + } + /* IsTable */ + else if (pg_strcasecmp(property, "istable") == 0) + { + result = dealwith_type_table(type); + } + /* IsView */ + else if (pg_strcasecmp(property, "isview") == 0) + { + result = dealwith_type_view(type); + } + /* IsUserView */ + else if (pg_strcasecmp(property, "isusertable") == 0) + { + result = dealwith_type_usertable(type, schema_id); + } + /* IsTableFunction */ + else if (pg_strcasecmp(property, "istablefunction") == 0) + { + result = dealwith_type_tablefunc(type); + } + /* IsInlineFunction */ + else if (pg_strcasecmp(property, "isinlinefunction") == 0) + { + result = dealwith_type_inlinefunc(type); + } + /* IsScalarFunction */ + else if (pg_strcasecmp(property, "isscalarfunction") == 0) + { + result = dealwith_type_scalarfunc(type); + } + /* IsPrimaryKey */ + else if (pg_strcasecmp(property, "isprimarykey") == 0) + { + result = dealwith_type_pk(type); + } + /* IsIndexed */ + else if (pg_strcasecmp(property, "isindexed") == 0) + { + result = dealwith_type_indexed(type, object_id); + } + /* IsDefault */ + else if (pg_strcasecmp(property, "isdefault") == 0) + { + /* + * Currently hardcoded to 0. + */ + return 0; + } + /* IsOBJECT_TYPE_RULE */ + else if (pg_strcasecmp(property, "isrule") == 0) + { + /* + * Currently hardcoded to 0. + */ + return 0; + } + /* IsTrigger */ + else if (pg_strcasecmp(property, "istrigger") == 0) + { + result = dealwith_type_trigger(type); + } + return result; +} + +static bool is_shared_schema(const char *name) +{ + if (strcmp("sys", name) == 0) + return true; /* D_FORMAT shared schema */ + else if ((strcmp("public", name) == 0) + || (strcmp("pg_catalog", name) == 0) + || (strcmp("pg_toast", name) == 0) + || (strcmp("information_schema", name) == 0)) + return true; + else + return false; +} + + +static char* get_physical_schema_name(char *db_name, const char *schema_name) +{ + char *name; + int len; + errno_t errorno = EOK; + + if (!schema_name) + return NULL; + + len = strlen(schema_name); + if (len == 0) + return NULL; + + if ((get_database_oid(db_name, true)) == InvalidOid) { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist. Make sure that the name is entered correctly.", db_name))); + } + + if (len >= NAMEDATALEN ) { + ereport(ERROR, + (errcode(ERRCODE_NAME_TOO_LONG), + errmsg("type name too long"), + errdetail("schema name should be less the %d letters.", + NAMEDATALEN))); + u_sess->plsql_cxt.have_error = true; + } + name = (char*)palloc0(len + 1); + errorno = strncpy_s(name, len + 1, schema_name, len); + securec_check(errorno, "\0", "\0"); + + if (is_shared_schema(name)) + { + return name; + } + + /* + * Parser guarantees identifier will always be truncated to 64B. Schema + * name that comes from other source (e.g scheam_id function) needs one + * more truncate function call + */ + truncate_identifier(name, strlen(name), false); + + /* all schema names are not prepended with db name on single-db */ + return name; +} + +/* + * tsql_get_proc_nsp_oid + * Given Oid of pg_proc entry return namespace_oid + * Returns InvalidOid if Oid is not found + */ +Oid +tsql_get_proc_nsp_oid(Oid object_id) +{ + Oid namespace_oid = InvalidOid; + HeapTuple tuple; + bool isnull; + + /* retrieve pronamespace in pg_proc by oid */ + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id)); + + if (HeapTupleIsValid(tuple)) + { + (void) SysCacheGetAttr(PROCOID, tuple, + Anum_pg_proc_pronamespace, + &isnull); + if (!isnull) + { + Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tuple); + + namespace_oid = proc->pronamespace; + } + ReleaseSysCache(tuple); + } + return namespace_oid; +} + +/* + * tsql_get_constraint_nsp_oid + * Given Oid of pg_constraint entry return namespace_oid + * Returns InvalidOid if Oid is not found + */ +Oid +tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id) +{ + + Oid namespace_oid = InvalidOid; + HeapTuple tuple; + bool isnull; + + /* retrieve connamespace in pg_constraint by oid */ + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id)); + + if (HeapTupleIsValid(tuple)) + { + (void) SysCacheGetAttr(CONSTROID, tuple, + Anum_pg_constraint_connamespace, + &isnull); + if (!isnull) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + + if (OidIsValid(HeapTupleGetOid(tuple))) + { + /* + * user should have permission of table associated with + * constraint + */ + if (OidIsValid(con->conrelid)) + { + if (pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK) + namespace_oid = con->connamespace; + } + } + } + ReleaseSysCache(tuple); + } + return namespace_oid; +} + +static char* get_current_physical_schema_name(char* schema_name) +{ + char *cur_db_name; + char *ret; + + if (strlen(schema_name) < 1) + return NULL; + + cur_db_name = get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true); + ret = get_physical_schema_name(cur_db_name, schema_name); + + return ret; +} + +static inline int dealwith_type_ownerid(int type, Oid schema_id) +{ + /* + * Search for schema_id in pg_namespace catalog. Return nspowner from + * the found pg_namespace object. + */ + if (OidIsValid(schema_id)) { + HeapTuple tp; + int result; + + tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(schema_id)); + if (HeapTupleIsValid(tp)) { + Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp); + result = ((int) nsptup->nspowner); + ReleaseSysCache(tp); + return result; + } + } + return -1; +} + +static inline int dealwith_type_defcnst(int type) +{ + /* + * The type of the object should be OBJECT_TYPE_DEFAULT_CONSTRAINT. + */ + if (type == OBJECT_TYPE_DEFAULT_CONSTRAINT) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_exec_bound(int type, char* property) +{ + /* + * These properties are only applicable to OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE, + * OBJECT_TYPE_VIEW, OBJECT_TYPE_TSQL_DML_TRIGGER, OBJECT_TYPE_TSQL_SCALAR_FUNCTION, OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION, + * OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION and OBJECT_TYPE_RULE. + * Hence, return NULL if the object is not from the above types. + */ + if (!(type == OBJECT_TYPE_TSQL_STORED_PROCEDURE || type == OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE || + type == OBJECT_TYPE_VIEW || type == OBJECT_TYPE_TSQL_DML_TRIGGER || type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || + type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION || + type == OBJECT_TYPE_RULE)) + { + return -1; + } + + /* + * Currently, for IsSchemaBound property, we have hardcoded the value to 0 + */ + if (pg_strcasecmp(property, "isschemabound") == 0) + { + return 0; + } + /* + * For ExecIsQuotedIdentOn and ExecIsAnsiNullsOn, we hardcoded it to 1 + */ + return 1; +} + +static inline int dealwith_type_status_format(int type) +{ + /* + * Currently, we have hardcoded the return value to 0. + */ + if (type == OBJECT_TYPE_TABLE) + { + return 0; + } + /* + * These properties are only applicable if the type of the object is TABLE, + * Hence, return NULL if the object is not a TABLE. + */ + return -1; +} + +static inline int dealwith_type_issysshipped(int type, Oid schema_id) +{ + /* + * Check whether the object is MS shipped. We are using is_ms_shipped helper function + * to check the same. + */ + char* schema_name = get_namespace_name(schema_id); + if (pg_strcasecmp(schema_name, "sys") == 0) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_dete(int type, Oid object_id) +{ + int result; + if (type == OBJECT_TYPE_AGGREGATE_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION || + type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION || + type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION){ + HeapTuple tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)){ + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple); + result = procform->provolatile == 'i' ? 1 : 0; + + ReleaseSysCache(tuple); + return result; + } + } + return -1; +} + +static inline int dealwith_type_procedure(int type) +{ + /* + * Check whether the type of the object is OBJECT_TYPE_TSQL_STORED_PROCEDURE. + */ + if (type == OBJECT_TYPE_TSQL_STORED_PROCEDURE) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_table(int type) +{ + /* + * The type of the object should be OBJECT_TYPE_INTERNAL_TABLE or OBJECT_TYPE_TABLE_TYPE or + * TABLE or OBJECT_TYPE_SYSTEM_BASE_TABLE. + */ + if (type == OBJECT_TYPE_INTERNAL_TABLE || type == OBJECT_TYPE_TABLE_TYPE || + type == OBJECT_TYPE_TABLE || type == OBJECT_TYPE_SYSTEM_BASE_TABLE) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_view(int type) +{ + /* + * The type of the object should be OBJECT_TYPE_VIEW. + */ + if (type == OBJECT_TYPE_VIEW) + { + PG_RETURN_INT32(1); + } + PG_RETURN_INT32(0); +} + +static inline int dealwith_type_usertable(int type, Oid schema_id) +{ + /* + * The object should be of the type TABLE. + */ + char* schema_name = get_namespace_name(schema_id); + if (type == OBJECT_TYPE_TABLE && pg_strcasecmp(schema_name, "sys") == 0) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_tablefunc(int type) +{ + /* + * The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION or OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION + * OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION || + type == OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_inlinefunc(int type) +{ + /* + * The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_scalarfunc(int type) +{ + /* + * The object should be either OBJECT_TYPE_TSQL_SCALAR_FUNCTION or OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_pk(int type) +{ + /* + * The object should be a OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT. + */ + if (type == OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT) + { + return 1; + } + return 0; +} + +static inline int dealwith_type_indexed(int type, Oid object_id) +{ + /* + * Search for object_id in pg_index catalog by indrelid column. + * The object is indexed if the entry exists in pg_index. + */ + Relation indRel; + ScanKeyData key; + SysScanDesc scan; + HeapTuple tup; + + if (type != OBJECT_TYPE_TABLE && type != OBJECT_TYPE_MATERIALIZED_VIEW) + return 0; + + indRel = table_open(IndexRelationId, RowExclusiveLock); + + ScanKeyInit(&key, + Anum_pg_index_indrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object_id)); + + scan = systable_beginscan(indRel, IndexIndrelidIndexId, true, + NULL, 1, &key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + systable_endscan(scan); + table_close(indRel, RowExclusiveLock); + return 1; + } + + systable_endscan(scan); + table_close(indRel, RowExclusiveLock); + + return 0; +} + +static inline int dealwith_type_trigger(int type) +{ + /* + * The type of the object should be OBJECT_TYPE_ASSEMBLY_DML_TRIGGER. + */ + if (type == OBJECT_TYPE_ASSEMBLY_DML_TRIGGER) + { + PG_RETURN_INT32(1); + } + PG_RETURN_INT32(0); +} \ No newline at end of file -- Gitee From 9daa23bc2c66183415b6bcb36b5de8a3b61905cf Mon Sep 17 00:00:00 2001 From: lukeman Date: Wed, 19 Feb 2025 17:31:13 +0800 Subject: [PATCH 06/11] =?UTF-8?q?D=E5=BA=93=E5=B8=B8=E7=94=A8=E8=AF=AD?= =?UTF-8?q?=E6=B3=95=E5=85=BC=E5=AE=B9-DDL/DML=E8=AF=AD=E6=B3=95=E5=85=BC?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/Makefile | 2 + contrib/shark/expected/test_ddl_and_dml.out | 4118 +++++++++++++++++ contrib/shark/parallel_schedule | 1 + contrib/shark/shark.cpp | 3 + contrib/shark/sql/test_ddl_and_dml.sql | 735 +++ .../shark/src/backend_parser/gram-tsql-decl.y | 7 +- .../gram-tsql-nonassoc-ident-tokens | 1 + .../shark/src/backend_parser/gram-tsql-rule.y | 836 +++- contrib/shark/src/backend_parser/include.pl | 35 +- contrib/shark/src/backend_parser/keywords.cpp | 17 +- contrib/shark/src/backend_parser/kwlist.h | 1447 +++--- .../src/backend_parser/scan-tsql-prologue.l.h | 2 +- contrib/shark/src/tablecmds.cpp | 454 ++ src/bin/pg_dump/pg_dump.cpp | 94 +- src/common/backend/catalog/heap.cpp | 12 +- src/common/backend/parser/analyze.cpp | 5 +- src/common/backend/parser/gram.y | 5 +- src/common/backend/parser/parse_utilcmd.cpp | 3 + src/common/backend/utils/adt/ruleutils.cpp | 2 + src/common/backend/utils/cache/relcache.cpp | 2 +- src/common/backend/utils/cache/syscache.cpp | 34 + src/common/pl/plpgsql/src/pl_exec.cpp | 3 +- .../optimizer/commands/ddldeparse.cpp | 27 +- .../optimizer/commands/tablecmds.cpp | 16 +- .../runtime/executor/nodeLimit.cpp | 17 +- .../runtime/executor/nodeModifyTable.cpp | 7 +- src/include/catalog/heap.h | 1 + src/include/catalog/pg_attribute.h | 1 + src/include/commands/tablecmds.h | 1 + src/include/executor/node/nodeLimit.h | 2 +- src/include/knl/knl_session.h | 4 + src/include/parser/analyze.h | 1 + src/include/parser/keywords.h | 1 + src/include/utils/syscache.h | 2 + 34 files changed, 7101 insertions(+), 797 deletions(-) create mode 100644 contrib/shark/expected/test_ddl_and_dml.out create mode 100644 contrib/shark/sql/test_ddl_and_dml.sql create mode 100644 contrib/shark/src/tablecmds.cpp diff --git a/contrib/shark/Makefile b/contrib/shark/Makefile index 2e2a25a75c..f8aef5c7f5 100644 --- a/contrib/shark/Makefile +++ b/contrib/shark/Makefile @@ -1,5 +1,6 @@ EXTENSION = shark MODULE_big = shark +BASECODEDIR=src BEPARSERDIR=src/backend_parser PLDIR=src/pltsql DATA = shark--1.0.sql @@ -11,6 +12,7 @@ OBJS += $(BEPARSERDIR)/gram-backend.o OBJS += $(BEPARSERDIR)/keywords.o OBJS += $(PLDIR)/pl_gram.o $(PLDIR)/pl_handler.o $(PLDIR)/pl_comp.o OBJS += $(PLDIR)/pl_scanner.o +OBJS += $(BASECODEDIR)/tablecmds.o subdir = contrib/shark top_builddir = ../.. diff --git a/contrib/shark/expected/test_ddl_and_dml.out b/contrib/shark/expected/test_ddl_and_dml.out new file mode 100644 index 0000000000..295cf42601 --- /dev/null +++ b/contrib/shark/expected/test_ddl_and_dml.out @@ -0,0 +1,4118 @@ +drop schema if exists test_ddl_and_dml cascade; +NOTICE: schema "test_ddl_and_dml" does not exist, skipping +create schema test_ddl_and_dml; +set current_schema = test_ddl_and_dml; +-- case 1: computed column +DROP TABLE IF EXISTS Products; +NOTICE: table "products" does not exist, skipping +CREATE TABLE Products( + QtyAvailable smallint, + UnitPrice money, + InventoryValue AS (QtyAvailable * UnitPrice) +); +ALTER TABLE Products ADD RetailValue AS (QtyAvailable * UnitPrice * 1.5) PERSISTED; +INSERT INTO Products (QtyAvailable, UnitPrice) VALUES (25, 2.00), (10, 1.5); +select * from Products; + qtyavailable | unitprice | inventoryvalue | retailvalue +--------------+-----------+----------------+------------- + 25 | $2.00 | $50.00 | $75.00 + 10 | $1.50 | $15.00 | $22.50 +(2 rows) + +\d+ Products + Table "test_ddl_and_dml.products" + Column | Type | Modifiers | Storage | Stats target | Description +----------------+----------+-----------------------------------------------------------------------------------------------------+---------+--------------+------------- + qtyavailable | smallint | | plain | | + unitprice | money | | plain | | + inventoryvalue | money | collate default generated always as ((qtyavailable * unitprice)) stored | plain | | + retailvalue | money | collate default generated always as (((qtyavailable * unitprice) * (1.5)::double precision)) stored | plain | | +Has OIDs: no +Options: orientation=row, compression=no + +-- 删除生成列 +ALTER TABLE Products DROP COLUMN RetailValue; +select * from Products; + qtyavailable | unitprice | inventoryvalue +--------------+-----------+---------------- + 25 | $2.00 | $50.00 + 10 | $1.50 | $15.00 +(2 rows) + +-- 嵌套生成列:报错 +ALTER TABLE Products ADD RetailValue2 AS (QtyAvailable * RetailValue * 1.5) PERSISTED; +ERROR: column "retailvalue" does not exist +-- 删除依赖列:报错 +ALTER TABLE Products DROP COLUMN UnitPrice; +ERROR: cannot drop a column used by a generated column +DETAIL: Column "unitprice" is used by generated column "inventoryvalue". +DROP TABLE IF EXISTS Products; +-- case2: top clause +DROP TABLE IF EXISTS Products; +NOTICE: table "products" does not exist, skipping +CREATE TABLE Products(QtyAvailable smallint, UnitPrice money, InventoryValue AS (QtyAvailable * UnitPrice)); +INSERT INTO Products(QtyAvailable, UnitPrice) VALUES (25, 2.00), (10, 1.5), (25, 2.00), (10, 1.5), (10, 1.5); +-- top N +select DISTINCT TOP 1 * from Products; + qtyavailable | unitprice | inventoryvalue +--------------+-----------+---------------- + 10 | $1.50 | $15.00 +(1 row) + +-- WITH TIES +select TOP 2 PERCENT WITH TIES * from Products ORDER BY InventoryValue; + qtyavailable | unitprice | inventoryvalue +--------------+-----------+---------------- + 10 | $1.50 | $15.00 + 10 | $1.50 | $15.00 + 10 | $1.50 | $15.00 +(3 rows) + +-- 百分比 +select TOP 2 PERCENT * from Products; + qtyavailable | unitprice | inventoryvalue +--------------+-----------+---------------- + 25 | $2.00 | $50.00 +(1 row) + +-- 报错:和limit子句同时使用 +select TOP 1 * from Products limit 10; +ERROR: multiple LIMIT clauses not allowed +LINE 1: select TOP 1 * from Products limit 10; + ^ +--报错:Percent values must be between 0 and 100. +select TOP 200 PERCENT * from Products; +ERROR: Percent values must be between 0 and 100. +--报错:WITH TIES必须和order by子句同时使用 +select TOP (select 10) WITH TIES * from Products; +ERROR: The WITH TIES clause is not allowed without a corresponding ORDER BY clause. +DROP TABLE IF EXISTS Products; +-- case 3: remove postfix operator +-- 报错:移除后缀运算符 +select 5!; +ERROR: syntax error at or near ";" +LINE 1: select 5!; + ^ +-- case 4: support direct column lable: 670 keywords +SELECT 1 ABORT; + abort +------- + 1 +(1 row) + +SELECT 1 ABSOLUTE; + absolute +---------- + 1 +(1 row) + +SELECT 1 ACCESS; + access +-------- + 1 +(1 row) + +SELECT 1 ACCOUNT; + account +--------- + 1 +(1 row) + +SELECT 1 ACTION; + action +-------- + 1 +(1 row) + +SELECT 1 ADD; + add +----- + 1 +(1 row) + +SELECT 1 ADMIN; + admin +------- + 1 +(1 row) + +SELECT 1 AFTER; + after +------- + 1 +(1 row) + +SELECT 1 AGGREGATE; + aggregate +----------- + 1 +(1 row) + +SELECT 1 ALGORITHM; + algorithm +----------- + 1 +(1 row) + +SELECT 1 ALL; + all +----- + 1 +(1 row) + +SELECT 1 ALSO; + also +------ + 1 +(1 row) + +SELECT 1 ALTER; + alter +------- + 1 +(1 row) + +SELECT 1 ALWAYS; + always +-------- + 1 +(1 row) + +SELECT 1 ANALYSE; + analyse +--------- + 1 +(1 row) + +SELECT 1 ANALYZE; + analyze +--------- + 1 +(1 row) + +SELECT 1 AND; + and +----- + 1 +(1 row) + +SELECT 1 ANY; + any +----- + 1 +(1 row) + +SELECT 1 APP; + app +----- + 1 +(1 row) + +SELECT 1 APPEND; + append +-------- + 1 +(1 row) + +SELECT 1 APPLY; + apply +------- + 1 +(1 row) + +SELECT 1 ARCHIVE; + archive +--------- + 1 +(1 row) + +SELECT 1 ASC; + asc +----- + 1 +(1 row) + +SELECT 1 ASOF; + asof +------ + 1 +(1 row) + +SELECT 1 ASSERTION; + assertion +----------- + 1 +(1 row) + +SELECT 1 ASSIGNMENT; + assignment +------------ + 1 +(1 row) + +SELECT 1 ASYMMETRIC; + asymmetric +------------ + 1 +(1 row) + +SELECT 1 AT; + at +---- + 1 +(1 row) + +SELECT 1 ATTRIBUTE; + attribute +----------- + 1 +(1 row) + +SELECT 1 AUDIT; + audit +------- + 1 +(1 row) + +SELECT 1 AUTHID; + authid +-------- + 1 +(1 row) + +SELECT 1 AUTHORIZATION; + authorization +--------------- + 1 +(1 row) + +SELECT 1 AUTO_INCREMENT; + auto_increment +---------------- + 1 +(1 row) + +SELECT 1 AUTOEXTEND; + autoextend +------------ + 1 +(1 row) + +SELECT 1 AUTOMAPPED; + automapped +------------ + 1 +(1 row) + +SELECT 1 BACKWARD; + backward +---------- + 1 +(1 row) + +SELECT 1 BARRIER; + barrier +--------- + 1 +(1 row) + +SELECT 1 BEFORE; + before +-------- + 1 +(1 row) + +SELECT 1 BEGIN; + begin +------- + 1 +(1 row) + +SELECT 1 BEGIN_NON_ANOYBLOCK; + begin_non_anoyblock +--------------------- + 1 +(1 row) + +SELECT 1 BIGINT; + bigint +-------- + 1 +(1 row) + +SELECT 1 BINARY; + binary +-------- + 1 +(1 row) + +SELECT 1 BINARY_DOUBLE; + binary_double +--------------- + 1 +(1 row) + +SELECT 1 BINARY_DOUBLE_INF; + binary_double_inf +------------------- + 1 +(1 row) + +SELECT 1 BINARY_DOUBLE_NAN; + binary_double_nan +------------------- + 1 +(1 row) + +SELECT 1 BINARY_INTEGER; + binary_integer +---------------- + 1 +(1 row) + +SELECT 1 BIT; + bit +----- + 1 +(1 row) + +SELECT 1 BLANKS; + blanks +-------- + 1 +(1 row) + +SELECT 1 BLOB; + blob +------ + 1 +(1 row) + +SELECT 1 BLOCKCHAIN; + blockchain +------------ + 1 +(1 row) + +SELECT 1 BODY; + body +------ + 1 +(1 row) + +SELECT 1 BOOLEAN; + boolean +--------- + 1 +(1 row) + +SELECT 1 BOTH; + both +------ + 1 +(1 row) + +SELECT 1 BUCKETCNT; + bucketcnt +----------- + 1 +(1 row) + +SELECT 1 BUCKETS; + buckets +--------- + 1 +(1 row) + +SELECT 1 BUILD; + build +------- + 1 +(1 row) + +SELECT 1 BYTE; + byte +------ + 1 +(1 row) + +SELECT 1 BYTEAWITHOUTORDER; + byteawithoutorder +------------------- + 1 +(1 row) + +SELECT 1 BYTEAWITHOUTORDERWITHEQUAL; + byteawithoutorderwithequal +---------------------------- + 1 +(1 row) + +SELECT 1 CACHE; + cache +------- + 1 +(1 row) + +SELECT 1 CALL; + call +------ + 1 +(1 row) + +SELECT 1 CALLED; + called +-------- + 1 +(1 row) + +SELECT 1 CANCELABLE; + cancelable +------------ + 1 +(1 row) + +SELECT 1 CASCADE; + cascade +--------- + 1 +(1 row) + +SELECT 1 CASCADED; + cascaded +---------- + 1 +(1 row) + +SELECT 1 CASE; + case +------ + 1 +(1 row) + +SELECT 1 CAST; + cast +------ + 1 +(1 row) + +SELECT 1 CATALOG; + catalog +--------- + 1 +(1 row) + +SELECT 1 CATALOG_NAME; + catalog_name +-------------- + 1 +(1 row) + +SELECT 1 CHAIN; + chain +------- + 1 +(1 row) + +SELECT 1 CHANGE; + change +-------- + 1 +(1 row) + +SELECT 1 CHARACTERISTICS; + characteristics +----------------- + 1 +(1 row) + +SELECT 1 CHARACTERSET; + characterset +-------------- + 1 +(1 row) + +SELECT 1 CHARSET; + charset +--------- + 1 +(1 row) + +SELECT 1 CHECK; + check +------- + 1 +(1 row) + +SELECT 1 CHECKPOINT; + checkpoint +------------ + 1 +(1 row) + +SELECT 1 CLASS; + class +------- + 1 +(1 row) + +SELECT 1 CLASS_ORIGIN; + class_origin +-------------- + 1 +(1 row) + +SELECT 1 CLEAN; + clean +------- + 1 +(1 row) + +SELECT 1 CLIENT; + client +-------- + 1 +(1 row) + +SELECT 1 CLIENT_MASTER_KEY; + client_master_key +------------------- + 1 +(1 row) + +SELECT 1 CLIENT_MASTER_KEYS; + client_master_keys +-------------------- + 1 +(1 row) + +SELECT 1 CLOB; + clob +------ + 1 +(1 row) + +SELECT 1 CLOSE; + close +------- + 1 +(1 row) + +SELECT 1 CLUSTER; + cluster +--------- + 1 +(1 row) + +SELECT 1 TSQL_CLUSTERED; + tsql_clustered +---------------- + 1 +(1 row) + +SELECT 1 COALESCE; + coalesce +---------- + 1 +(1 row) + +SELECT 1 COLLATE; + collate +--------- + 1 +(1 row) + +SELECT 1 COLLATION; + collation +----------- + 1 +(1 row) + +SELECT 1 COLUMN; + column +-------- + 1 +(1 row) + +SELECT 1 COLUMN_ENCRYPTION_KEY; + column_encryption_key +----------------------- + 1 +(1 row) + +SELECT 1 COLUMN_ENCRYPTION_KEYS; + column_encryption_keys +------------------------ + 1 +(1 row) + +SELECT 1 COLUMN_NAME; + column_name +------------- + 1 +(1 row) + +SELECT 1 COLUMNS; + columns +--------- + 1 +(1 row) + +SELECT 1 TSQL_COLUMNSTORE; + tsql_columnstore +------------------ + 1 +(1 row) + +SELECT 1 COMMENT; + comment +--------- + 1 +(1 row) + +SELECT 1 COMMENTS; + comments +---------- + 1 +(1 row) + +SELECT 1 COMMIT; + commit +-------- + 1 +(1 row) + +SELECT 1 COMMITTED; + committed +----------- + 1 +(1 row) + +SELECT 1 COMPACT; + compact +--------- + 1 +(1 row) + +SELECT 1 COMPATIBLE_ILLEGAL_CHARS; + compatible_illegal_chars +-------------------------- + 1 +(1 row) + +SELECT 1 COMPILE; + compile +--------- + 1 +(1 row) + +SELECT 1 COMPLETE; + complete +---------- + 1 +(1 row) + +SELECT 1 COMPLETION; + completion +------------ + 1 +(1 row) + +SELECT 1 COMPRESS; + compress +---------- + 1 +(1 row) + +SELECT 1 CONCURRENTLY; + concurrently +-------------- + 1 +(1 row) + +SELECT 1 CONDITION; + condition +----------- + 1 +(1 row) + +SELECT 1 CONFIGURATION; + configuration +--------------- + 1 +(1 row) + +SELECT 1 CONNECT; + connect +--------- + 1 +(1 row) + +SELECT 1 CONNECTION; + connection +------------ + 1 +(1 row) + +SELECT 1 CONSISTENT; + consistent +------------ + 1 +(1 row) + +SELECT 1 CONSTANT; + constant +---------- + 1 +(1 row) + +SELECT 1 CONSTRAINT; + constraint +------------ + 1 +(1 row) + +SELECT 1 CONSTRAINT_CATALOG; + constraint_catalog +-------------------- + 1 +(1 row) + +SELECT 1 CONSTRAINT_NAME; + constraint_name +----------------- + 1 +(1 row) + +SELECT 1 CONSTRAINT_SCHEMA; + constraint_schema +------------------- + 1 +(1 row) + +SELECT 1 CONSTRAINTS; + constraints +------------- + 1 +(1 row) + +SELECT 1 CONSTRUCTOR; + constructor +------------- + 1 +(1 row) + +SELECT 1 CONTENT; + content +--------- + 1 +(1 row) + +SELECT 1 CONTINUE; + continue +---------- + 1 +(1 row) + +SELECT 1 CONTVIEW; + contview +---------- + 1 +(1 row) + +SELECT 1 CONVERSION; + conversion +------------ + 1 +(1 row) + +SELECT 1 CONVERT; + convert +--------- + 1 +(1 row) + +SELECT 1 COORDINATOR; + coordinator +------------- + 1 +(1 row) + +SELECT 1 COORDINATORS; + coordinators +-------------- + 1 +(1 row) + +SELECT 1 COPY; + copy +------ + 1 +(1 row) + +SELECT 1 COST; + cost +------ + 1 +(1 row) + +SELECT 1 CROSS; + cross +------- + 1 +(1 row) + +SELECT 1 CSN; + csn +----- + 1 +(1 row) + +SELECT 1 CSV; + csv +----- + 1 +(1 row) + +SELECT 1 CUBE; + cube +------ + 1 +(1 row) + +SELECT 1 CURRENT; + current +--------- + 1 +(1 row) + +SELECT 1 CURRENT_CATALOG; + current_catalog +----------------- + 1 +(1 row) + +SELECT 1 CURRENT_DATE; + current_date +-------------- + 1 +(1 row) + +SELECT 1 CURRENT_ROLE; + current_role +-------------- + 1 +(1 row) + +SELECT 1 CURRENT_SCHEMA; + current_schema +---------------- + 1 +(1 row) + +SELECT 1 CURRENT_TIME; + current_time +-------------- + 1 +(1 row) + +SELECT 1 CURRENT_TIMESTAMP; + current_timestamp +------------------- + 1 +(1 row) + +SELECT 1 CURRENT_USER; + current_user +-------------- + 1 +(1 row) + +SELECT 1 CURSOR; + cursor +-------- + 1 +(1 row) + +SELECT 1 CURSOR_NAME; + cursor_name +------------- + 1 +(1 row) + +SELECT 1 CYCLE; + cycle +------- + 1 +(1 row) + +SELECT 1 DATA; + data +------ + 1 +(1 row) + +SELECT 1 DATABASE; + database +---------- + 1 +(1 row) + +SELECT 1 DATAFILE; + datafile +---------- + 1 +(1 row) + +SELECT 1 DATANODE; + datanode +---------- + 1 +(1 row) + +SELECT 1 DATANODES; + datanodes +----------- + 1 +(1 row) + +SELECT 1 DATATYPE_CL; + datatype_cl +------------- + 1 +(1 row) + +SELECT 1 DATE; + date +------ + 1 +(1 row) + +SELECT 1 DATE_FORMAT; + date_format +------------- + 1 +(1 row) + +SELECT 1 DAY_HOUR; + day_hour +---------- + 1 +(1 row) + +SELECT 1 DAY_MINUTE; + day_minute +------------ + 1 +(1 row) + +SELECT 1 DAY_SECOND; + day_second +------------ + 1 +(1 row) + +SELECT 1 DBCOMPATIBILITY; + dbcompatibility +----------------- + 1 +(1 row) + +SELECT 1 DEALLOCATE; + deallocate +------------ + 1 +(1 row) + +SELECT 1 DEC; + dec +----- + 1 +(1 row) + +SELECT 1 DECIMAL; + decimal +--------- + 1 +(1 row) + +SELECT 1 DECLARE; + declare +--------- + 1 +(1 row) + +SELECT 1 DECODE; + decode +-------- + 1 +(1 row) + +SELECT 1 DEFAULT; + default +--------- + 1 +(1 row) + +SELECT 1 DEFAULTS; + defaults +---------- + 1 +(1 row) + +SELECT 1 DEFERRABLE; + deferrable +------------ + 1 +(1 row) + +SELECT 1 DEFERRED; + deferred +---------- + 1 +(1 row) + +SELECT 1 DEFINER; + definer +--------- + 1 +(1 row) + +SELECT 1 DELETE; + delete +-------- + 1 +(1 row) + +SELECT 1 DELIMITER; + delimiter +----------- + 1 +(1 row) + +SELECT 1 DELIMITERS; + delimiters +------------ + 1 +(1 row) + +SELECT 1 DELTA; + delta +------- + 1 +(1 row) + +SELECT 1 DELTAMERGE; + deltamerge +------------ + 1 +(1 row) + +SELECT 1 DENSE_RANK; + dense_rank +------------ + 1 +(1 row) + +SELECT 1 DESC; + desc +------ + 1 +(1 row) + +SELECT 1 DETERMINISTIC; + deterministic +--------------- + 1 +(1 row) + +SELECT 1 DIAGNOSTICS; + diagnostics +------------- + 1 +(1 row) + +SELECT 1 DICTIONARY; + dictionary +------------ + 1 +(1 row) + +SELECT 1 DIRECT; + direct +-------- + 1 +(1 row) + +SELECT 1 DIRECTORY; + directory +----------- + 1 +(1 row) + +SELECT 1 DISABLE; + disable +--------- + 1 +(1 row) + +SELECT 1 DISCARD; + discard +--------- + 1 +(1 row) + +SELECT 1 DISCONNECT; + disconnect +------------ + 1 +(1 row) + +SELECT 1 DISTINCT; + distinct +---------- + 1 +(1 row) + +SELECT 1 DISTRIBUTE; + distribute +------------ + 1 +(1 row) + +SELECT 1 DISTRIBUTION; + distribution +-------------- + 1 +(1 row) + +SELECT 1 DO; + do +---- + 1 +(1 row) + +SELECT 1 DOCUMENT; + document +---------- + 1 +(1 row) + +SELECT 1 DOMAIN; + domain +-------- + 1 +(1 row) + +SELECT 1 DOUBLE; + double +-------- + 1 +(1 row) + +SELECT 1 DROP; + drop +------ + 1 +(1 row) + +SELECT 1 DUMPFILE; + dumpfile +---------- + 1 +(1 row) + +SELECT 1 DUPLICATE; + duplicate +----------- + 1 +(1 row) + +SELECT 1 EACH; + each +------ + 1 +(1 row) + +SELECT 1 ELASTIC; + elastic +--------- + 1 +(1 row) + +SELECT 1 ELSE; + else +------ + 1 +(1 row) + +SELECT 1 ENABLE; + enable +-------- + 1 +(1 row) + +SELECT 1 ENCLOSED; + enclosed +---------- + 1 +(1 row) + +SELECT 1 ENCODING; + encoding +---------- + 1 +(1 row) + +SELECT 1 ENCRYPTED; + encrypted +----------- + 1 +(1 row) + +SELECT 1 ENCRYPTED_VALUE; + encrypted_value +----------------- + 1 +(1 row) + +SELECT 1 ENCRYPTION; + encryption +------------ + 1 +(1 row) + +SELECT 1 ENCRYPTION_TYPE; + encryption_type +----------------- + 1 +(1 row) + +SELECT 1 END; + end +----- + 1 +(1 row) + +SELECT 1 ENDS; + ends +------ + 1 +(1 row) + +SELECT 1 ENFORCED; + enforced +---------- + 1 +(1 row) + +SELECT 1 ENUM; + enum +------ + 1 +(1 row) + +SELECT 1 EOL; + eol +----- + 1 +(1 row) + +SELECT 1 ERROR; + error +------- + 1 +(1 row) + +SELECT 1 ERRORS; + errors +-------- + 1 +(1 row) + +SELECT 1 ESCAPE; + escape +-------- + 1 +(1 row) + +SELECT 1 ESCAPED; + escaped +--------- + 1 +(1 row) + +SELECT 1 ESCAPING; + escaping +---------- + 1 +(1 row) + +SELECT 1 EVENT; + event +------- + 1 +(1 row) + +SELECT 1 EVENTS; + events +-------- + 1 +(1 row) + +SELECT 1 EVERY; + every +------- + 1 +(1 row) + +SELECT 1 EXCHANGE; + exchange +---------- + 1 +(1 row) + +SELECT 1 EXCLUDE; + exclude +--------- + 1 +(1 row) + +SELECT 1 EXCLUDED; + excluded +---------- + 1 +(1 row) + +SELECT 1 EXCLUDING; + excluding +----------- + 1 +(1 row) + +SELECT 1 EXCLUSIVE; + exclusive +----------- + 1 +(1 row) + +SELECT 1 EXECUTE; + execute +--------- + 1 +(1 row) + +SELECT 1 EXISTS; + exists +-------- + 1 +(1 row) + +SELECT 1 EXPIRED; + expired +--------- + 1 +(1 row) + +SELECT 1 EXPLAIN; + explain +--------- + 1 +(1 row) + +SELECT 1 EXTENSION; + extension +----------- + 1 +(1 row) + +SELECT 1 EXTERNAL; + external +---------- + 1 +(1 row) + +SELECT 1 EXTRACT; + extract +--------- + 1 +(1 row) + +SELECT 1 FALSE; + false +------- + 1 +(1 row) + +SELECT 1 FAMILY; + family +-------- + 1 +(1 row) + +SELECT 1 FAST; + fast +------ + 1 +(1 row) + +SELECT 1 FEATURES; + features +---------- + 1 +(1 row) + +SELECT 1 FENCED; + fenced +-------- + 1 +(1 row) + +SELECT 1 FIELDS; + fields +-------- + 1 +(1 row) + +SELECT 1 FILEHEADER; + fileheader +------------ + 1 +(1 row) + +SELECT 1 FILL_MISSING_FIELDS; + fill_missing_fields +--------------------- + 1 +(1 row) + +SELECT 1 FILLER; + filler +-------- + 1 +(1 row) + +SELECT 1 FINAL; + final +------- + 1 +(1 row) + +SELECT 1 FIRST; + first +------- + 1 +(1 row) + +SELECT 1 FIXED; + fixed +------- + 1 +(1 row) + +SELECT 1 FLOAT; + float +------- + 1 +(1 row) + +SELECT 1 FOLLOWING; + following +----------- + 1 +(1 row) + +SELECT 1 FOLLOWS; + follows +--------- + 1 +(1 row) + +SELECT 1 FORCE; + force +------- + 1 +(1 row) + +SELECT 1 FOREIGN; + foreign +--------- + 1 +(1 row) + +SELECT 1 FORMATTER; + formatter +----------- + 1 +(1 row) + +SELECT 1 FORWARD; + forward +--------- + 1 +(1 row) + +SELECT 1 FREEZE; + freeze +-------- + 1 +(1 row) + +SELECT 1 FULL; + full +------ + 1 +(1 row) + +SELECT 1 FUNCTION; + function +---------- + 1 +(1 row) + +SELECT 1 FUNCTIONS; + functions +----------- + 1 +(1 row) + +SELECT 1 GENERATED; + generated +----------- + 1 +(1 row) + +SELECT 1 GET; + get +----- + 1 +(1 row) + +SELECT 1 GLOBAL; + global +-------- + 1 +(1 row) + +SELECT 1 GRANTED; + granted +--------- + 1 +(1 row) + +SELECT 1 GREATEST; + greatest +---------- + 1 +(1 row) + +SELECT 1 GROUPING; + grouping +---------- + 1 +(1 row) + +SELECT 1 GROUPPARENT; + groupparent +------------- + 1 +(1 row) + +SELECT 1 HANDLER; + handler +--------- + 1 +(1 row) + +SELECT 1 HDFSDIRECTORY; + hdfsdirectory +--------------- + 1 +(1 row) + +SELECT 1 HEADER; + header +-------- + 1 +(1 row) + +SELECT 1 HOLD; + hold +------ + 1 +(1 row) + +SELECT 1 HOUR_MINUTE; + hour_minute +------------- + 1 +(1 row) + +SELECT 1 HOUR_SECOND; + hour_second +------------- + 1 +(1 row) + +SELECT 1 IDENTIFIED; + identified +------------ + 1 +(1 row) + +SELECT 1 IDENTITY; + identity +---------- + 1 +(1 row) + +SELECT 1 IF; + if +---- + 1 +(1 row) + +SELECT 1 IGNORE; + ignore +-------- + 1 +(1 row) + +SELECT 1 IGNORE_EXTRA_DATA; + ignore_extra_data +------------------- + 1 +(1 row) + +SELECT 1 ILIKE; + ilike +------- + 1 +(1 row) + +SELECT 1 IMCSTORED; + imcstored +----------- + 1 +(1 row) + +SELECT 1 IMMEDIATE; + immediate +----------- + 1 +(1 row) + +SELECT 1 IMMUTABLE; + immutable +----------- + 1 +(1 row) + +SELECT 1 IMPLICIT; + implicit +---------- + 1 +(1 row) + +SELECT 1 IN; + in +---- + 1 +(1 row) + +SELECT 1 INCLUDE; + include +--------- + 1 +(1 row) + +SELECT 1 INCLUDING; + including +----------- + 1 +(1 row) + +SELECT 1 INCREMENT; + increment +----------- + 1 +(1 row) + +SELECT 1 INCREMENTAL; + incremental +------------- + 1 +(1 row) + +SELECT 1 INDEX; + index +------- + 1 +(1 row) + +SELECT 1 INDEXES; + indexes +--------- + 1 +(1 row) + +SELECT 1 INFILE; + infile +-------- + 1 +(1 row) + +SELECT 1 INFINITE; + infinite +---------- + 1 +(1 row) + +SELECT 1 INHERIT; + inherit +--------- + 1 +(1 row) + +SELECT 1 INHERITS; + inherits +---------- + 1 +(1 row) + +SELECT 1 INITIAL; + initial +--------- + 1 +(1 row) + +SELECT 1 INITIALLY; + initially +----------- + 1 +(1 row) + +SELECT 1 INITRANS; + initrans +---------- + 1 +(1 row) + +SELECT 1 INLINE; + inline +-------- + 1 +(1 row) + +SELECT 1 INNER; + inner +------- + 1 +(1 row) + +SELECT 1 INOUT; + inout +------- + 1 +(1 row) + +SELECT 1 INPUT; + input +------- + 1 +(1 row) + +SELECT 1 INSENSITIVE; + insensitive +------------- + 1 +(1 row) + +SELECT 1 INSERT; + insert +-------- + 1 +(1 row) + +SELECT 1 INSTEAD; + instead +--------- + 1 +(1 row) + +SELECT 1 INT; + int +----- + 1 +(1 row) + +SELECT 1 INTEGER; + integer +--------- + 1 +(1 row) + +SELECT 1 INTERNAL; + internal +---------- + 1 +(1 row) + +SELECT 1 INTERVAL; + interval +---------- + 1 +(1 row) + +SELECT 1 INVISIBLE; + invisible +----------- + 1 +(1 row) + +SELECT 1 INVOKER; + invoker +--------- + 1 +(1 row) + +SELECT 1 IP; + ip +---- + 1 +(1 row) + +SELECT 1 IS; + is +---- + 1 +(1 row) + +SELECT 1 ISOLATION; + isolation +----------- + 1 +(1 row) + +SELECT 1 JOIN; + join +------ + 1 +(1 row) + +SELECT 1 JSON_EXISTS; + json_exists +------------- + 1 +(1 row) + +SELECT 1 KEY; + key +----- + 1 +(1 row) + +SELECT 1 KEYATH; + keyath +-------- + 1 +(1 row) + +SELECT 1 KEY_STORE; + key_store +----------- + 1 +(1 row) + +SELECT 1 KILL; + kill +------ + 1 +(1 row) + +SELECT 1 LABEL; + label +------- + 1 +(1 row) + +SELECT 1 LANGUAGE; + language +---------- + 1 +(1 row) + +SELECT 1 LARGE; + large +------- + 1 +(1 row) + +SELECT 1 LAST; + last +------ + 1 +(1 row) + +SELECT 1 LATERAL; + lateral +--------- + 1 +(1 row) + +SELECT 1 LC_COLLATE; + lc_collate +------------ + 1 +(1 row) + +SELECT 1 LC_CTYPE; + lc_ctype +---------- + 1 +(1 row) + +SELECT 1 LEADING; + leading +--------- + 1 +(1 row) + +SELECT 1 LEAKPROOF; + leakproof +----------- + 1 +(1 row) + +SELECT 1 LEAST; + least +------- + 1 +(1 row) + +SELECT 1 LEFT; + left +------ + 1 +(1 row) + +SELECT 1 LESS; + less +------ + 1 +(1 row) + +SELECT 1 LEVEL; + level +------- + 1 +(1 row) + +SELECT 1 LIKE; + like +------ + 1 +(1 row) + +SELECT 1 LINES; + lines +------- + 1 +(1 row) + +SELECT 1 LIST; + list +------ + 1 +(1 row) + +SELECT 1 LISTEN; + listen +-------- + 1 +(1 row) + +SELECT 1 LOAD; + load +------ + 1 +(1 row) + +SELECT 1 LOCAL; + local +------- + 1 +(1 row) + +SELECT 1 LOCALTIME; + localtime +----------- + 1 +(1 row) + +SELECT 1 LOCALTIMESTAMP; + localtimestamp +---------------- + 1 +(1 row) + +SELECT 1 LOCATION; + location +---------- + 1 +(1 row) + +SELECT 1 LOCK; + lock +------ + 1 +(1 row) + +SELECT 1 LOCKED; + locked +-------- + 1 +(1 row) + +SELECT 1 LOG; + log +----- + 1 +(1 row) + +SELECT 1 LOGGING; + logging +--------- + 1 +(1 row) + +SELECT 1 LOGIN_ANY; + login_any +----------- + 1 +(1 row) + +SELECT 1 LOGIN_FAILURE; + login_failure +--------------- + 1 +(1 row) + +SELECT 1 LOGIN_SUCCESS; + login_success +--------------- + 1 +(1 row) + +SELECT 1 LOGOUT; + logout +-------- + 1 +(1 row) + +SELECT 1 LOOP; + loop +------ + 1 +(1 row) + +SELECT 1 MAP; + map +----- + 1 +(1 row) + +SELECT 1 MAPPING; + mapping +--------- + 1 +(1 row) + +SELECT 1 MASKING; + masking +--------- + 1 +(1 row) + +SELECT 1 MASTER; + master +-------- + 1 +(1 row) + +SELECT 1 MATCH; + match +------- + 1 +(1 row) + +SELECT 1 MATCHED; + matched +--------- + 1 +(1 row) + +SELECT 1 MATERIALIZED; + materialized +-------------- + 1 +(1 row) + +SELECT 1 MAXEXTENTS; + maxextents +------------ + 1 +(1 row) + +SELECT 1 MAXSIZE; + maxsize +--------- + 1 +(1 row) + +SELECT 1 MAXTRANS; + maxtrans +---------- + 1 +(1 row) + +SELECT 1 MAXVALUE; + maxvalue +---------- + 1 +(1 row) + +SELECT 1 MEMBER; + member +-------- + 1 +(1 row) + +SELECT 1 MERGE; + merge +------- + 1 +(1 row) + +SELECT 1 MESSAGE_TEXT; + message_text +-------------- + 1 +(1 row) + +SELECT 1 METHOD; + method +-------- + 1 +(1 row) + +SELECT 1 MINEXTENTS; + minextents +------------ + 1 +(1 row) + +SELECT 1 MINUTE_SECOND; + minute_second +--------------- + 1 +(1 row) + +SELECT 1 MINVALUE; + minvalue +---------- + 1 +(1 row) + +SELECT 1 MODE; + mode +------ + 1 +(1 row) + +SELECT 1 MODEL; + model +------- + 1 +(1 row) + +SELECT 1 MODIFY; + modify +-------- + 1 +(1 row) + +SELECT 1 MOVE; + move +------ + 1 +(1 row) + +SELECT 1 MOVEMENT; + movement +---------- + 1 +(1 row) + +SELECT 1 MYSQL_ERRNO; + mysql_errno +------------- + 1 +(1 row) + +SELECT 1 NAMES; + names +------- + 1 +(1 row) + +SELECT 1 NAN; + nan +----- + 1 +(1 row) + +SELECT 1 NATIONAL; + national +---------- + 1 +(1 row) + +SELECT 1 NATURAL; + natural +--------- + 1 +(1 row) + +SELECT 1 NCHAR; + nchar +------- + 1 +(1 row) + +SELECT 1 NEXT; + next +------ + 1 +(1 row) + +SELECT 1 NO; + no +---- + 1 +(1 row) + +SELECT 1 NOCOMPRESS; + nocompress +------------ + 1 +(1 row) + +SELECT 1 NOCYCLE; + nocycle +--------- + 1 +(1 row) + +SELECT 1 NODE; + node +------ + 1 +(1 row) + +SELECT 1 NOLOGGING; + nologging +----------- + 1 +(1 row) + +SELECT 1 NOMAXVALUE; + nomaxvalue +------------ + 1 +(1 row) + +SELECT 1 NOMINVALUE; + nominvalue +------------ + 1 +(1 row) + +SELECT 1 TSQL_NONCLUSTERED; + tsql_nonclustered +------------------- + 1 +(1 row) + +SELECT 1 NONE; + none +------ + 1 +(1 row) + +SELECT 1 NOTHING; + nothing +--------- + 1 +(1 row) + +SELECT 1 NOTIFY; + notify +-------- + 1 +(1 row) + +SELECT 1 NOVALIDATE; + novalidate +------------ + 1 +(1 row) + +SELECT 1 NOWAIT; + nowait +-------- + 1 +(1 row) + +SELECT 1 NTH_VALUE; + nth_value +----------- + 1 +(1 row) + +SELECT 1 NULL; + null +------ + 1 +(1 row) + +SELECT 1 NULLCOLS; + nullcols +---------- + 1 +(1 row) + +SELECT 1 NULLIF; + nullif +-------- + 1 +(1 row) + +SELECT 1 NULLS; + nulls +------- + 1 +(1 row) + +SELECT 1 NUMBER; + number +-------- + 1 +(1 row) + +SELECT 1 NUMERIC; + numeric +--------- + 1 +(1 row) + +SELECT 1 NUMSTR; + numstr +-------- + 1 +(1 row) + +SELECT 1 NVARCHAR; + nvarchar +---------- + 1 +(1 row) + +SELECT 1 NVARCHAR2; + nvarchar2 +----------- + 1 +(1 row) + +SELECT 1 NVL; + nvl +----- + 1 +(1 row) + +SELECT 1 OBJECT; + object +-------- + 1 +(1 row) + +SELECT 1 OF; + of +---- + 1 +(1 row) + +SELECT 1 OFF; + off +----- + 1 +(1 row) + +SELECT 1 OIDS; + oids +------ + 1 +(1 row) + +SELECT 1 ONLY; + only +------ + 1 +(1 row) + +SELECT 1 OPERATOR; + operator +---------- + 1 +(1 row) + +SELECT 1 OPTIMIZATION; + optimization +-------------- + 1 +(1 row) + +SELECT 1 OPTION; + option +-------- + 1 +(1 row) + +SELECT 1 OPTIONALLY; + optionally +------------ + 1 +(1 row) + +SELECT 1 OPTIONS; + options +--------- + 1 +(1 row) + +SELECT 1 OR; + or +---- + 1 +(1 row) + +SELECT 1 OUT; + out +----- + 1 +(1 row) + +SELECT 1 OUTER; + outer +------- + 1 +(1 row) + +SELECT 1 OUTFILE; + outfile +--------- + 1 +(1 row) + +SELECT 1 OVERLAY; + overlay +--------- + 1 +(1 row) + +SELECT 1 OWNED; + owned +------- + 1 +(1 row) + +SELECT 1 OWNER; + owner +------- + 1 +(1 row) + +SELECT 1 PACKAGE; + package +--------- + 1 +(1 row) + +SELECT 1 PACKAGES; + packages +---------- + 1 +(1 row) + +SELECT 1 PARALLEL_ENABLE; + parallel_enable +----------------- + 1 +(1 row) + +SELECT 1 PARSER; + parser +-------- + 1 +(1 row) + +SELECT 1 PARTIAL; + partial +--------- + 1 +(1 row) + +SELECT 1 PARTITION; + partition +----------- + 1 +(1 row) + +SELECT 1 PARTITIONS; + partitions +------------ + 1 +(1 row) + +SELECT 1 PASSING; + passing +--------- + 1 +(1 row) + +SELECT 1 PASSWORD; + password +---------- + 1 +(1 row) + +SELECT 1 PCTFREE; + pctfree +--------- + 1 +(1 row) + +SELECT 1 PER; + per +----- + 1 +(1 row) + +SELECT 1 TSQLERCENT; + tsqlercent +------------ + 1 +(1 row) + +SELECT 1 PERFORMANCE; + performance +------------- + 1 +(1 row) + +SELECT 1 PERM; + perm +------ + 1 +(1 row) + +SELECT 1 TSQLERSISTED; + tsqlersisted +-------------- + 1 +(1 row) + +SELECT 1 PIPELINED; + pipelined +----------- + 1 +(1 row) + +SELECT 1 PLACING; + placing +--------- + 1 +(1 row) + +SELECT 1 PLAN; + plan +------ + 1 +(1 row) + +SELECT 1 PLANS; + plans +------- + 1 +(1 row) + +SELECT 1 POLICY; + policy +-------- + 1 +(1 row) + +SELECT 1 POOL; + pool +------ + 1 +(1 row) + +SELECT 1 POSITION; + position +---------- + 1 +(1 row) + +SELECT 1 PRECEDES; + precedes +---------- + 1 +(1 row) + +SELECT 1 PRECEDING; + preceding +----------- + 1 +(1 row) + +SELECT 1 PREDICT; + predict +--------- + 1 +(1 row) + +SELECT 1 PREFERRED; + preferred +----------- + 1 +(1 row) + +SELECT 1 PREFIX; + prefix +-------- + 1 +(1 row) + +SELECT 1 PREPARE; + prepare +--------- + 1 +(1 row) + +SELECT 1 PREPARED; + prepared +---------- + 1 +(1 row) + +SELECT 1 PRESERVE; + preserve +---------- + 1 +(1 row) + +SELECT 1 PRIMARY; + primary +--------- + 1 +(1 row) + +SELECT 1 PRIOR; + prior +------- + 1 +(1 row) + +SELECT 1 PRIORER; + priorer +--------- + 1 +(1 row) + +SELECT 1 PRIVATE; + private +--------- + 1 +(1 row) + +SELECT 1 PRIVILEGE; + privilege +----------- + 1 +(1 row) + +SELECT 1 PRIVILEGES; + privileges +------------ + 1 +(1 row) + +SELECT 1 PROCEDURAL; + procedural +------------ + 1 +(1 row) + +SELECT 1 PROCEDURE; + procedure +----------- + 1 +(1 row) + +SELECT 1 PROFILE; + profile +--------- + 1 +(1 row) + +SELECT 1 PUBLICATION; + publication +------------- + 1 +(1 row) + +SELECT 1 PUBLISH; + publish +--------- + 1 +(1 row) + +SELECT 1 PURGE; + purge +------- + 1 +(1 row) + +SELECT 1 QUERY; + query +------- + 1 +(1 row) + +SELECT 1 QUOTE; + quote +------- + 1 +(1 row) + +SELECT 1 RANDOMIZED; + randomized +------------ + 1 +(1 row) + +SELECT 1 RANGE; + range +------- + 1 +(1 row) + +SELECT 1 RATIO; + ratio +------- + 1 +(1 row) + +SELECT 1 RAW; + raw +----- + 1 +(1 row) + +SELECT 1 READ; + read +------ + 1 +(1 row) + +SELECT 1 REAL; + real +------ + 1 +(1 row) + +SELECT 1 REASSIGN; + reassign +---------- + 1 +(1 row) + +SELECT 1 REBUILD; + rebuild +--------- + 1 +(1 row) + +SELECT 1 RECHECK; + recheck +--------- + 1 +(1 row) + +SELECT 1 RECURSIVE; + recursive +----------- + 1 +(1 row) + +SELECT 1 RECYCLEBIN; + recyclebin +------------ + 1 +(1 row) + +SELECT 1 REDISANYVALUE; + redisanyvalue +--------------- + 1 +(1 row) + +SELECT 1 REF; + ref +----- + 1 +(1 row) + +SELECT 1 REFERENCES; + references +------------ + 1 +(1 row) + +SELECT 1 REFRESH; + refresh +--------- + 1 +(1 row) + +SELECT 1 REINDEX; + reindex +--------- + 1 +(1 row) + +SELECT 1 REJECT; + reject +-------- + 1 +(1 row) + +SELECT 1 RELATIVE; + relative +---------- + 1 +(1 row) + +SELECT 1 RELEASE; + release +--------- + 1 +(1 row) + +SELECT 1 RELOPTIONS; + reloptions +------------ + 1 +(1 row) + +SELECT 1 REMOTE; + remote +-------- + 1 +(1 row) + +SELECT 1 REMOVE; + remove +-------- + 1 +(1 row) + +SELECT 1 RENAME; + rename +-------- + 1 +(1 row) + +SELECT 1 REPEAT; + repeat +-------- + 1 +(1 row) + +SELECT 1 REPEATABLE; + repeatable +------------ + 1 +(1 row) + +SELECT 1 REPLACE; + replace +--------- + 1 +(1 row) + +SELECT 1 REPLICA; + replica +--------- + 1 +(1 row) + +SELECT 1 RESET; + reset +------- + 1 +(1 row) + +SELECT 1 RESIZE; + resize +-------- + 1 +(1 row) + +SELECT 1 RESOURCE; + resource +---------- + 1 +(1 row) + +SELECT 1 RESPECT; + respect +--------- + 1 +(1 row) + +SELECT 1 RESTART; + restart +--------- + 1 +(1 row) + +SELECT 1 RESTRICT; + restrict +---------- + 1 +(1 row) + +SELECT 1 RESULT; + result +-------- + 1 +(1 row) + +SELECT 1 RETURN; + return +-------- + 1 +(1 row) + +SELECT 1 RETURNED_SQLSTATE; + returned_sqlstate +------------------- + 1 +(1 row) + +SELECT 1 RETURNS; + returns +--------- + 1 +(1 row) + +SELECT 1 REUSE; + reuse +------- + 1 +(1 row) + +SELECT 1 REVOKE; + revoke +-------- + 1 +(1 row) + +SELECT 1 RIGHT; + right +------- + 1 +(1 row) + +SELECT 1 ROLE; + role +------ + 1 +(1 row) + +SELECT 1 ROLES; + roles +------- + 1 +(1 row) + +SELECT 1 ROLLBACK; + rollback +---------- + 1 +(1 row) + +SELECT 1 ROLLUP; + rollup +-------- + 1 +(1 row) + +SELECT 1 ROTATE; + rotate +-------- + 1 +(1 row) + +SELECT 1 ROTATION; + rotation +---------- + 1 +(1 row) + +SELECT 1 ROW; + row +----- + 1 +(1 row) + +SELECT 1 ROW_COUNT; + row_count +----------- + 1 +(1 row) + +SELECT 1 ROWNUM; + rownum +-------- + 1 +(1 row) + +SELECT 1 ROWS; + rows +------ + 1 +(1 row) + +SELECT 1 ROWTYPE; + rowtype +--------- + 1 +(1 row) + +SELECT 1 RULE; + rule +------ + 1 +(1 row) + +SELECT 1 SAMPLE; + sample +-------- + 1 +(1 row) + +SELECT 1 SAVEPOINT; + savepoint +----------- + 1 +(1 row) + +SELECT 1 SCHEDULE; + schedule +---------- + 1 +(1 row) + +SELECT 1 SCHEMA; + schema +-------- + 1 +(1 row) + +SELECT 1 SCHEMA_NAME; + schema_name +------------- + 1 +(1 row) + +SELECT 1 SCROLL; + scroll +-------- + 1 +(1 row) + +SELECT 1 SEARCH; + search +-------- + 1 +(1 row) + +SELECT 1 SECURITY; + security +---------- + 1 +(1 row) + +SELECT 1 SELF; + self +------ + 1 +(1 row) + +SELECT 1 SEPARATOR; + separator +----------- + 1 +(1 row) + +SELECT 1 SEQUENCE; + sequence +---------- + 1 +(1 row) + +SELECT 1 SEQUENCES; + sequences +----------- + 1 +(1 row) + +SELECT 1 SERIALIZABLE; + serializable +-------------- + 1 +(1 row) + +SELECT 1 SERVER; + server +-------- + 1 +(1 row) + +SELECT 1 SESSION; + session +--------- + 1 +(1 row) + +SELECT 1 SESSION_USER; + session_user +-------------- + 1 +(1 row) + +SELECT 1 SET; + set +----- + 1 +(1 row) + +SELECT 1 SETOF; + setof +------- + 1 +(1 row) + +SELECT 1 SETS; + sets +------ + 1 +(1 row) + +SELECT 1 SHARE; + share +------- + 1 +(1 row) + +SELECT 1 SHIPPABLE; + shippable +----------- + 1 +(1 row) + +SELECT 1 SHOW; + show +------ + 1 +(1 row) + +SELECT 1 SHRINK; + shrink +-------- + 1 +(1 row) + +SELECT 1 SHUTDOWN; + shutdown +---------- + 1 +(1 row) + +SELECT 1 SIBLINGS; + siblings +---------- + 1 +(1 row) + +SELECT 1 SIMILAR; + similar +--------- + 1 +(1 row) + +SELECT 1 SIMPLE; + simple +-------- + 1 +(1 row) + +SELECT 1 SIZE; + size +------ + 1 +(1 row) + +SELECT 1 SKIP; + skip +------ + 1 +(1 row) + +SELECT 1 SLAVE; + slave +------- + 1 +(1 row) + +SELECT 1 SLICE; + slice +------- + 1 +(1 row) + +SELECT 1 SMALLDATETIME; + smalldatetime +--------------- + 1 +(1 row) + +SELECT 1 SMALLDATETIME_FORMAT; + smalldatetime_format +---------------------- + 1 +(1 row) + +SELECT 1 SMALLINT; + smallint +---------- + 1 +(1 row) + +SELECT 1 SNAPSHOT; + snapshot +---------- + 1 +(1 row) + +SELECT 1 SOME; + some +------ + 1 +(1 row) + +SELECT 1 SOURCE; + source +-------- + 1 +(1 row) + +SELECT 1 SPACE; + space +------- + 1 +(1 row) + +SELECT 1 SPECIFICATION; + specification +--------------- + 1 +(1 row) + +SELECT 1 SPILL; + spill +------- + 1 +(1 row) + +SELECT 1 SPLIT; + split +------- + 1 +(1 row) + +SELECT 1 SQL; + sql +----- + 1 +(1 row) + +SELECT 1 STABLE; + stable +-------- + 1 +(1 row) + +SELECT 1 STACKED; + stacked +--------- + 1 +(1 row) + +SELECT 1 STANDALONE; + standalone +------------ + 1 +(1 row) + +SELECT 1 START; + start +------- + 1 +(1 row) + +SELECT 1 STARTING; + starting +---------- + 1 +(1 row) + +SELECT 1 STARTS; + starts +-------- + 1 +(1 row) + +SELECT 1 STATEMENT; + statement +----------- + 1 +(1 row) + +SELECT 1 STATEMENT_ID; + statement_id +-------------- + 1 +(1 row) + +SELECT 1 STATIC; + static +-------- + 1 +(1 row) + +SELECT 1 STATISTICS; + statistics +------------ + 1 +(1 row) + +SELECT 1 STDIN; + stdin +------- + 1 +(1 row) + +SELECT 1 STDOUT; + stdout +-------- + 1 +(1 row) + +SELECT 1 STORAGE; + storage +--------- + 1 +(1 row) + +SELECT 1 STORE; + store +------- + 1 +(1 row) + +SELECT 1 STORED; + stored +-------- + 1 +(1 row) + +SELECT 1 STRATIFY; + stratify +---------- + 1 +(1 row) + +SELECT 1 STREAM; + stream +-------- + 1 +(1 row) + +SELECT 1 STRICT; + strict +-------- + 1 +(1 row) + +SELECT 1 STRIP; + strip +------- + 1 +(1 row) + +SELECT 1 SUBCLASS_ORIGIN; + subclass_origin +----------------- + 1 +(1 row) + +SELECT 1 SUBPARTITION; + subpartition +-------------- + 1 +(1 row) + +SELECT 1 SUBPARTITIONS; + subpartitions +--------------- + 1 +(1 row) + +SELECT 1 SUBSCRIPTION; + subscription +-------------- + 1 +(1 row) + +SELECT 1 SUBSTRING; + substring +----------- + 1 +(1 row) + +SELECT 1 SYMMETRIC; + symmetric +----------- + 1 +(1 row) + +SELECT 1 SYNONYM; + synonym +--------- + 1 +(1 row) + +SELECT 1 SYS_REFCURSOR; + sys_refcursor +--------------- + 1 +(1 row) + +SELECT 1 SYSDATE; + sysdate +--------- + 1 +(1 row) + +SELECT 1 SYSID; + sysid +------- + 1 +(1 row) + +SELECT 1 SYSTEM; + system +-------- + 1 +(1 row) + +SELECT 1 TABLE; + table +------- + 1 +(1 row) + +SELECT 1 TABLE_NAME; + table_name +------------ + 1 +(1 row) + +SELECT 1 TABLES; + tables +-------- + 1 +(1 row) + +SELECT 1 TABLESAMPLE; + tablesample +------------- + 1 +(1 row) + +SELECT 1 TABLESPACE; + tablespace +------------ + 1 +(1 row) + +SELECT 1 TEMP; + temp +------ + 1 +(1 row) + +SELECT 1 TEMPLATE; + template +---------- + 1 +(1 row) + +SELECT 1 TEMPORARY; + temporary +----------- + 1 +(1 row) + +SELECT 1 TERMINATED; + terminated +------------ + 1 +(1 row) + +SELECT 1 TEXT; + text +------ + 1 +(1 row) + +SELECT 1 THAN; + than +------ + 1 +(1 row) + +SELECT 1 THEN; + then +------ + 1 +(1 row) + +SELECT 1 TIES; + ties +------ + 1 +(1 row) + +SELECT 1 TIME; + time +------ + 1 +(1 row) + +SELECT 1 TIME_FORMAT; + time_format +------------- + 1 +(1 row) + +SELECT 1 TIMECAPSULE; + timecapsule +------------- + 1 +(1 row) + +SELECT 1 TIMESTAMP; + timestamp +----------- + 1 +(1 row) + +SELECT 1 TIMESTAMP_FORMAT; + timestamp_format +------------------ + 1 +(1 row) + +SELECT 1 TIMESTAMPDIFF; + timestampdiff +--------------- + 1 +(1 row) + +SELECT 1 TIMEZONE_HOUR; + timezone_hour +--------------- + 1 +(1 row) + +SELECT 1 TIMEZONE_MINUTE; + timezone_minute +----------------- + 1 +(1 row) + +SELECT 1 TINYINT; + tinyint +--------- + 1 +(1 row) + +SELECT 1 TSQL_TOP; + tsql_top +---------- + 1 +(1 row) + +SELECT 1 TRAILING; + trailing +---------- + 1 +(1 row) + +SELECT 1 TRANSACTION; + transaction +------------- + 1 +(1 row) + +SELECT 1 TRANSFORM; + transform +----------- + 1 +(1 row) + +SELECT 1 TREAT; + treat +------- + 1 +(1 row) + +SELECT 1 TRIGGER; + trigger +--------- + 1 +(1 row) + +SELECT 1 TRIM; + trim +------ + 1 +(1 row) + +SELECT 1 TRUE; + true +------ + 1 +(1 row) + +SELECT 1 TRUNCATE; + truncate +---------- + 1 +(1 row) + +SELECT 1 TRUSTED; + trusted +--------- + 1 +(1 row) + +SELECT 1 TSFIELD; + tsfield +--------- + 1 +(1 row) + +SELECT 1 TSTAG; + tstag +------- + 1 +(1 row) + +SELECT 1 TSTIME; + tstime +-------- + 1 +(1 row) + +SELECT 1 TYPES; + types +------- + 1 +(1 row) + +SELECT 1 UNBOUNDED; + unbounded +----------- + 1 +(1 row) + +SELECT 1 UNCOMMITTED; + uncommitted +------------- + 1 +(1 row) + +SELECT 1 UNDER; + under +------- + 1 +(1 row) + +SELECT 1 UNENCRYPTED; + unencrypted +------------- + 1 +(1 row) + +SELECT 1 UNIMCSTORED; + unimcstored +------------- + 1 +(1 row) + +SELECT 1 UNIQUE; + unique +-------- + 1 +(1 row) + +SELECT 1 UNKNOWN; + unknown +--------- + 1 +(1 row) + +SELECT 1 UNLIMITED; + unlimited +----------- + 1 +(1 row) + +SELECT 1 UNLISTEN; + unlisten +---------- + 1 +(1 row) + +SELECT 1 UNLOCK; + unlock +-------- + 1 +(1 row) + +SELECT 1 UNLOGGED; + unlogged +---------- + 1 +(1 row) + +SELECT 1 UNTIL; + until +------- + 1 +(1 row) + +SELECT 1 UNUSABLE; + unusable +---------- + 1 +(1 row) + +SELECT 1 UPDATE; + update +-------- + 1 +(1 row) + +SELECT 1 USE; + use +----- + 1 +(1 row) + +SELECT 1 USEEOF; + useeof +-------- + 1 +(1 row) + +SELECT 1 USER; + user +------ + 1 +(1 row) + +SELECT 1 USING; + using +------- + 1 +(1 row) + +SELECT 1 VACUUM; + vacuum +-------- + 1 +(1 row) + +SELECT 1 VALID; + valid +------- + 1 +(1 row) + +SELECT 1 VALIDATE; + validate +---------- + 1 +(1 row) + +SELECT 1 VALIDATION; + validation +------------ + 1 +(1 row) + +SELECT 1 VALIDATOR; + validator +----------- + 1 +(1 row) + +SELECT 1 VALUES; + values +-------- + 1 +(1 row) + +SELECT 1 VARCHAR; + varchar +--------- + 1 +(1 row) + +SELECT 1 VARCHAR2; + varchar2 +---------- + 1 +(1 row) + +SELECT 1 VARIABLES; + variables +----------- + 1 +(1 row) + +SELECT 1 VARIADIC; + variadic +---------- + 1 +(1 row) + +SELECT 1 VARRAY; + varray +-------- + 1 +(1 row) + +SELECT 1 VCGROUP; + vcgroup +--------- + 1 +(1 row) + +SELECT 1 VERBOSE; + verbose +--------- + 1 +(1 row) + +SELECT 1 VERIFY; + verify +-------- + 1 +(1 row) + +SELECT 1 VERSION; + version +--------- + 1 +(1 row) + +SELECT 1 VIEW; + view +------ + 1 +(1 row) + +SELECT 1 VISIBLE; + visible +--------- + 1 +(1 row) + +SELECT 1 VOLATILE; + volatile +---------- + 1 +(1 row) + +SELECT 1 WAIT; + wait +------ + 1 +(1 row) + +SELECT 1 WARNINGS; + warnings +---------- + 1 +(1 row) + +SELECT 1 WEAK; + weak +------ + 1 +(1 row) + +SELECT 1 WHEN; + when +------ + 1 +(1 row) + +SELECT 1 WHILE; + while +------- + 1 +(1 row) + +SELECT 1 WHITESPACE; + whitespace +------------ + 1 +(1 row) + +SELECT 1 WORK; + work +------ + 1 +(1 row) + +SELECT 1 WORKLOAD; + workload +---------- + 1 +(1 row) + +SELECT 1 WRAPPER; + wrapper +--------- + 1 +(1 row) + +SELECT 1 WRITE; + write +------- + 1 +(1 row) + +SELECT 1 XMLATTRIBUTES; + xmlattributes +--------------- + 1 +(1 row) + +SELECT 1 XMLCONCAT; + xmlconcat +----------- + 1 +(1 row) + +SELECT 1 XMLELEMENT; + xmlelement +------------ + 1 +(1 row) + +SELECT 1 XMLEXISTS; + xmlexists +----------- + 1 +(1 row) + +SELECT 1 XMLFOREST; + xmlforest +----------- + 1 +(1 row) + +SELECT 1 XMLPARSE; + xmlparse +---------- + 1 +(1 row) + +SELECT 1 XMLPI; + xmlpi +------- + 1 +(1 row) + +SELECT 1 XMLROOT; + xmlroot +--------- + 1 +(1 row) + +SELECT 1 XMLSERIALIZE; + xmlserialize +-------------- + 1 +(1 row) + +SELECT 1 YEAR_MONTH; + year_month +------------ + 1 +(1 row) + +SELECT 1 YES; + yes +----- + 1 +(1 row) + +SELECT 1 ZONE; + zone +------ + 1 +(1 row) + +reset current_schema; +drop schema if exists test_ddl_and_dml cascade; diff --git a/contrib/shark/parallel_schedule b/contrib/shark/parallel_schedule index 578e0def9f..3c1a7aad46 100644 --- a/contrib/shark/parallel_schedule +++ b/contrib/shark/parallel_schedule @@ -4,6 +4,7 @@ test: basetest test: day_test rand_test test: objectproperty test: clustered_index insert_stmt sbr_test +test: test_ddl_and_dml test: rotate-test-part2 rotate-test-part2_ci test: functions test: test_dbcc test_dbcc_case_sen diff --git a/contrib/shark/shark.cpp b/contrib/shark/shark.cpp index 90d257ecb5..e03a764e94 100644 --- a/contrib/shark/shark.cpp +++ b/contrib/shark/shark.cpp @@ -10,6 +10,7 @@ static bool global_hook_inited = false; static uint32 shark_index; extern List* tsql_raw_parser(const char* str, List** query_string_locationlist); +extern void assign_tablecmds_hook(void); void _PG_init(void) {} @@ -35,6 +36,8 @@ void init_session_vars(void) cxt->dialect_sql = false; cxt->rowcount = 0; cxt->fetch_status = FETCH_STATUS_SUCCESS; + + assign_tablecmds_hook(); } SharkContext* GetSessionContext() diff --git a/contrib/shark/sql/test_ddl_and_dml.sql b/contrib/shark/sql/test_ddl_and_dml.sql new file mode 100644 index 0000000000..6c79d5e239 --- /dev/null +++ b/contrib/shark/sql/test_ddl_and_dml.sql @@ -0,0 +1,735 @@ +drop schema if exists test_ddl_and_dml cascade; +create schema test_ddl_and_dml; +set current_schema = test_ddl_and_dml; + +-- case 1: computed column +DROP TABLE IF EXISTS Products; +CREATE TABLE Products( + QtyAvailable smallint, + UnitPrice money, + InventoryValue AS (QtyAvailable * UnitPrice) +); + +ALTER TABLE Products ADD RetailValue AS (QtyAvailable * UnitPrice * 1.5) PERSISTED; + +INSERT INTO Products (QtyAvailable, UnitPrice) VALUES (25, 2.00), (10, 1.5); + +select * from Products; + +\d+ Products + +-- 删除生成列 +ALTER TABLE Products DROP COLUMN RetailValue; + +select * from Products; + +-- 嵌套生成列:报错 +ALTER TABLE Products ADD RetailValue2 AS (QtyAvailable * RetailValue * 1.5) PERSISTED; + +-- 删除依赖列:报错 +ALTER TABLE Products DROP COLUMN UnitPrice; + +DROP TABLE IF EXISTS Products; + +-- case2: top clause +DROP TABLE IF EXISTS Products; +CREATE TABLE Products(QtyAvailable smallint, UnitPrice money, InventoryValue AS (QtyAvailable * UnitPrice)); + +INSERT INTO Products(QtyAvailable, UnitPrice) VALUES (25, 2.00), (10, 1.5), (25, 2.00), (10, 1.5), (10, 1.5); + +-- top N +select DISTINCT TOP 1 * from Products; +-- WITH TIES +select TOP 2 PERCENT WITH TIES * from Products ORDER BY InventoryValue; +-- 百分比 +select TOP 2 PERCENT * from Products; + +-- 报错:和limit子句同时使用 +select TOP 1 * from Products limit 10; + +--报错:Percent values must be between 0 and 100. +select TOP 200 PERCENT * from Products; + +--报错:WITH TIES必须和order by子句同时使用 +select TOP (select 10) WITH TIES * from Products; + +DROP TABLE IF EXISTS Products; + +-- case 3: remove postfix operator +-- 报错:移除后缀运算符 +select 5!; + +-- case 4: support direct column lable: 670 keywords +SELECT 1 ABORT; +SELECT 1 ABSOLUTE; +SELECT 1 ACCESS; +SELECT 1 ACCOUNT; +SELECT 1 ACTION; +SELECT 1 ADD; +SELECT 1 ADMIN; +SELECT 1 AFTER; +SELECT 1 AGGREGATE; +SELECT 1 ALGORITHM; +SELECT 1 ALL; +SELECT 1 ALSO; +SELECT 1 ALTER; +SELECT 1 ALWAYS; +SELECT 1 ANALYSE; +SELECT 1 ANALYZE; +SELECT 1 AND; +SELECT 1 ANY; +SELECT 1 APP; +SELECT 1 APPEND; +SELECT 1 APPLY; +SELECT 1 ARCHIVE; +SELECT 1 ASC; +SELECT 1 ASOF; +SELECT 1 ASSERTION; +SELECT 1 ASSIGNMENT; +SELECT 1 ASYMMETRIC; +SELECT 1 AT; +SELECT 1 ATTRIBUTE; +SELECT 1 AUDIT; +SELECT 1 AUTHID; +SELECT 1 AUTHORIZATION; +SELECT 1 AUTO_INCREMENT; +SELECT 1 AUTOEXTEND; +SELECT 1 AUTOMAPPED; +SELECT 1 BACKWARD; +SELECT 1 BARRIER; +SELECT 1 BEFORE; +SELECT 1 BEGIN; +SELECT 1 BEGIN_NON_ANOYBLOCK; +SELECT 1 BIGINT; +SELECT 1 BINARY; +SELECT 1 BINARY_DOUBLE; +SELECT 1 BINARY_DOUBLE_INF; +SELECT 1 BINARY_DOUBLE_NAN; +SELECT 1 BINARY_INTEGER; +SELECT 1 BIT; +SELECT 1 BLANKS; +SELECT 1 BLOB; +SELECT 1 BLOCKCHAIN; +SELECT 1 BODY; +SELECT 1 BOOLEAN; +SELECT 1 BOTH; +SELECT 1 BUCKETCNT; +SELECT 1 BUCKETS; +SELECT 1 BUILD; +SELECT 1 BYTE; +SELECT 1 BYTEAWITHOUTORDER; +SELECT 1 BYTEAWITHOUTORDERWITHEQUAL; +SELECT 1 CACHE; +SELECT 1 CALL; +SELECT 1 CALLED; +SELECT 1 CANCELABLE; +SELECT 1 CASCADE; +SELECT 1 CASCADED; +SELECT 1 CASE; +SELECT 1 CAST; +SELECT 1 CATALOG; +SELECT 1 CATALOG_NAME; +SELECT 1 CHAIN; +SELECT 1 CHANGE; +SELECT 1 CHARACTERISTICS; +SELECT 1 CHARACTERSET; +SELECT 1 CHARSET; +SELECT 1 CHECK; +SELECT 1 CHECKPOINT; +SELECT 1 CLASS; +SELECT 1 CLASS_ORIGIN; +SELECT 1 CLEAN; +SELECT 1 CLIENT; +SELECT 1 CLIENT_MASTER_KEY; +SELECT 1 CLIENT_MASTER_KEYS; +SELECT 1 CLOB; +SELECT 1 CLOSE; +SELECT 1 CLUSTER; +SELECT 1 TSQL_CLUSTERED; +SELECT 1 COALESCE; +SELECT 1 COLLATE; +SELECT 1 COLLATION; +SELECT 1 COLUMN; +SELECT 1 COLUMN_ENCRYPTION_KEY; +SELECT 1 COLUMN_ENCRYPTION_KEYS; +SELECT 1 COLUMN_NAME; +SELECT 1 COLUMNS; +SELECT 1 TSQL_COLUMNSTORE; +SELECT 1 COMMENT; +SELECT 1 COMMENTS; +SELECT 1 COMMIT; +SELECT 1 COMMITTED; +SELECT 1 COMPACT; +SELECT 1 COMPATIBLE_ILLEGAL_CHARS; +SELECT 1 COMPILE; +SELECT 1 COMPLETE; +SELECT 1 COMPLETION; +SELECT 1 COMPRESS; +SELECT 1 CONCURRENTLY; +SELECT 1 CONDITION; +SELECT 1 CONFIGURATION; +SELECT 1 CONNECT; +SELECT 1 CONNECTION; +SELECT 1 CONSISTENT; +SELECT 1 CONSTANT; +SELECT 1 CONSTRAINT; +SELECT 1 CONSTRAINT_CATALOG; +SELECT 1 CONSTRAINT_NAME; +SELECT 1 CONSTRAINT_SCHEMA; +SELECT 1 CONSTRAINTS; +SELECT 1 CONSTRUCTOR; +SELECT 1 CONTENT; +SELECT 1 CONTINUE; +SELECT 1 CONTVIEW; +SELECT 1 CONVERSION; +SELECT 1 CONVERT; +SELECT 1 COORDINATOR; +SELECT 1 COORDINATORS; +SELECT 1 COPY; +SELECT 1 COST; +SELECT 1 CROSS; +SELECT 1 CSN; +SELECT 1 CSV; +SELECT 1 CUBE; +SELECT 1 CURRENT; +SELECT 1 CURRENT_CATALOG; +SELECT 1 CURRENT_DATE; +SELECT 1 CURRENT_ROLE; +SELECT 1 CURRENT_SCHEMA; +SELECT 1 CURRENT_TIME; +SELECT 1 CURRENT_TIMESTAMP; +SELECT 1 CURRENT_USER; +SELECT 1 CURSOR; +SELECT 1 CURSOR_NAME; +SELECT 1 CYCLE; +SELECT 1 DATA; +SELECT 1 DATABASE; +SELECT 1 DATAFILE; +SELECT 1 DATANODE; +SELECT 1 DATANODES; +SELECT 1 DATATYPE_CL; +SELECT 1 DATE; +SELECT 1 DATE_FORMAT; +SELECT 1 DAY_HOUR; +SELECT 1 DAY_MINUTE; +SELECT 1 DAY_SECOND; +SELECT 1 DBCOMPATIBILITY; +SELECT 1 DEALLOCATE; +SELECT 1 DEC; +SELECT 1 DECIMAL; +SELECT 1 DECLARE; +SELECT 1 DECODE; +SELECT 1 DEFAULT; +SELECT 1 DEFAULTS; +SELECT 1 DEFERRABLE; +SELECT 1 DEFERRED; +SELECT 1 DEFINER; +SELECT 1 DELETE; +SELECT 1 DELIMITER; +SELECT 1 DELIMITERS; +SELECT 1 DELTA; +SELECT 1 DELTAMERGE; +SELECT 1 DENSE_RANK; +SELECT 1 DESC; +SELECT 1 DETERMINISTIC; +SELECT 1 DIAGNOSTICS; +SELECT 1 DICTIONARY; +SELECT 1 DIRECT; +SELECT 1 DIRECTORY; +SELECT 1 DISABLE; +SELECT 1 DISCARD; +SELECT 1 DISCONNECT; +SELECT 1 DISTINCT; +SELECT 1 DISTRIBUTE; +SELECT 1 DISTRIBUTION; +SELECT 1 DO; +SELECT 1 DOCUMENT; +SELECT 1 DOMAIN; +SELECT 1 DOUBLE; +SELECT 1 DROP; +SELECT 1 DUMPFILE; +SELECT 1 DUPLICATE; +SELECT 1 EACH; +SELECT 1 ELASTIC; +SELECT 1 ELSE; +SELECT 1 ENABLE; +SELECT 1 ENCLOSED; +SELECT 1 ENCODING; +SELECT 1 ENCRYPTED; +SELECT 1 ENCRYPTED_VALUE; +SELECT 1 ENCRYPTION; +SELECT 1 ENCRYPTION_TYPE; +SELECT 1 END; +SELECT 1 ENDS; +SELECT 1 ENFORCED; +SELECT 1 ENUM; +SELECT 1 EOL; +SELECT 1 ERROR; +SELECT 1 ERRORS; +SELECT 1 ESCAPE; +SELECT 1 ESCAPED; +SELECT 1 ESCAPING; +SELECT 1 EVENT; +SELECT 1 EVENTS; +SELECT 1 EVERY; +SELECT 1 EXCHANGE; +SELECT 1 EXCLUDE; +SELECT 1 EXCLUDED; +SELECT 1 EXCLUDING; +SELECT 1 EXCLUSIVE; +SELECT 1 EXECUTE; +SELECT 1 EXISTS; +SELECT 1 EXPIRED; +SELECT 1 EXPLAIN; +SELECT 1 EXTENSION; +SELECT 1 EXTERNAL; +SELECT 1 EXTRACT; +SELECT 1 FALSE; +SELECT 1 FAMILY; +SELECT 1 FAST; +SELECT 1 FEATURES; +SELECT 1 FENCED; +SELECT 1 FIELDS; +SELECT 1 FILEHEADER; +SELECT 1 FILL_MISSING_FIELDS; +SELECT 1 FILLER; +SELECT 1 FINAL; +SELECT 1 FIRST; +SELECT 1 FIXED; +SELECT 1 FLOAT; +SELECT 1 FOLLOWING; +SELECT 1 FOLLOWS; +SELECT 1 FORCE; +SELECT 1 FOREIGN; +SELECT 1 FORMATTER; +SELECT 1 FORWARD; +SELECT 1 FREEZE; +SELECT 1 FULL; +SELECT 1 FUNCTION; +SELECT 1 FUNCTIONS; +SELECT 1 GENERATED; +SELECT 1 GET; +SELECT 1 GLOBAL; +SELECT 1 GRANTED; +SELECT 1 GREATEST; +SELECT 1 GROUPING; +SELECT 1 GROUPPARENT; +SELECT 1 HANDLER; +SELECT 1 HDFSDIRECTORY; +SELECT 1 HEADER; +SELECT 1 HOLD; +SELECT 1 HOUR_MINUTE; +SELECT 1 HOUR_SECOND; +SELECT 1 IDENTIFIED; +SELECT 1 IDENTITY; +SELECT 1 IF; +SELECT 1 IGNORE; +SELECT 1 IGNORE_EXTRA_DATA; +SELECT 1 ILIKE; +SELECT 1 IMCSTORED; +SELECT 1 IMMEDIATE; +SELECT 1 IMMUTABLE; +SELECT 1 IMPLICIT; +SELECT 1 IN; +SELECT 1 INCLUDE; +SELECT 1 INCLUDING; +SELECT 1 INCREMENT; +SELECT 1 INCREMENTAL; +SELECT 1 INDEX; +SELECT 1 INDEXES; +SELECT 1 INFILE; +SELECT 1 INFINITE; +SELECT 1 INHERIT; +SELECT 1 INHERITS; +SELECT 1 INITIAL; +SELECT 1 INITIALLY; +SELECT 1 INITRANS; +SELECT 1 INLINE; +SELECT 1 INNER; +SELECT 1 INOUT; +SELECT 1 INPUT; +SELECT 1 INSENSITIVE; +SELECT 1 INSERT; +SELECT 1 INSTEAD; +SELECT 1 INT; +SELECT 1 INTEGER; +SELECT 1 INTERNAL; +SELECT 1 INTERVAL; +SELECT 1 INVISIBLE; +SELECT 1 INVOKER; +SELECT 1 IP; +SELECT 1 IS; +SELECT 1 ISOLATION; +SELECT 1 JOIN; +SELECT 1 JSON_EXISTS; +SELECT 1 KEY; +SELECT 1 KEYATH; +SELECT 1 KEY_STORE; +SELECT 1 KILL; +SELECT 1 LABEL; +SELECT 1 LANGUAGE; +SELECT 1 LARGE; +SELECT 1 LAST; +SELECT 1 LATERAL; +SELECT 1 LC_COLLATE; +SELECT 1 LC_CTYPE; +SELECT 1 LEADING; +SELECT 1 LEAKPROOF; +SELECT 1 LEAST; +SELECT 1 LEFT; +SELECT 1 LESS; +SELECT 1 LEVEL; +SELECT 1 LIKE; +SELECT 1 LINES; +SELECT 1 LIST; +SELECT 1 LISTEN; +SELECT 1 LOAD; +SELECT 1 LOCAL; +SELECT 1 LOCALTIME; +SELECT 1 LOCALTIMESTAMP; +SELECT 1 LOCATION; +SELECT 1 LOCK; +SELECT 1 LOCKED; +SELECT 1 LOG; +SELECT 1 LOGGING; +SELECT 1 LOGIN_ANY; +SELECT 1 LOGIN_FAILURE; +SELECT 1 LOGIN_SUCCESS; +SELECT 1 LOGOUT; +SELECT 1 LOOP; +SELECT 1 MAP; +SELECT 1 MAPPING; +SELECT 1 MASKING; +SELECT 1 MASTER; +SELECT 1 MATCH; +SELECT 1 MATCHED; +SELECT 1 MATERIALIZED; +SELECT 1 MAXEXTENTS; +SELECT 1 MAXSIZE; +SELECT 1 MAXTRANS; +SELECT 1 MAXVALUE; +SELECT 1 MEMBER; +SELECT 1 MERGE; +SELECT 1 MESSAGE_TEXT; +SELECT 1 METHOD; +SELECT 1 MINEXTENTS; +SELECT 1 MINUTE_SECOND; +SELECT 1 MINVALUE; +SELECT 1 MODE; +SELECT 1 MODEL; +SELECT 1 MODIFY; +SELECT 1 MOVE; +SELECT 1 MOVEMENT; +SELECT 1 MYSQL_ERRNO; +SELECT 1 NAMES; +SELECT 1 NAN; +SELECT 1 NATIONAL; +SELECT 1 NATURAL; +SELECT 1 NCHAR; +SELECT 1 NEXT; +SELECT 1 NO; +SELECT 1 NOCOMPRESS; +SELECT 1 NOCYCLE; +SELECT 1 NODE; +SELECT 1 NOLOGGING; +SELECT 1 NOMAXVALUE; +SELECT 1 NOMINVALUE; +SELECT 1 TSQL_NONCLUSTERED; +SELECT 1 NONE; +SELECT 1 NOTHING; +SELECT 1 NOTIFY; +SELECT 1 NOVALIDATE; +SELECT 1 NOWAIT; +SELECT 1 NTH_VALUE; +SELECT 1 NULL; +SELECT 1 NULLCOLS; +SELECT 1 NULLIF; +SELECT 1 NULLS; +SELECT 1 NUMBER; +SELECT 1 NUMERIC; +SELECT 1 NUMSTR; +SELECT 1 NVARCHAR; +SELECT 1 NVARCHAR2; +SELECT 1 NVL; +SELECT 1 OBJECT; +SELECT 1 OF; +SELECT 1 OFF; +SELECT 1 OIDS; +SELECT 1 ONLY; +SELECT 1 OPERATOR; +SELECT 1 OPTIMIZATION; +SELECT 1 OPTION; +SELECT 1 OPTIONALLY; +SELECT 1 OPTIONS; +SELECT 1 OR; +SELECT 1 OUT; +SELECT 1 OUTER; +SELECT 1 OUTFILE; +SELECT 1 OVERLAY; +SELECT 1 OWNED; +SELECT 1 OWNER; +SELECT 1 PACKAGE; +SELECT 1 PACKAGES; +SELECT 1 PARALLEL_ENABLE; +SELECT 1 PARSER; +SELECT 1 PARTIAL; +SELECT 1 PARTITION; +SELECT 1 PARTITIONS; +SELECT 1 PASSING; +SELECT 1 PASSWORD; +SELECT 1 PCTFREE; +SELECT 1 PER; +SELECT 1 TSQLERCENT; +SELECT 1 PERFORMANCE; +SELECT 1 PERM; +SELECT 1 TSQLERSISTED; +SELECT 1 PIPELINED; +SELECT 1 PLACING; +SELECT 1 PLAN; +SELECT 1 PLANS; +SELECT 1 POLICY; +SELECT 1 POOL; +SELECT 1 POSITION; +SELECT 1 PRECEDES; +SELECT 1 PRECEDING; +SELECT 1 PREDICT; +SELECT 1 PREFERRED; +SELECT 1 PREFIX; +SELECT 1 PREPARE; +SELECT 1 PREPARED; +SELECT 1 PRESERVE; +SELECT 1 PRIMARY; +SELECT 1 PRIOR; +SELECT 1 PRIORER; +SELECT 1 PRIVATE; +SELECT 1 PRIVILEGE; +SELECT 1 PRIVILEGES; +SELECT 1 PROCEDURAL; +SELECT 1 PROCEDURE; +SELECT 1 PROFILE; +SELECT 1 PUBLICATION; +SELECT 1 PUBLISH; +SELECT 1 PURGE; +SELECT 1 QUERY; +SELECT 1 QUOTE; +SELECT 1 RANDOMIZED; +SELECT 1 RANGE; +SELECT 1 RATIO; +SELECT 1 RAW; +SELECT 1 READ; +SELECT 1 REAL; +SELECT 1 REASSIGN; +SELECT 1 REBUILD; +SELECT 1 RECHECK; +SELECT 1 RECURSIVE; +SELECT 1 RECYCLEBIN; +SELECT 1 REDISANYVALUE; +SELECT 1 REF; +SELECT 1 REFERENCES; +SELECT 1 REFRESH; +SELECT 1 REINDEX; +SELECT 1 REJECT; +SELECT 1 RELATIVE; +SELECT 1 RELEASE; +SELECT 1 RELOPTIONS; +SELECT 1 REMOTE; +SELECT 1 REMOVE; +SELECT 1 RENAME; +SELECT 1 REPEAT; +SELECT 1 REPEATABLE; +SELECT 1 REPLACE; +SELECT 1 REPLICA; +SELECT 1 RESET; +SELECT 1 RESIZE; +SELECT 1 RESOURCE; +SELECT 1 RESPECT; +SELECT 1 RESTART; +SELECT 1 RESTRICT; +SELECT 1 RESULT; +SELECT 1 RETURN; +SELECT 1 RETURNED_SQLSTATE; +SELECT 1 RETURNS; +SELECT 1 REUSE; +SELECT 1 REVOKE; +SELECT 1 RIGHT; +SELECT 1 ROLE; +SELECT 1 ROLES; +SELECT 1 ROLLBACK; +SELECT 1 ROLLUP; +SELECT 1 ROTATE; +SELECT 1 ROTATION; +SELECT 1 ROW; +SELECT 1 ROW_COUNT; +SELECT 1 ROWNUM; +SELECT 1 ROWS; +SELECT 1 ROWTYPE; +SELECT 1 RULE; +SELECT 1 SAMPLE; +SELECT 1 SAVEPOINT; +SELECT 1 SCHEDULE; +SELECT 1 SCHEMA; +SELECT 1 SCHEMA_NAME; +SELECT 1 SCROLL; +SELECT 1 SEARCH; +SELECT 1 SECURITY; +SELECT 1 SELF; +SELECT 1 SEPARATOR; +SELECT 1 SEQUENCE; +SELECT 1 SEQUENCES; +SELECT 1 SERIALIZABLE; +SELECT 1 SERVER; +SELECT 1 SESSION; +SELECT 1 SESSION_USER; +SELECT 1 SET; +SELECT 1 SETOF; +SELECT 1 SETS; +SELECT 1 SHARE; +SELECT 1 SHIPPABLE; +SELECT 1 SHOW; +SELECT 1 SHRINK; +SELECT 1 SHUTDOWN; +SELECT 1 SIBLINGS; +SELECT 1 SIMILAR; +SELECT 1 SIMPLE; +SELECT 1 SIZE; +SELECT 1 SKIP; +SELECT 1 SLAVE; +SELECT 1 SLICE; +SELECT 1 SMALLDATETIME; +SELECT 1 SMALLDATETIME_FORMAT; +SELECT 1 SMALLINT; +SELECT 1 SNAPSHOT; +SELECT 1 SOME; +SELECT 1 SOURCE; +SELECT 1 SPACE; +SELECT 1 SPECIFICATION; +SELECT 1 SPILL; +SELECT 1 SPLIT; +SELECT 1 SQL; +SELECT 1 STABLE; +SELECT 1 STACKED; +SELECT 1 STANDALONE; +SELECT 1 START; +SELECT 1 STARTING; +SELECT 1 STARTS; +SELECT 1 STATEMENT; +SELECT 1 STATEMENT_ID; +SELECT 1 STATIC; +SELECT 1 STATISTICS; +SELECT 1 STDIN; +SELECT 1 STDOUT; +SELECT 1 STORAGE; +SELECT 1 STORE; +SELECT 1 STORED; +SELECT 1 STRATIFY; +SELECT 1 STREAM; +SELECT 1 STRICT; +SELECT 1 STRIP; +SELECT 1 SUBCLASS_ORIGIN; +SELECT 1 SUBPARTITION; +SELECT 1 SUBPARTITIONS; +SELECT 1 SUBSCRIPTION; +SELECT 1 SUBSTRING; +SELECT 1 SYMMETRIC; +SELECT 1 SYNONYM; +SELECT 1 SYS_REFCURSOR; +SELECT 1 SYSDATE; +SELECT 1 SYSID; +SELECT 1 SYSTEM; +SELECT 1 TABLE; +SELECT 1 TABLE_NAME; +SELECT 1 TABLES; +SELECT 1 TABLESAMPLE; +SELECT 1 TABLESPACE; +SELECT 1 TEMP; +SELECT 1 TEMPLATE; +SELECT 1 TEMPORARY; +SELECT 1 TERMINATED; +SELECT 1 TEXT; +SELECT 1 THAN; +SELECT 1 THEN; +SELECT 1 TIES; +SELECT 1 TIME; +SELECT 1 TIME_FORMAT; +SELECT 1 TIMECAPSULE; +SELECT 1 TIMESTAMP; +SELECT 1 TIMESTAMP_FORMAT; +SELECT 1 TIMESTAMPDIFF; +SELECT 1 TIMEZONE_HOUR; +SELECT 1 TIMEZONE_MINUTE; +SELECT 1 TINYINT; +SELECT 1 TSQL_TOP; +SELECT 1 TRAILING; +SELECT 1 TRANSACTION; +SELECT 1 TRANSFORM; +SELECT 1 TREAT; +SELECT 1 TRIGGER; +SELECT 1 TRIM; +SELECT 1 TRUE; +SELECT 1 TRUNCATE; +SELECT 1 TRUSTED; +SELECT 1 TSFIELD; +SELECT 1 TSTAG; +SELECT 1 TSTIME; +SELECT 1 TYPES; +SELECT 1 UNBOUNDED; +SELECT 1 UNCOMMITTED; +SELECT 1 UNDER; +SELECT 1 UNENCRYPTED; +SELECT 1 UNIMCSTORED; +SELECT 1 UNIQUE; +SELECT 1 UNKNOWN; +SELECT 1 UNLIMITED; +SELECT 1 UNLISTEN; +SELECT 1 UNLOCK; +SELECT 1 UNLOGGED; +SELECT 1 UNTIL; +SELECT 1 UNUSABLE; +SELECT 1 UPDATE; +SELECT 1 USE; +SELECT 1 USEEOF; +SELECT 1 USER; +SELECT 1 USING; +SELECT 1 VACUUM; +SELECT 1 VALID; +SELECT 1 VALIDATE; +SELECT 1 VALIDATION; +SELECT 1 VALIDATOR; +SELECT 1 VALUES; +SELECT 1 VARCHAR; +SELECT 1 VARCHAR2; +SELECT 1 VARIABLES; +SELECT 1 VARIADIC; +SELECT 1 VARRAY; +SELECT 1 VCGROUP; +SELECT 1 VERBOSE; +SELECT 1 VERIFY; +SELECT 1 VERSION; +SELECT 1 VIEW; +SELECT 1 VISIBLE; +SELECT 1 VOLATILE; +SELECT 1 WAIT; +SELECT 1 WARNINGS; +SELECT 1 WEAK; +SELECT 1 WHEN; +SELECT 1 WHILE; +SELECT 1 WHITESPACE; +SELECT 1 WORK; +SELECT 1 WORKLOAD; +SELECT 1 WRAPPER; +SELECT 1 WRITE; +SELECT 1 XMLATTRIBUTES; +SELECT 1 XMLCONCAT; +SELECT 1 XMLELEMENT; +SELECT 1 XMLEXISTS; +SELECT 1 XMLFOREST; +SELECT 1 XMLPARSE; +SELECT 1 XMLPI; +SELECT 1 XMLROOT; +SELECT 1 XMLSERIALIZE; +SELECT 1 YEAR_MONTH; +SELECT 1 YES; +SELECT 1 ZONE; + +reset current_schema; +drop schema if exists test_ddl_and_dml cascade; \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index d00edd8857..b284521b6a 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -1,7 +1,12 @@ %type tsql_stmtmulti %type DBCCCheckIdentStmt DBCCStmt tsql_stmt tsql_CreateProcedureStmt tsql_IndexStmt -%token CHECKIDENT DBCC NO_INFOMSGS NORESEED RESEED TSQL_CLUSTERED TSQL_NONCLUSTERED TSQL_COLUMNSTORE +%token CHECKIDENT DBCC NO_INFOMSGS NORESEED RESEED TSQL_CLUSTERED TSQL_NONCLUSTERED TSQL_COLUMNSTORE TSQL_PERSISTED TSQL_TOP TSQL_PERCENT %type tsql_opt_clustered tsql_opt_columnstore %token TSQL_ATAT_IDENT %type opt_with_no_infomsgs +%type TSQL_computed_column +%type tsql_top_clause tsql_select_top_value +%type tsql_opt_ties tsql_opt_percent +%type DirectColLabel +%type direct_label_keyword diff --git a/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens b/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens index e69de29bb2..8bb73b236e 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens +++ b/contrib/shark/src/backend_parser/gram-tsql-nonassoc-ident-tokens @@ -0,0 +1 @@ +TSQL_PERSISTED /* these tokens can follow b_expr. To resolve ambiguity, we need to assign the same priority with IDENT. please see the comment in gram.y for details */ \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index 3d4c9784fb..2edd3196b4 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -508,7 +508,8 @@ unreserved_keyword: | NORESEED | RESEED | TSQL_CLUSTERED - | TSQL_NONCLUSTERED ; + | TSQL_NONCLUSTERED + | TSQL_PERSISTED ; DBCCCheckIdentStmt: @@ -788,3 +789,836 @@ func_expr_common_subexpr: $$ = (Node *)makeFuncCall(TsqlSystemFuncName2(name), NIL, @1); } ; + +columnDef: + ColId TSQL_computed_column ColQualList + { + ColumnDef *n = makeNode(ColumnDef); + n->colname = $1; + /* + * For computed columns, user doesn't provide a datatype. + * But, PG expects a datatype. Hence, we just assign a + * valid datatype temporarily. Later, we'll evaluate + * expression to detect the actual datatype. + */ + n->typname = makeTypeName("varchar"); + n->inhcount = 0; + n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collOid = InvalidOid; + n->fdwoptions = NULL; + + $3 = lappend($3, $2); + SplitColQualList($3, &n->constraints, &n->collClause, &n->clientLogicColumnRef, yyscanner); + + $$ = (Node *)n; + } + ; + +/* + * Computed columns uses b_expr not a_expr to avoid conflict with general NOT + * (used in constraints). Besides, it seems TSQL doesn't allow AND, NOT, IS + * IN clauses in the computed column expression. So, there shouldn't be + * any issues. + */ +TSQL_computed_column: + AS b_expr + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_GENERATED; + n->generated_when = ATTRIBUTE_GENERATED_PERSISTED; + n->raw_expr = $2; + n->cooked_expr = NULL; + n->location = @1; + + $$ = (Node *)n; + } + | AS b_expr TSQL_PERSISTED + { + Constraint *n = makeNode(Constraint); + + n->contype = CONSTR_GENERATED; + n->generated_when = ATTRIBUTE_GENERATED_PERSISTED; + n->raw_expr = $2; + n->cooked_expr = NULL; + n->location = @1; + + $$ = (Node *)n; + } + ; + +tsql_select_top_value: + SignedIconst { $$ = makeIntConst($1, @1); } + | FCONST { $$ = makeFloatConst($1, @1); } + | '(' a_expr ')' { $$ = $2; } + | select_with_parens + { + /* + * We need a speical grammar for scalar subquery here + * because c_expr (in a_expr) has a rule select_with_parens but we defined the first rule as '(' a_expr ')'. + * In other words, the first rule will be hit only when double parenthesis is used like `SELECT TOP ((select 1)) ...` + */ + SubLink *n = makeNode(SubLink); + n->subLinkType = EXPR_SUBLINK; + n->testexpr = NULL; + n->operName = NIL; + n->subselect = $1; + n->location = @1; + $$ = (Node *)n; + } + ; + +tsql_opt_ties: + WITH TIES { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + +tsql_opt_percent: + TSQL_PERCENT { $$ = true; } + | /*EMPTY*/ { $$ = false; } + ; + +tsql_top_clause: + TSQL_TOP tsql_select_top_value tsql_opt_percent tsql_opt_ties + { + FetchLimit *result = (FetchLimit *)palloc0(sizeof(FetchLimit)); + result->limitOffset = NULL; + result->limitCount = $2; + result->isPercent = $3; + result->isWithTies = $4; + result->isFetch = true; + $$ = (Node *)result; + } + ; + +simple_select: + SELECT hint_string opt_distinct tsql_top_clause target_list + opt_into_clause from_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = $3; + + FetchLimit* topClause = (FetchLimit*)$4; + if (n->limitCount) { + const char* message = "multiple OFFSET clauses not allowed"; + InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple LIMIT clauses not allowed"), + parser_errposition(exprLocation(topClause->limitCount)))); + } + n->limitCount = topClause->limitCount; + n->isFetch = topClause->isFetch; + n->limitIsPercent = topClause->isPercent; + n->limitWithTies = topClause->isWithTies; + + n->targetList = $5; + n->intoClause = $6; + n->fromClause = $7; + n->whereClause = $8; + n->groupClause = $9; + n->havingClause = $10; + n->windowClause = $11; + n->hintState = create_hintstate($2); + n->hasPlus = getOperatorPlusFlag(); + $$ = (Node *)n; + } + ; + +/* Direct column label --- names that can be column labels without writing "AS". + * This classification is orthogonal to the other keyword categories. + */ +DirectColLabel: IDENT { $$ = $1; } + | direct_label_keyword { $$ = pstrdup($1); } + ; + +/* + * While all keywords can be used as column labels when preceded by AS, + * not all of them can be used as a "direct" column label without AS. + * Those that can be used as a direct label must be listed here, + * in addition to appearing in one of the category lists above. + * + * Always add a new keyword to this list if possible. Mark it DIRECT_LABEL + * in kwlist.h if it is included here, or AS_LABEL if it is not. + */ +direct_label_keyword: ABORT_P + | ABSOLUTE_P + | ACCESS + | ACCOUNT + | ACTION + | ADD_P + | ADMIN + | AFTER + | AGGREGATE + | ALGORITHM + | ALL + | ALSO + | ALTER + | ALWAYS + | ANALYSE + | ANALYZE + | AND + | ANY + | APP + | APPEND + | APPLY + | ARCHIVE + | ASC + | ASOF_P + | ASSERTION + | ASSIGNMENT + | ASYMMETRIC + | AT + | ATTRIBUTE + | AUDIT + | AUTHID + | AUTHORIZATION + | AUTO_INCREMENT + | AUTOEXTEND + | AUTOMAPPED + | BACKWARD + | BARRIER + | BEFORE + | BEGIN_P + | BEGIN_NON_ANOYBLOCK + | BIGINT + | BINARY + | BINARY_DOUBLE + | BINARY_DOUBLE_INF + | BINARY_DOUBLE_NAN + | BINARY_INTEGER + | BIT + | BLANKS + | BLOB_P + | BLOCKCHAIN + | BODY_P + | BOOLEAN_P + | BOTH + | BUCKETCNT + | BUCKETS + | BUILD + | BYTE_P + | BYTEAWITHOUTORDER + | BYTEAWITHOUTORDERWITHEQUAL + | CACHE + | CALL + | CALLED + | CANCELABLE + | CASCADE + | CASCADED + | CASE + | CAST + | CATALOG_P + | CATALOG_NAME + | CHAIN + | CHANGE + | CHARACTERISTICS + | CHARACTERSET + | CHARSET + | CHECK + | CHECKPOINT + | CLASS + | CLASS_ORIGIN + | CLEAN + | CLIENT + | CLIENT_MASTER_KEY + | CLIENT_MASTER_KEYS + | CLOB + | CLOSE + | CLUSTER + | TSQL_CLUSTERED + | COALESCE + | COLLATE + | COLLATION + | COLUMN + | COLUMN_ENCRYPTION_KEY + | COLUMN_ENCRYPTION_KEYS + | COLUMN_NAME + | COLUMNS + | TSQL_COLUMNSTORE + | COMMENT + | COMMENTS + | COMMIT + | COMMITTED + | COMPACT + | COMPATIBLE_ILLEGAL_CHARS + | COMPILE + | COMPLETE + | COMPLETION + | COMPRESS + | CONCURRENTLY + | CONDITION + | CONFIGURATION + | CONNECT + | CONNECTION + | CONSISTENT + | CONSTANT + | CONSTRAINT + | CONSTRAINT_CATALOG + | CONSTRAINT_NAME + | CONSTRAINT_SCHEMA + | CONSTRAINTS + | CONSTRUCTOR + | CONTENT_P + | CONTINUE_P + | CONTVIEW + | CONVERSION_P + | CONVERT_P + | COORDINATOR + | COORDINATORS + | COPY + | COST + | CROSS + | CSN + | CSV + | CUBE + | CURRENT_P + | CURRENT_CATALOG + | CURRENT_DATE + | CURRENT_ROLE + | CURRENT_SCHEMA + | CURRENT_TIME + | CURRENT_TIMESTAMP + | CURRENT_USER + | CURSOR + | CURSOR_NAME + | CYCLE + | DATA_P + | DATABASE + | DATAFILE + | DATANODE + | DATANODES + | DATATYPE_CL + | DATE_P + | DATE_FORMAT_P + | DAY_HOUR_P + | DAY_MINUTE_P + | DAY_SECOND_P + | DBCC + | DBCOMPATIBILITY_P + | DEALLOCATE + | DEC + | DECIMAL_P + | DECLARE + | DECODE + | DEFAULT + | DEFAULTS + | DEFERRABLE + | DEFERRED + | DEFINER + | DELETE_P + | DELIMITER + | DELIMITERS + | DELTA + | DELTAMERGE + | DENSE_RANK + | DESC + | DETERMINISTIC + | DIAGNOSTICS + | DICTIONARY + | DIRECT + | DIRECTORY + | DISABLE_P + | DISCARD + | DISCONNECT + | DISTINCT + | DISTRIBUTE + | DISTRIBUTION + | DO + | DOCUMENT_P + | DOMAIN_P + | DOUBLE_P + | DROP + | DUMPFILE + | DUPLICATE + | EACH + | ELASTIC + | ELSE + | ENABLE_P + | ENCLOSED + | ENCODING + | ENCRYPTED + | ENCRYPTED_VALUE + | ENCRYPTION + | ENCRYPTION_TYPE + | END_P + | ENDS + | ENFORCED + | ENUM_P + | EOL + | ERROR_P + | ERRORS + | ESCAPE + | ESCAPED + | ESCAPING + | EVENT + | EVENTS + | EVERY + | EXCHANGE + | EXCLUDE + | EXCLUDED + | EXCLUDING + | EXCLUSIVE + | EXECUTE + | EXISTS + | EXPIRED_P + | EXPLAIN + | EXTENSION + | EXTERNAL + | EXTRACT + | FALSE_P + | FAMILY + | FAST + | FEATURES + | FENCED + | FIELDS + | FILEHEADER_P + | FILL_MISSING_FIELDS + | FILLER + | FINAL + | FIRST_P + | FIXED_P + | FLOAT_P + | FOLLOWING + | FOLLOWS_P + | FORCE + | FOREIGN + | FORMATTER + | FORWARD + | FREEZE + | FULL + | FUNCTION + | FUNCTIONS + | GENERATED + | GET + | GLOBAL + | GRANTED + | GREATEST + | GROUPING_P + | GROUPPARENT + | HANDLER + | HDFSDIRECTORY + | HEADER_P + | HOLD + | HOUR_MINUTE_P + | HOUR_SECOND_P + | IDENTIFIED + | IDENTITY_P + | IF_P + | IGNORE + | IGNORE_EXTRA_DATA + | ILIKE + | IMCSTORED + | IMMEDIATE + | IMMUTABLE + | IMPLICIT_P + | IN_P + | INCLUDE + | INCLUDING + | INCREMENT + | INCREMENTAL + | INDEX + | INDEXES + | INFILE + | INFINITE_P + | INHERIT + | INHERITS + | INITIAL_P + | INITIALLY + | INITRANS + | INLINE_P + | INNER_P + | INOUT + | INPUT_P + | INSENSITIVE + | INSERT + | INSTEAD + | INT_P + | INTEGER + | INTERNAL + | INTERVAL + | INVISIBLE + | INVOKER + | IP + | IS + | ISOLATION + | JOIN + | JSON_EXISTS + | KEY + | KEY_PATH + | KEY_STORE + | KILL + | LABEL + | LANGUAGE + | LARGE_P + | LAST_P + | LATERAL_P + | LC_COLLATE_P + | LC_CTYPE_P + | LEADING + | LEAKPROOF + | LEAST + | LEFT + | LESS + | LEVEL + | LIKE + | LINES + | LIST + | LISTEN + | LOAD + | LOCAL + | LOCALTIME + | LOCALTIMESTAMP + | LOCATION + | LOCK_P + | LOCKED + | LOG_P + | LOGGING + | LOGIN_ANY + | LOGIN_FAILURE + | LOGIN_SUCCESS + | LOGOUT + | LOOP + | MAP + | MAPPING + | MASKING + | MASTER + | MATCH + | MATCHED + | MATERIALIZED + | MAXEXTENTS + | MAXSIZE + | MAXTRANS + | MAXVALUE + | MEMBER + | MERGE + | MESSAGE_TEXT + | METHOD + | MINEXTENTS + | MINUTE_SECOND_P + | MINVALUE + | MODE + | MODEL + | MODIFY_P + | MOVE + | MOVEMENT + | MYSQL_ERRNO + | NAMES + | NAN_P + | NATIONAL + | NATURAL + | NCHAR + | NEXT + | NO + | NO_INFOMSGS + | NOCOMPRESS + | NOCYCLE + | NODE + | NOLOGGING + | NOMAXVALUE + | NOMINVALUE + | TSQL_NONCLUSTERED + | NONE + | NORESEED + | NOTHING + | NOTIFY + | NOVALIDATE + | NOWAIT + | NTH_VALUE_P + | NULL_P + | NULLCOLS + | NULLIF + | NULLS_P + | NUMBER_P + | NUMERIC + | NUMSTR + | NVARCHAR + | NVARCHAR2 + | NVL + | OBJECT_P + | OF + | OFF + | OIDS + | ONLY + | OPERATOR + | OPTIMIZATION + | OPTION + | OPTIONALLY + | OPTIONS + | OR + | OUT_P + | OUTER_P + | OUTFILE + | OVERLAY + | OWNED + | OWNER + | PACKAGE + | PACKAGES + | PARALLEL_ENABLE + | PARSER + | PARTIAL + | PARTITION + | PARTITIONS + | PASSING + | PASSWORD + | PCTFREE + | PER_P + | TSQL_PERCENT + | PERFORMANCE + | PERM + | TSQL_PERSISTED + | PIPELINED + | PLACING + | PLAN + | PLANS + | POLICY + | POOL + | POSITION + | PRECEDES_P + | PRECEDING + | PREDICT + | PREFERRED + | PREFIX + | PREPARE + | PREPARED + | PRESERVE + | PRIMARY + | PRIOR + | PRIORER + | PRIVATE + | PRIVILEGE + | PRIVILEGES + | PROCEDURAL + | PROCEDURE + | PROFILE + | PUBLICATION + | PUBLISH + | PURGE + | QUERY + | QUOTE + | RANDOMIZED + | RANGE + | RATIO + | RAW + | READ + | REAL + | REASSIGN + | REBUILD + | RECHECK + | RECURSIVE + | RECYCLEBIN + | REDISANYVALUE + | REF + | REFERENCES + | REFRESH + | REINDEX + | REJECT_P + | RELATIVE_P + | RELEASE + | RELOPTIONS + | REMOTE_P + | REMOVE + | RENAME + | REPEAT + | REPEATABLE + | REPLACE + | REPLICA + | RESEED + | RESET + | RESIZE + | RESOURCE + | RESPECT_P + | RESTART + | RESTRICT + | RESULT + | RETURN + | RETURNED_SQLSTATE + | RETURNS + | REUSE + | REVOKE + | RIGHT + | ROLE + | ROLES + | ROLLBACK + | ROLLUP + | ROTATE + | ROTATION + | ROW + | ROW_COUNT + | ROWNUM + | ROWS + | ROWTYPE_P + | RULE + | SAMPLE + | SAVEPOINT + | SCHEDULE + | SCHEMA + | SCHEMA_NAME + | SCROLL + | SEARCH + | SECURITY + | SELF + | SEPARATOR_P + | SEQUENCE + | SEQUENCES + | SERIALIZABLE + | SERVER + | SESSION + | SESSION_USER + | SET + | SETOF + | SETS + | SHARE + | SHIPPABLE + | SHOW + | SHRINK + | SHUTDOWN + | SIBLINGS + | SIMILAR + | SIMPLE + | SIZE + | SKIP + | SLAVE + | SLICE + | SMALLDATETIME + | SMALLDATETIME_FORMAT_P + | SMALLINT + | SNAPSHOT + | SOME + | SOURCE_P + | SPACE + | SPECIFICATION + | SPILL + | SPLIT + | SQL_P + | STABLE + | STACKED_P + | STANDALONE_P + | START + | STARTING + | STARTS + | STATEMENT + | STATEMENT_ID + | STATIC_P + | STATISTICS + | STDIN + | STDOUT + | STORAGE + | STORE_P + | STORED + | STRATIFY + | STREAM + | STRICT_P + | STRIP_P + | SUBCLASS_ORIGIN + | SUBPARTITION + | SUBPARTITIONS + | SUBSCRIPTION + | SUBSTRING + | SYMMETRIC + | SYNONYM + | SYS_REFCURSOR + | SYSDATE + | SYSID + | SYSTEM_P + | TABLE + | TABLE_NAME + | TABLES + | TABLESAMPLE + | TABLESPACE + | TEMP + | TEMPLATE + | TEMPORARY + | TERMINATED + | TEXT_P + | THAN + | THEN + | TIES + | TIME + | TIME_FORMAT_P + | TIMECAPSULE + | TIMESTAMP + | TIMESTAMP_FORMAT_P + | TIMESTAMPDIFF + | TIMEZONE_HOUR_P + | TIMEZONE_MINUTE_P + | TINYINT + | TSQL_TOP + | TRAILING + | TRANSACTION + | TRANSFORM + | TREAT + | TRIGGER + | TRIM + | TRUE_P + | TRUNCATE + | TRUSTED + | TSFIELD + | TSTAG + | TSTIME + | TYPES_P + | UNBOUNDED + | UNCOMMITTED + | UNDER + | UNENCRYPTED + | UNIMCSTORED + | UNIQUE + | UNKNOWN + | UNLIMITED + | UNLISTEN + | UNLOCK + | UNLOGGED + | UNTIL + | UNUSABLE + | UPDATE + | USE_P + | USEEOF + | USER + | USING + | VACUUM + | VALID + | VALIDATE + | VALIDATION + | VALIDATOR + | VALUES + | VARCHAR + | VARCHAR2 + | VARIABLES + | VARIADIC + | VARRAY + | VCGROUP + | VERBOSE + | VERIFY + | VERSION_P + | VIEW + | VISIBLE + | VOLATILE + | WAIT + | WARNINGS + | WEAK + | WHEN + | WHILE_P + | WHITESPACE_P + | WORK + | WORKLOAD + | WRAPPER + | WRITE + | XMLATTRIBUTES + | XMLCONCAT + | XMLELEMENT + | XMLEXISTS + | XMLFOREST + | XMLPARSE + | XMLPI + | XMLROOT + | XMLSERIALIZE + | YEAR_MONTH_P + | YES_P + | ZONE + ; diff --git a/contrib/shark/src/backend_parser/include.pl b/contrib/shark/src/backend_parser/include.pl index f02ce58246..1ac2c75381 100644 --- a/contrib/shark/src/backend_parser/include.pl +++ b/contrib/shark/src/backend_parser/include.pl @@ -20,6 +20,7 @@ my $in_prologue = 0; my $in_comment = 0; my $brace_indent = 0; my $brace_started = 0; # did prev line start a new brace? +my $prior_can_be_added = 0; while ($line = ) { $line =~ s/\r//g; @@ -59,6 +60,10 @@ while ($line = ) { next; } + if ($line =~ /col_name_keyword_nonambiguous:/) { + $prior_can_be_added = 1; + } + # in higher version of bison, duplicate name-prefix is ignored. replace the name-prefix to pgtsql here. This can be refactored later. if ($line =~ "%name-prefix \"$pg_yy_name_prefix\"") { @@ -67,7 +72,35 @@ while ($line = ) { elsif ($line =~ "#include \"parser/gramparse.h\"") { print "#include \"gramparse.h\"\n" } - else + elsif ($line =~ /\| a_expr IDENT\n/) { + print "| a_expr DirectColLabel\n" + } + elsif ($line =~ /\| PRECISION\n/ && $prior_can_be_added == 1) { + $prior_can_be_added = 0; + print "| PRECISION\n| PRIOR\n" + } + # remove postfix expression syntax in D compatibility database + elsif ($line =~ /\| PRIOR\n/ || + $line =~ /%left\s+POSTFIXOP/ || + $line =~ /\| b_expr qual_Op\s+%prec POSTFIXOP/ || + $line =~ /\| a_expr qual_Op\s+%prec POSTFIXOP/ || + $line =~ m{ + \{ \s* + \$\$ \s* = \s* + \( \s* Node \s* \* \s* \) \s* + makeA_Expr \s* + \( \s* + AEXPR_OP \s* , \s* + \$2 \s* , \s* + \$1 \s* , \s* + NULL \s* , \s* + \@2 + \s* \) \s* ; \s* + \} + }x) { + next; + } + else { simple_parse($line, $in_comment, $in_prologue, $brace_indent, $brace_started); #print "in_comment: $in_comment, in_prologue: $in_prologue, brace_indent: $brace_indent, brace_started: $brace_started || "; diff --git a/contrib/shark/src/backend_parser/keywords.cpp b/contrib/shark/src/backend_parser/keywords.cpp index b91371271b..5c726b78a8 100644 --- a/contrib/shark/src/backend_parser/keywords.cpp +++ b/contrib/shark/src/backend_parser/keywords.cpp @@ -9,10 +9,25 @@ /* Keyword categories for SQL keywords */ -#define PG_KEYWORD(kwname, value, category) category, +#define PG_KEYWORD(kwname, value, category, collabel) category, const uint8 pgtsql_ScanKeywordCategories[PGTSQL_SCANKEYWORDS_NUM_KEYWORDS] = { #include "src/backend_parser/kwlist.h" }; #undef PG_KEYWORD + +/* Keyword can-be-direct-label flags for SQL keywords */ + +#define PG_KEYWORD(kwname, value, category, collabel) collabel, + +#define DIRECT_LABEL true +#define AS_LABEL false + +const bool ScanKeywordDirectLabel[PGTSQL_SCANKEYWORDS_NUM_KEYWORDS] = { +#include "src/backend_parser/kwlist.h" +}; + +#undef PG_KEYWORD +#undef DIRECT_LABEL +#undef AS_LABEL \ No newline at end of file diff --git a/contrib/shark/src/backend_parser/kwlist.h b/contrib/shark/src/backend_parser/kwlist.h index 870b65c556..3340ab8c0f 100644 --- a/contrib/shark/src/backend_parser/kwlist.h +++ b/contrib/shark/src/backend_parser/kwlist.h @@ -21,744 +21,745 @@ /* there is deliberately not an #ifndef KWLIST_H here */ /* - * List of keyword (name, token-value, category) entries. + * List of keyword (name, token-value, category, direct-label-status) entries. * * Note: gen_keywordlist.pl requires the entries to appear in ASCII order. */ /* name, value, category */ -PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD) -PG_KEYWORD("account", ACCOUNT, UNRESERVED_KEYWORD) -PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD) -PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD) -PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD) -PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD) -PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD) -PG_KEYWORD("algorithm", ALGORITHM, UNRESERVED_KEYWORD) -PG_KEYWORD("all", ALL, RESERVED_KEYWORD) -PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD) -PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD) -PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD) -PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD) /* British spelling */ -PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD) -PG_KEYWORD("and", AND, RESERVED_KEYWORD) -PG_KEYWORD("any", ANY, RESERVED_KEYWORD) -PG_KEYWORD("app", APP, UNRESERVED_KEYWORD) -PG_KEYWORD("append", APPEND, UNRESERVED_KEYWORD) -PG_KEYWORD("apply", APPLY, UNRESERVED_KEYWORD) -PG_KEYWORD("archive", ARCHIVE, UNRESERVED_KEYWORD) -PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD) -PG_KEYWORD("as", AS, RESERVED_KEYWORD) -PG_KEYWORD("asc", ASC, RESERVED_KEYWORD) -PG_KEYWORD("asof", ASOF_P, UNRESERVED_KEYWORD) -PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD) -PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD) -PG_KEYWORD("at", AT, UNRESERVED_KEYWORD) -PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD) -PG_KEYWORD("audit", AUDIT, UNRESERVED_KEYWORD) -PG_KEYWORD("authid", AUTHID, RESERVED_KEYWORD) -PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("auto_increment", AUTO_INCREMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("autoextend", AUTOEXTEND, UNRESERVED_KEYWORD) -PG_KEYWORD("automapped", AUTOMAPPED, UNRESERVED_KEYWORD) -PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD) +PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("account", ACCOUNT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("algorithm", ALGORITHM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("all", ALL, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, DIRECT_LABEL) /* British spelling */ +PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("and", AND, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("any", ANY, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("app", APP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("append", APPEND, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("apply", APPLY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("archive", ARCHIVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("as", AS, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("asof", ASOF_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("audit", AUDIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("authid", AUTHID, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("auto_increment", AUTO_INCREMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("autoextend", AUTOEXTEND, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("automapped", AUTOMAPPED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, DIRECT_LABEL) #ifdef PGXC -PG_KEYWORD("barrier", BARRIER, UNRESERVED_KEYWORD) +PG_KEYWORD("barrier", BARRIER, UNRESERVED_KEYWORD, DIRECT_LABEL) #endif -PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD) -PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD) -PG_KEYWORD("begin_non_anoyblock", BEGIN_NON_ANOYBLOCK, UNRESERVED_KEYWORD) -PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD) -PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD) -PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("binary_double", BINARY_DOUBLE, COL_NAME_KEYWORD) -PG_KEYWORD("binary_double_infinity", BINARY_DOUBLE_INF, COL_NAME_KEYWORD) -PG_KEYWORD("binary_double_nan", BINARY_DOUBLE_NAN, COL_NAME_KEYWORD) -PG_KEYWORD("binary_integer", BINARY_INTEGER, COL_NAME_KEYWORD) -PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD) -PG_KEYWORD("blanks", BLANKS, UNRESERVED_KEYWORD) -PG_KEYWORD("blob", BLOB_P, UNRESERVED_KEYWORD) -PG_KEYWORD("blockchain", BLOCKCHAIN, UNRESERVED_KEYWORD) -PG_KEYWORD("body", BODY_P, UNRESERVED_KEYWORD) -PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD) -PG_KEYWORD("both", BOTH, RESERVED_KEYWORD) -PG_KEYWORD("bucketcnt", BUCKETCNT, COL_NAME_KEYWORD) -PG_KEYWORD("buckets", BUCKETS, RESERVED_KEYWORD) -PG_KEYWORD("build", BUILD, UNRESERVED_KEYWORD) -PG_KEYWORD("by", BY, UNRESERVED_KEYWORD) -PG_KEYWORD("byte", BYTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("byteawithoutorder", BYTEAWITHOUTORDER, COL_NAME_KEYWORD) -PG_KEYWORD("byteawithoutorderwithequal", BYTEAWITHOUTORDERWITHEQUAL, COL_NAME_KEYWORD) -PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD) -PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD) -PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD) -PG_KEYWORD("cancelable", CANCELABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD) -PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD) -PG_KEYWORD("case", CASE, RESERVED_KEYWORD) -PG_KEYWORD("cast", CAST, RESERVED_KEYWORD) -PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD) -PG_KEYWORD("catalog_name", CATALOG_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD) -PG_KEYWORD("change", CHANGE, UNRESERVED_KEYWORD) -PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD) -PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD) -PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD) -PG_KEYWORD("characterset", CHARACTERSET, UNRESERVED_KEYWORD) -PG_KEYWORD("charset", CHARSET, UNRESERVED_KEYWORD) -PG_KEYWORD("check", CHECK, RESERVED_KEYWORD) -PG_KEYWORD("checkident", CHECKIDENT, UNRESERVED_KEYWORD) -PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD) -PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD) -PG_KEYWORD("class_origin", CLASS_ORIGIN, UNRESERVED_KEYWORD) +PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("begin_non_anoyblock", BEGIN_NON_ANOYBLOCK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("binary_double", BINARY_DOUBLE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("binary_double_infinity", BINARY_DOUBLE_INF, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("binary_double_nan", BINARY_DOUBLE_NAN, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("binary_integer", BINARY_INTEGER, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("blanks", BLANKS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("blob", BLOB_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("blockchain", BLOCKCHAIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("body", BODY_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("bucketcnt", BUCKETCNT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("buckets", BUCKETS, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("build", BUILD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("byte", BYTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("byteawithoutorder", BYTEAWITHOUTORDER, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("byteawithoutorderwithequal", BYTEAWITHOUTORDERWITHEQUAL, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cancelable", CANCELABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("case", CASE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("catalog_name", CATALOG_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("change", CHANGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("characterset", CHARACTERSET, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("charset", CHARSET, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("class_origin", CLASS_ORIGIN, UNRESERVED_KEYWORD, DIRECT_LABEL) #ifdef PGXC -PG_KEYWORD("clean", CLEAN, UNRESERVED_KEYWORD) +PG_KEYWORD("clean", CLEAN, UNRESERVED_KEYWORD, DIRECT_LABEL) #endif -PG_KEYWORD("client", CLIENT, UNRESERVED_KEYWORD) -PG_KEYWORD("client_master_key", CLIENT_MASTER_KEY, UNRESERVED_KEYWORD) -PG_KEYWORD("client_master_keys", CLIENT_MASTER_KEYS, UNRESERVED_KEYWORD) -PG_KEYWORD("clob", CLOB, UNRESERVED_KEYWORD) -PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD) -PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD) -PG_KEYWORD("clustered", TSQL_CLUSTERED, UNRESERVED_KEYWORD) -PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD) -PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD) -PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD) -PG_KEYWORD("column_encryption_key", COLUMN_ENCRYPTION_KEY, UNRESERVED_KEYWORD) -PG_KEYWORD("column_encryption_keys", COLUMN_ENCRYPTION_KEYS, UNRESERVED_KEYWORD) -PG_KEYWORD("column_name", COLUMN_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD) -PG_KEYWORD("columnstore", TSQL_COLUMNSTORE, UNRESERVED_KEYWORD) -PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD) -PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD) -PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD) -PG_KEYWORD("compact", COMPACT, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("compatible_illegal_chars", COMPATIBLE_ILLEGAL_CHARS, UNRESERVED_KEYWORD) -PG_KEYWORD("compile", COMPILE, UNRESERVED_KEYWORD) -PG_KEYWORD("complete", COMPLETE, UNRESERVED_KEYWORD) -PG_KEYWORD("completion", COMPLETION, UNRESERVED_KEYWORD) -PG_KEYWORD("compress", COMPRESS, UNRESERVED_KEYWORD) -PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("condition", CONDITION, UNRESERVED_KEYWORD) -PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD) -PG_KEYWORD("connect", CONNECT, UNRESERVED_KEYWORD) -PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD) -PG_KEYWORD("consistent", CONSISTENT, UNRESERVED_KEYWORD) -PG_KEYWORD("constant", CONSTANT, UNRESERVED_KEYWORD) -PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD) -PG_KEYWORD("constraint_catalog", CONSTRAINT_CATALOG, UNRESERVED_KEYWORD) -PG_KEYWORD("constraint_name", CONSTRAINT_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("constraint_schema", CONSTRAINT_SCHEMA, UNRESERVED_KEYWORD) -PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD) -PG_KEYWORD("constructor", CONSTRUCTOR, UNRESERVED_KEYWORD) -PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("contview", CONTVIEW, UNRESERVED_KEYWORD) -PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD) -PG_KEYWORD("convert", CONVERT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("coordinator", COORDINATOR, UNRESERVED_KEYWORD) -PG_KEYWORD("coordinators", COORDINATORS, UNRESERVED_KEYWORD) -PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD) -PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD) -PG_KEYWORD("create", CREATE, RESERVED_KEYWORD) -PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("csn", CSN, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD) -PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD) -PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD) -PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD) -PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD) -PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD) -PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD) -PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD) -PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD) -PG_KEYWORD("cursor_name", CURSOR_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD) -PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD) -PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD) -PG_KEYWORD("datafile", DATAFILE, UNRESERVED_KEYWORD) -PG_KEYWORD("datanode", DATANODE, UNRESERVED_KEYWORD) -PG_KEYWORD("datanodes", DATANODES, UNRESERVED_KEYWORD) -PG_KEYWORD("datatype_cl", DATATYPE_CL, UNRESERVED_KEYWORD) -PG_KEYWORD("date", DATE_P, COL_NAME_KEYWORD) -PG_KEYWORD("date_format", DATE_FORMAT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD) -PG_KEYWORD("day_hour", DAY_HOUR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("day_minute", DAY_MINUTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("day_second", DAY_SECOND_P, UNRESERVED_KEYWORD) -PG_KEYWORD("dbcc", DBCC, UNRESERVED_KEYWORD) -PG_KEYWORD("dbcompatibility", DBCOMPATIBILITY_P, UNRESERVED_KEYWORD) -PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD) -PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD) -PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD) -PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD) -PG_KEYWORD("decode", DECODE, COL_NAME_KEYWORD) -PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD) -PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD) -PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD) -PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD) -PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD) -PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD) -PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD) -PG_KEYWORD("delta", DELTA, UNRESERVED_KEYWORD) -PG_KEYWORD("deltamerge", DELTAMERGE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("dense_rank", DENSE_RANK, UNRESERVED_KEYWORD) -PG_KEYWORD("desc", DESC, RESERVED_KEYWORD) -PG_KEYWORD("deterministic", DETERMINISTIC, UNRESERVED_KEYWORD) -PG_KEYWORD("diagnostics", DIAGNOSTICS, UNRESERVED_KEYWORD) -PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD) -PG_KEYWORD("direct", DIRECT, UNRESERVED_KEYWORD) -PG_KEYWORD("directory", DIRECTORY, UNRESERVED_KEYWORD) -PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD) -PG_KEYWORD("disconnect", DISCONNECT, UNRESERVED_KEYWORD) -PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD) +PG_KEYWORD("client", CLIENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("client_master_key", CLIENT_MASTER_KEY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("client_master_keys", CLIENT_MASTER_KEYS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("clob", CLOB, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("clustered", TSQL_CLUSTERED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("column_encryption_key", COLUMN_ENCRYPTION_KEY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("column_encryption_keys", COLUMN_ENCRYPTION_KEYS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("column_name", COLUMN_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("columnstore", TSQL_COLUMNSTORE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("compact", COMPACT, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("compatible_illegal_chars", COMPATIBLE_ILLEGAL_CHARS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("compile", COMPILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("complete", COMPLETE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("completion", COMPLETION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("compress", COMPRESS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("condition", CONDITION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("connect", CONNECT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("consistent", CONSISTENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constant", CONSTANT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constraint_catalog", CONSTRAINT_CATALOG, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constraint_name", CONSTRAINT_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constraint_schema", CONSTRAINT_SCHEMA, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("constructor", CONSTRUCTOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("contview", CONTVIEW, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("convert", CONVERT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("coordinator", COORDINATOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("coordinators", COORDINATORS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("csn", CSN, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cursor_name", CURSOR_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("datafile", DATAFILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("datanode", DATANODE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("datanodes", DATANODES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("datatype_cl", DATATYPE_CL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("date", DATE_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("date_format", DATE_FORMAT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("day_hour", DAY_HOUR_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("day_minute", DAY_MINUTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("day_second", DAY_SECOND_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dbcc", DBCC, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dbcompatibility", DBCOMPATIBILITY_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("decode", DECODE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("delta", DELTA, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("deltamerge", DELTAMERGE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dense_rank", DENSE_RANK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("deterministic", DETERMINISTIC, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("diagnostics", DIAGNOSTICS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("direct", DIRECT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("directory", DIRECTORY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("disconnect", DISCONNECT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, DIRECT_LABEL) #ifdef PGXC -PG_KEYWORD("distribute", DISTRIBUTE, UNRESERVED_KEYWORD) -PG_KEYWORD("distribution", DISTRIBUTION, UNRESERVED_KEYWORD) +PG_KEYWORD("distribute", DISTRIBUTE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("distribution", DISTRIBUTION, UNRESERVED_KEYWORD, DIRECT_LABEL) #endif -PG_KEYWORD("do", DO, RESERVED_KEYWORD) -PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD) -PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD) -PG_KEYWORD("dumpfile", DUMPFILE, UNRESERVED_KEYWORD) -PG_KEYWORD("duplicate", DUPLICATE, UNRESERVED_KEYWORD) -PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD) -PG_KEYWORD("elastic", ELASTIC, UNRESERVED_KEYWORD) -PG_KEYWORD("else", ELSE, RESERVED_KEYWORD) -PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("enclosed", ENCLOSED, UNRESERVED_KEYWORD) -PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD) -PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD) -PG_KEYWORD("encrypted_value", ENCRYPTED_VALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("encryption", ENCRYPTION, UNRESERVED_KEYWORD) -PG_KEYWORD("encryption_type", ENCRYPTION_TYPE, UNRESERVED_KEYWORD) -PG_KEYWORD("end", END_P, RESERVED_KEYWORD) -PG_KEYWORD("ends", ENDS, UNRESERVED_KEYWORD) -PG_KEYWORD("enforced", ENFORCED, UNRESERVED_KEYWORD) -PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD) -PG_KEYWORD("eol", EOL, UNRESERVED_KEYWORD) -PG_KEYWORD("error", ERROR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("errors", ERRORS, UNRESERVED_KEYWORD) -PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD) -PG_KEYWORD("escaped", ESCAPED, UNRESERVED_KEYWORD) -PG_KEYWORD("escaping", ESCAPING, UNRESERVED_KEYWORD) -PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD) -PG_KEYWORD("events", EVENTS, UNRESERVED_KEYWORD) -PG_KEYWORD("every", EVERY, UNRESERVED_KEYWORD) -PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD) -PG_KEYWORD("exchange", EXCHANGE, UNRESERVED_KEYWORD) -PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD) +PG_KEYWORD("do", DO, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("dumpfile", DUMPFILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("duplicate", DUPLICATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("elastic", ELASTIC, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("enclosed", ENCLOSED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("encrypted_value", ENCRYPTED_VALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("encryption", ENCRYPTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("encryption_type", ENCRYPTION_TYPE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("end", END_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ends", ENDS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("enforced", ENFORCED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("eol", EOL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("error", ERROR_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("errors", ERRORS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("escaped", ESCAPED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("escaping", ESCAPING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("events", EVENTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("every", EVERY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("exchange", EXCHANGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, DIRECT_LABEL) #ifndef ENABLE_MULTIPLE_NODES -PG_KEYWORD("excluded", EXCLUDED, RESERVED_KEYWORD) +PG_KEYWORD("excluded", EXCLUDED, RESERVED_KEYWORD, DIRECT_LABEL) #endif -PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD) -PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD) -PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD) -PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD) -PG_KEYWORD("expired", EXPIRED_P, UNRESERVED_KEYWORD) -PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD) -PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD) -PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD) -PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD) -PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD) -PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD) -PG_KEYWORD("fast", FAST, UNRESERVED_KEYWORD) -PG_KEYWORD("features", FEATURES, UNRESERVED_KEYWORD) -PG_KEYWORD("fenced", FENCED, UNRESERVED_KEYWORD) -PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD) -PG_KEYWORD("fields", FIELDS, UNRESERVED_KEYWORD) -PG_KEYWORD("fileheader", FILEHEADER_P, UNRESERVED_KEYWORD) -PG_KEYWORD("fill_missing_fields", FILL_MISSING_FIELDS, UNRESERVED_KEYWORD) -PG_KEYWORD("filler", FILLER, UNRESERVED_KEYWORD) -PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD) -PG_KEYWORD("final", FINAL, UNRESERVED_KEYWORD) -PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD) -PG_KEYWORD("fixed", FIXED_P, UNRESERVED_KEYWORD) -PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD) -PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD) -PG_KEYWORD("follows", FOLLOWS_P, UNRESERVED_KEYWORD) -PG_KEYWORD("for", FOR, RESERVED_KEYWORD) -PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD) -PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD) -PG_KEYWORD("formatter", FORMATTER, UNRESERVED_KEYWORD) -PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD) -PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("from", FROM, RESERVED_KEYWORD) -PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD) -PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD) -PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD) -PG_KEYWORD("get", GET, UNRESERVED_KEYWORD) -PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD) -PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD) -PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD) -PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD) -PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD) -PG_KEYWORD("grouping", GROUPING_P, COL_NAME_KEYWORD) -PG_KEYWORD("groupparent", GROUPPARENT, RESERVED_KEYWORD) -PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD) -PG_KEYWORD("having", HAVING, RESERVED_KEYWORD) -PG_KEYWORD("hdfsdirectory", HDFSDIRECTORY, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD) -PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD) -PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("hour_minute", HOUR_MINUTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("hour_second", HOUR_SECOND_P, UNRESERVED_KEYWORD) +PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("expired", EXPIRED_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fast", FAST, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("features", FEATURES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fenced", FENCED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("fields", FIELDS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fileheader", FILEHEADER_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fill_missing_fields", FILL_MISSING_FIELDS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("filler", FILLER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("final", FINAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("fixed", FIXED_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("follows", FOLLOWS_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("for", FOR, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("formatter", FORMATTER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("from", FROM, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("get", GET, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("grouping", GROUPING_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("groupparent", GROUPPARENT, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("hdfsdirectory", HDFSDIRECTORY, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("hour_minute", HOUR_MINUTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("hour_second", HOUR_SECOND_P, UNRESERVED_KEYWORD, DIRECT_LABEL) /* new key-word for ALTER ROLE */ -PG_KEYWORD("identified", IDENTIFIED, UNRESERVED_KEYWORD) -PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD) -PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD) -PG_KEYWORD("ignore", IGNORE, UNRESERVED_KEYWORD) -PG_KEYWORD("ignore_extra_data", IGNORE_EXTRA_DATA, UNRESERVED_KEYWORD) -PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("imcstored", IMCSTORED, RESERVED_KEYWORD) -PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD) -PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("in", IN_P, RESERVED_KEYWORD) -PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD) -PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD) -PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("incremental", INCREMENTAL, UNRESERVED_KEYWORD) -PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD) -PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD) -PG_KEYWORD("infile", INFILE, UNRESERVED_KEYWORD) -PG_KEYWORD("infinite", INFINITE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD) -PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD) -PG_KEYWORD("initial", INITIAL_P, UNRESERVED_KEYWORD) -PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD) -PG_KEYWORD("initrans", INITRANS, UNRESERVED_KEYWORD) -PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD) -PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD) -PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD) -PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD) -PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD) -PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD) -PG_KEYWORD("internal", INTERNAL, UNRESERVED_KEYWORD) -PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD) -PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD) -PG_KEYWORD("into", INTO, RESERVED_KEYWORD) -PG_KEYWORD("invisible", INVISIBLE, UNRESERVED_KEYWORD) -PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD) -PG_KEYWORD("ip", IP, UNRESERVED_KEYWORD) -PG_KEYWORD("is", IS, RESERVED_KEYWORD) -PG_KEYWORD("isnull", ISNULL, UNRESERVED_KEYWORD) -PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD) -PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("json_exists", JSON_EXISTS, COL_NAME_KEYWORD) -PG_KEYWORD("keep", KEEP, UNRESERVED_KEYWORD) -PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) -PG_KEYWORD("key_path", KEY_PATH, UNRESERVED_KEYWORD) -PG_KEYWORD("key_store", KEY_STORE, UNRESERVED_KEYWORD) -PG_KEYWORD("kill", KILL, UNRESERVED_KEYWORD) -PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) -PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) -PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD) -PG_KEYWORD("lateral", LATERAL_P, UNRESERVED_KEYWORD) -PG_KEYWORD("lc_collate", LC_COLLATE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD) -PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD) -PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD) -PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("less", LESS, RESERVED_KEYWORD) -PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD) -PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD) -PG_KEYWORD("lines", LINES, UNRESERVED_KEYWORD) -PG_KEYWORD("list", LIST, UNRESERVED_KEYWORD) -PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD) -PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD) -PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD) -PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD) -PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD) -PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD) -PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD) -PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD) -PG_KEYWORD("log", LOG_P, UNRESERVED_KEYWORD) -PG_KEYWORD("logging", LOGGING, UNRESERVED_KEYWORD) -PG_KEYWORD("login_any", LOGIN_ANY, UNRESERVED_KEYWORD) -PG_KEYWORD("login_failure", LOGIN_FAILURE, UNRESERVED_KEYWORD) -PG_KEYWORD("login_success", LOGIN_SUCCESS, UNRESERVED_KEYWORD) -PG_KEYWORD("logout", LOGOUT, UNRESERVED_KEYWORD) -PG_KEYWORD("loop", LOOP, UNRESERVED_KEYWORD) -PG_KEYWORD("map", MAP, UNRESERVED_KEYWORD) -PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD) -PG_KEYWORD("masking", MASKING, UNRESERVED_KEYWORD) -PG_KEYWORD("master", MASTER, UNRESERVED_KEYWORD) -PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD) -PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD) -PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD) -PG_KEYWORD("maxextents", MAXEXTENTS, UNRESERVED_KEYWORD) -PG_KEYWORD("maxsize", MAXSIZE, UNRESERVED_KEYWORD) -PG_KEYWORD("maxtrans", MAXTRANS, UNRESERVED_KEYWORD) -PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("member", MEMBER, UNRESERVED_KEYWORD) -PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD) -PG_KEYWORD("message_text", MESSAGE_TEXT, UNRESERVED_KEYWORD) -PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD) -PG_KEYWORD("minextents", MINEXTENTS, UNRESERVED_KEYWORD) -PG_KEYWORD("minus", MINUS_P, RESERVED_KEYWORD) -PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("minute_second", MINUTE_SECOND_P, UNRESERVED_KEYWORD) -PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD) -PG_KEYWORD("model", MODEL, UNRESERVED_KEYWORD) -PG_KEYWORD("modify", MODIFY_P, RESERVED_KEYWORD) -PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD) -PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD) -PG_KEYWORD("movement", MOVEMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("mysql_errno", MYSQL_ERRNO, UNRESERVED_KEYWORD) -PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD) -PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD) -PG_KEYWORD("nan", NAN_P, UNRESERVED_KEYWORD) -PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD) -PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD) -PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD) -PG_KEYWORD("no", NO, UNRESERVED_KEYWORD) -PG_KEYWORD("no_infomsgs", NO_INFOMSGS, UNRESERVED_KEYWORD) -PG_KEYWORD("nocompress", NOCOMPRESS, UNRESERVED_KEYWORD) -PG_KEYWORD("nocycle", NOCYCLE, RESERVED_KEYWORD) +PG_KEYWORD("identified", IDENTIFIED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ignore", IGNORE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ignore_extra_data", IGNORE_EXTRA_DATA, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("imcstored", IMCSTORED, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("incremental", INCREMENTAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("infile", INFILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("infinite", INFINITE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("initial", INITIAL_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("initrans", INITRANS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("internal", INTERNAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("into", INTO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("invisible", INVISIBLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ip", IP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("is", IS, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("isnull", ISNULL, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("json_exists", JSON_EXISTS, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("keep", KEEP, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("key_path", KEY_PATH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("key_store", KEY_STORE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("kill", KILL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("lateral", LATERAL_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("lc_collate", LC_COLLATE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("less", LESS, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("lines", LINES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("list", LIST, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("log", LOG_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("logging", LOGGING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("login_any", LOGIN_ANY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("login_failure", LOGIN_FAILURE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("login_success", LOGIN_SUCCESS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("logout", LOGOUT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("loop", LOOP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("map", MAP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("masking", MASKING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("master", MASTER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("maxextents", MAXEXTENTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("maxsize", MAXSIZE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("maxtrans", MAXTRANS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("member", MEMBER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("message_text", MESSAGE_TEXT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("minextents", MINEXTENTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("minus", MINUS_P, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("minute_second", MINUTE_SECOND_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("model", MODEL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("modify", MODIFY_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("movement", MOVEMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("mysql_errno", MYSQL_ERRNO, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nan", NAN_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("no_infomsgs", NO_INFOMSGS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nocompress", NOCOMPRESS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nocycle", NOCYCLE, RESERVED_KEYWORD, DIRECT_LABEL) #ifdef PGXC -PG_KEYWORD("node", NODE, UNRESERVED_KEYWORD) +PG_KEYWORD("node", NODE, UNRESERVED_KEYWORD, DIRECT_LABEL) #endif -PG_KEYWORD("nologging", NOLOGGING, UNRESERVED_KEYWORD) -PG_KEYWORD("nomaxvalue", NOMAXVALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("nominvalue", NOMINVALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("nonclustered", TSQL_NONCLUSTERED, UNRESERVED_KEYWORD) -PG_KEYWORD("none", NONE, COL_NAME_KEYWORD) -PG_KEYWORD("noreseed", NORESEED, UNRESERVED_KEYWORD) -PG_KEYWORD("not", NOT, RESERVED_KEYWORD) -PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD) -PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD) -PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("novalidate", NOVALIDATE, UNRESERVED_KEYWORD) -PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD) -PG_KEYWORD("nth_value", NTH_VALUE_P, COL_NAME_KEYWORD) -PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD) -PG_KEYWORD("nullcols", NULLCOLS, UNRESERVED_KEYWORD) -PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD) -PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD) -PG_KEYWORD("number", NUMBER_P, COL_NAME_KEYWORD) -PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD) -PG_KEYWORD("numstr", NUMSTR, UNRESERVED_KEYWORD) -PG_KEYWORD("nvarchar", NVARCHAR, COL_NAME_KEYWORD) -PG_KEYWORD("nvarchar2", NVARCHAR2, COL_NAME_KEYWORD) -PG_KEYWORD("nvl", NVL, COL_NAME_KEYWORD) -PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("of", OF, UNRESERVED_KEYWORD) -PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD) -PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD) -PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD) -PG_KEYWORD("on", ON, RESERVED_KEYWORD) -PG_KEYWORD("only", ONLY, RESERVED_KEYWORD) -PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD) -PG_KEYWORD("optimization", OPTIMIZATION, UNRESERVED_KEYWORD) -PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD) -PG_KEYWORD("optionally", OPTIONALLY, UNRESERVED_KEYWORD) -PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD) -PG_KEYWORD("or", OR, RESERVED_KEYWORD) -PG_KEYWORD("order", ORDER, RESERVED_KEYWORD) -PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD) -PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("outfile", OUTFILE, UNRESERVED_KEYWORD) -PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD) -PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD) -PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD) -PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD) -PG_KEYWORD("package", PACKAGE, UNRESERVED_KEYWORD) -PG_KEYWORD("packages", PACKAGES, UNRESERVED_KEYWORD) -PG_KEYWORD("parallel_enable", PARALLEL_ENABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD) -PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD) -PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD) -PG_KEYWORD("partitions", PARTITIONS, UNRESERVED_KEYWORD) -PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD) -PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD) -PG_KEYWORD("pctfree", PCTFREE, UNRESERVED_KEYWORD) -PG_KEYWORD("per", PER_P, UNRESERVED_KEYWORD) -PG_KEYWORD("percent", PERCENT, UNRESERVED_KEYWORD) -PG_KEYWORD("performance", PERFORMANCE, RESERVED_KEYWORD) -PG_KEYWORD("perm", PERM, UNRESERVED_KEYWORD) -PG_KEYWORD("pipelined", PIPELINED, UNRESERVED_KEYWORD) -PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD) -PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD) -PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD) -PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD) -PG_KEYWORD("pool", POOL, UNRESERVED_KEYWORD) -PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD) -PG_KEYWORD("precedes", PRECEDES_P, UNRESERVED_KEYWORD) -PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD) -PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD) -PG_KEYWORD("predict", PREDICT, UNRESERVED_KEYWORD) +PG_KEYWORD("nologging", NOLOGGING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nomaxvalue", NOMAXVALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nominvalue", NOMINVALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nonclustered", TSQL_NONCLUSTERED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("noreseed", NORESEED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("not", NOT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("novalidate", NOVALIDATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nth_value", NTH_VALUE_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nullcols", NULLCOLS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("number", NUMBER_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("numstr", NUMSTR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nvarchar", NVARCHAR, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nvarchar2", NVARCHAR2, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("nvl", NVL, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("on", ON, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("optimization", OPTIMIZATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("optionally", OPTIONALLY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("or", OR, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("outfile", OUTFILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("package", PACKAGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("packages", PACKAGES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("parallel_enable", PARALLEL_ENABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("partitions", PARTITIONS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("pctfree", PCTFREE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("per", PER_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("percent", TSQL_PERCENT, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("performance", PERFORMANCE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("perm", PERM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("persisted", TSQL_PERSISTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("pipelined", PIPELINED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("plan", PLAN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("pool", POOL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("precedes", PRECEDES_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("predict", PREDICT, UNRESERVED_KEYWORD, DIRECT_LABEL) /* PGXC_BEGIN */ -PG_KEYWORD("preferred", PREFERRED, UNRESERVED_KEYWORD) +PG_KEYWORD("preferred", PREFERRED, UNRESERVED_KEYWORD, DIRECT_LABEL) /* PGXC_END */ -PG_KEYWORD("prefix", PREFIX, UNRESERVED_KEYWORD) -PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD) -PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD) -PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD) -PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD) -PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD) -PG_KEYWORD("priorer", PRIORER, UNRESERVED_KEYWORD) -PG_KEYWORD("private", PRIVATE, UNRESERVED_KEYWORD) -PG_KEYWORD("privilege", PRIVILEGE, UNRESERVED_KEYWORD) -PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD) -PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD) -PG_KEYWORD("procedure", PROCEDURE, RESERVED_KEYWORD) -PG_KEYWORD("profile", PROFILE, UNRESERVED_KEYWORD) -PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD) -PG_KEYWORD("publish", PUBLISH, UNRESERVED_KEYWORD) -PG_KEYWORD("purge", PURGE, UNRESERVED_KEYWORD) -PG_KEYWORD("query", QUERY, UNRESERVED_KEYWORD) -PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD) -PG_KEYWORD("randomized", RANDOMIZED, UNRESERVED_KEYWORD) -PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD) -PG_KEYWORD("ratio", RATIO, UNRESERVED_KEYWORD) -PG_KEYWORD("raw", RAW, UNRESERVED_KEYWORD) -PG_KEYWORD("read", READ, UNRESERVED_KEYWORD) -PG_KEYWORD("real", REAL, COL_NAME_KEYWORD) -PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD) -PG_KEYWORD("rebuild", REBUILD, UNRESERVED_KEYWORD) -PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD) -PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD) -PG_KEYWORD("recyclebin", RECYCLEBIN, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("redisanyvalue", REDISANYVALUE, UNRESERVED_KEYWORD) -PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD) -PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD) -PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD) -PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD) -PG_KEYWORD("reject", REJECT_P, RESERVED_KEYWORD) -PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD) -PG_KEYWORD("reloptions", RELOPTIONS, UNRESERVED_KEYWORD) -PG_KEYWORD("remote", REMOTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("remove", REMOVE, UNRESERVED_KEYWORD) -PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD) -PG_KEYWORD("repeat", REPEAT, UNRESERVED_KEYWORD) -PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD) -PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD) -PG_KEYWORD("reseed", RESEED, UNRESERVED_KEYWORD) -PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD) -PG_KEYWORD("resize", RESIZE, UNRESERVED_KEYWORD) -PG_KEYWORD("resource", RESOURCE, UNRESERVED_KEYWORD) -PG_KEYWORD("respect", RESPECT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD) -PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD) -PG_KEYWORD("result", RESULT, UNRESERVED_KEYWORD) -PG_KEYWORD("return", RETURN, UNRESERVED_KEYWORD) -PG_KEYWORD("returned_sqlstate", RETURNED_SQLSTATE, UNRESERVED_KEYWORD) -PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD) -PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD) -PG_KEYWORD("reuse", REUSE, UNRESERVED_KEYWORD) -PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD) -PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD) -PG_KEYWORD("roles", ROLES, UNRESERVED_KEYWORD) -PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD) -PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD) -PG_KEYWORD("rotate", ROTATE, UNRESERVED_KEYWORD) -PG_KEYWORD("rotation", ROTATION, UNRESERVED_KEYWORD) -PG_KEYWORD("row", ROW, COL_NAME_KEYWORD) -PG_KEYWORD("row_count", ROW_COUNT, UNRESERVED_KEYWORD) -PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD) -PG_KEYWORD("rowtype", ROWTYPE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD) -PG_KEYWORD("sample", SAMPLE, UNRESERVED_KEYWORD) -PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD) -PG_KEYWORD("schedule", SCHEDULE, UNRESERVED_KEYWORD) -PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD) -PG_KEYWORD("schema_name", SCHEMA_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD) -PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD) -PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD) -PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD) -PG_KEYWORD("select", SELECT, RESERVED_KEYWORD) -PG_KEYWORD("self", SELF, RESERVED_KEYWORD) -PG_KEYWORD("separator", SEPARATOR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD) -PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD) -PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD) -PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD) -PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD) -PG_KEYWORD("set", SET, UNRESERVED_KEYWORD) -PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD) -PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD) -PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD) -PG_KEYWORD("shippable", SHIPPABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD) -PG_KEYWORD("shrink", SHRINK, RESERVED_KEYWORD) -PG_KEYWORD("shutdown", SHUTDOWN, UNRESERVED_KEYWORD) -PG_KEYWORD("siblings", SIBLINGS, UNRESERVED_KEYWORD) -PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD) -PG_KEYWORD("size", SIZE, UNRESERVED_KEYWORD) -PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD) -PG_KEYWORD("slave", SLAVE, UNRESERVED_KEYWORD) -PG_KEYWORD("slice", SLICE, UNRESERVED_KEYWORD) -PG_KEYWORD("smalldatetime", SMALLDATETIME, COL_NAME_KEYWORD) -PG_KEYWORD("smalldatetime_format", SMALLDATETIME_FORMAT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD) -PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD) -PG_KEYWORD("some", SOME, RESERVED_KEYWORD) -PG_KEYWORD("source", SOURCE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("space", SPACE, UNRESERVED_KEYWORD) -PG_KEYWORD("specification", SPECIFICATION, UNRESERVED_KEYWORD) -PG_KEYWORD("spill", SPILL, UNRESERVED_KEYWORD) -PG_KEYWORD("split", SPLIT, UNRESERVED_KEYWORD) -PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD) -PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("stacked", STACKED_P, UNRESERVED_KEYWORD) -PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("start", START, UNRESERVED_KEYWORD) -PG_KEYWORD("starting", STARTING, UNRESERVED_KEYWORD) -PG_KEYWORD("starts", STARTS, UNRESERVED_KEYWORD) -PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD) -PG_KEYWORD("statement_id", STATEMENT_ID, UNRESERVED_KEYWORD) -PG_KEYWORD("static", STATIC_P, UNRESERVED_KEYWORD) -PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD) -PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD) -PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD) -PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD) -PG_KEYWORD("store", STORE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD) -PG_KEYWORD("stratify", STRATIFY, UNRESERVED_KEYWORD) -PG_KEYWORD("stream", STREAM, UNRESERVED_KEYWORD) -PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD) -PG_KEYWORD("subclass_origin", SUBCLASS_ORIGIN, UNRESERVED_KEYWORD) -PG_KEYWORD("subpartition", SUBPARTITION, UNRESERVED_KEYWORD) -PG_KEYWORD("subpartitions", SUBPARTITIONS, UNRESERVED_KEYWORD) -PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD) -PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD) -PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD) -PG_KEYWORD("synonym", SYNONYM, UNRESERVED_KEYWORD) -PG_KEYWORD("sys_refcursor", SYS_REFCURSOR, UNRESERVED_KEYWORD) -PG_KEYWORD("sysdate", SYSDATE, RESERVED_KEYWORD) -PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD) -PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD) -PG_KEYWORD("table", TABLE, RESERVED_KEYWORD) -PG_KEYWORD("table_name", TABLE_NAME, UNRESERVED_KEYWORD) -PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD) -PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD) -PG_KEYWORD("target", TARGET, UNRESERVED_KEYWORD) -PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD) -PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD) -PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD) -PG_KEYWORD("terminated", TERMINATED, UNRESERVED_KEYWORD) -PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("than", THAN, UNRESERVED_KEYWORD) -PG_KEYWORD("then", THEN, RESERVED_KEYWORD) -PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD) -PG_KEYWORD("time", TIME, COL_NAME_KEYWORD) -PG_KEYWORD("time_format", TIME_FORMAT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("timecapsule", TIMECAPSULE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD) -PG_KEYWORD("timestamp_format", TIMESTAMP_FORMAT_P, UNRESERVED_KEYWORD) -PG_KEYWORD("timestampdiff", TIMESTAMPDIFF, COL_NAME_KEYWORD) -PG_KEYWORD("timezone_hour", TIMEZONE_HOUR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("timezone_minute", TIMEZONE_MINUTE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("tinyint", TINYINT, COL_NAME_KEYWORD) -PG_KEYWORD("to", TO, RESERVED_KEYWORD) -PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD) -PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD) -PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD) -PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD) -PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD) -PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD) -PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD) -PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD) -PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD) -PG_KEYWORD("tsfield", TSFIELD, UNRESERVED_KEYWORD) -PG_KEYWORD("tstag", TSTAG, UNRESERVED_KEYWORD) -PG_KEYWORD("tstime", TSTIME, UNRESERVED_KEYWORD) -PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD) -PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD) -PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD) -PG_KEYWORD("under", UNDER, UNRESERVED_KEYWORD) -PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD) -PG_KEYWORD("unimcstored", UNIMCSTORED, RESERVED_KEYWORD) -PG_KEYWORD("union", UNION, RESERVED_KEYWORD) -PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD) -PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD) -PG_KEYWORD("unlimited", UNLIMITED, UNRESERVED_KEYWORD) -PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD) -PG_KEYWORD("unlock", UNLOCK, UNRESERVED_KEYWORD) -PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD) -PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD) -PG_KEYWORD("unusable", UNUSABLE, UNRESERVED_KEYWORD) -PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD) -PG_KEYWORD("use", USE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("useeof", USEEOF, UNRESERVED_KEYWORD) -PG_KEYWORD("user", USER, RESERVED_KEYWORD) -PG_KEYWORD("using", USING, RESERVED_KEYWORD) -PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD) -PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD) -PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD) -PG_KEYWORD("validation", VALIDATION, UNRESERVED_KEYWORD) -PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD) -PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD) -PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD) -PG_KEYWORD("varchar2", VARCHAR2, COL_NAME_KEYWORD) -PG_KEYWORD("variables", VARIABLES, UNRESERVED_KEYWORD) -PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD) -PG_KEYWORD("varray", VARRAY, UNRESERVED_KEYWORD) -PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD) -PG_KEYWORD("vcgroup", VCGROUP, UNRESERVED_KEYWORD) -PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD) -PG_KEYWORD("verify", VERIFY, RESERVED_KEYWORD) -PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD) -PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD) -PG_KEYWORD("visible", VISIBLE, UNRESERVED_KEYWORD) -PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD) -PG_KEYWORD("wait", WAIT, UNRESERVED_KEYWORD) -PG_KEYWORD("warnings", WARNINGS, UNRESERVED_KEYWORD) -PG_KEYWORD("weak", WEAK, UNRESERVED_KEYWORD) -PG_KEYWORD("when", WHEN, RESERVED_KEYWORD) -PG_KEYWORD("where", WHERE, RESERVED_KEYWORD) -PG_KEYWORD("while", WHILE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD) -PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD) -PG_KEYWORD("with", WITH, RESERVED_KEYWORD) -PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD) -PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD) -PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD) -PG_KEYWORD("workload", WORKLOAD, UNRESERVED_KEYWORD) -PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD) -PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD) -PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD) -PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD) -PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD) -PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD) -PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD) -PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD) -PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD) -PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD) -PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD) -PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD) -PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD) -PG_KEYWORD("year_month", YEAR_MONTH_P, UNRESERVED_KEYWORD) -PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD) -PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD) +PG_KEYWORD("prefix", PREFIX, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("priorer", PRIORER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("private", PRIVATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("privilege", PRIVILEGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("procedure", PROCEDURE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("profile", PROFILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("publish", PUBLISH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("purge", PURGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("query", QUERY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("randomized", RANDOMIZED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ratio", RATIO, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("raw", RAW, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rebuild", REBUILD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("recyclebin", RECYCLEBIN, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("redisanyvalue", REDISANYVALUE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reject", REJECT_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reloptions", RELOPTIONS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("remote", REMOTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("remove", REMOVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("repeat", REPEAT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reseed", RESEED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("resize", RESIZE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("resource", RESOURCE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("respect", RESPECT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("result", RESULT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("return", RETURN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("returned_sqlstate", RETURNED_SQLSTATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("reuse", REUSE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("roles", ROLES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rotate", ROTATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rotation", ROTATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("row_count", ROW_COUNT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rowtype", ROWTYPE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sample", SAMPLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("schedule", SCHEDULE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("schema_name", SCHEMA_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("self", SELF, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("separator", SEPARATOR_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("shippable", SHIPPABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("shrink", SHRINK, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("shutdown", SHUTDOWN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("siblings", SIBLINGS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("size", SIZE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("slave", SLAVE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("slice", SLICE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("smalldatetime", SMALLDATETIME, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("smalldatetime_format", SMALLDATETIME_FORMAT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("some", SOME, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("source", SOURCE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("space", SPACE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("specification", SPECIFICATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("spill", SPILL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("split", SPLIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stacked", STACKED_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("start", START, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("starting", STARTING, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("starts", STARTS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("statement_id", STATEMENT_ID, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("static", STATIC_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("store", STORE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stratify", STRATIFY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("stream", STREAM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("subclass_origin", SUBCLASS_ORIGIN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("subpartition", SUBPARTITION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("subpartitions", SUBPARTITIONS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("synonym", SYNONYM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sys_refcursor", SYS_REFCURSOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sysdate", SYSDATE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("table_name", TABLE_NAME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("target", TARGET, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("terminated", TERMINATED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("than", THAN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("then", THEN, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("time_format", TIME_FORMAT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timecapsule", TIMECAPSULE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timestamp_format", TIMESTAMP_FORMAT_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timestampdiff", TIMESTAMPDIFF, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timezone_hour", TIMEZONE_HOUR_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("timezone_minute", TIMEZONE_MINUTE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tinyint", TINYINT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("to", TO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("top", TSQL_TOP, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tsfield", TSFIELD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tstag", TSTAG, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("tstime", TSTIME, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("under", UNDER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unimcstored", UNIMCSTORED, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("union", UNION, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unlimited", UNLIMITED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unlock", UNLOCK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("unusable", UNUSABLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("use", USE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("useeof", USEEOF, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("user", USER, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("using", USING, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("validation", VALIDATION, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("varchar2", VARCHAR2, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("variables", VARIABLES, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("varray", VARRAY, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("vcgroup", VCGROUP, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("verify", VERIFY, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("visible", VISIBLE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("wait", WAIT, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("warnings", WARNINGS, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("weak", WEAK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("while", WHILE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("with", WITH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("workload", WORKLOAD, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("year_month", YEAR_MONTH_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, DIRECT_LABEL) diff --git a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h index 3a5a687b22..93b49fbfea 100644 --- a/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h +++ b/contrib/shark/src/backend_parser/scan-tsql-prologue.l.h @@ -5,7 +5,7 @@ * callers need to pass it to scanner_init, if they are using the * standard keyword list ScanKeywords. */ -#define PG_KEYWORD(kwname, value, category) value, +#define PG_KEYWORD(kwname, value, category, collabel) value, const uint16 pgtsql_ScanKeywordTokens[] = { #include "src/backend_parser/kwlist.h" diff --git a/contrib/shark/src/tablecmds.cpp b/contrib/shark/src/tablecmds.cpp new file mode 100644 index 0000000000..39eba8c6a5 --- /dev/null +++ b/contrib/shark/src/tablecmds.cpp @@ -0,0 +1,454 @@ +/* ------------------------------------------------------------------------- + * + * tablecmds.cpp + * Shark's Commands for creating and altering table structures and settings + * + * Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd. + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 2010-2012 Postgres-XC Development Group + * + * + * IDENTIFICATION + * contrib/shark/src/tablecmds.cpp + * + * ------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "knl/knl_session.h" +#include "access/genam.h" +#include "commands/tablecmds.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "nodes/nodeFuncs.h" +#include "parser/parse_expr.h" +#include "parser/parse_type.h" +#include "parser/parse_collate.h" +#include "catalog/heap.h" +#include "catalog/pg_depend.h" +#include "catalog/pg_attrdef.h" + +typedef struct ComputedColumnContextData +{ + Relation rel; + ParseState *pstate; + List *gen_column_list; +} ComputedColumnContextData; + +typedef ComputedColumnContextData *ComputedColumnContext; + +void assign_tablecmds_hook(void); +static void pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum); +static void pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefaults); +static void pltsql_TransformSelectForLimitHook(SelectStmt* stmt); +static void pltsql_RecomputeLimitsHook(float8 val); +static ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid); +static bool check_nested_computed_column(Node *node, void *context); +static bool IsComputedColumn(Oid adrelid, int2 asnum); + +/* Hook to tablecmds.cpp in the engine */ +static void* prev_InvokePreDropColumnHook = NULL; +static void* prev_InvokePreAddConstraintsHook = NULL; +static void* prev_InvokeTransformSelectForLimitHook = NULL; +static void* prev_RecomputeLimitsHook = NULL; + +void assign_tablecmds_hook(void) +{ + if (u_sess->hook_cxt.invokePreDropColumnHook) { + prev_InvokePreDropColumnHook = u_sess->hook_cxt.invokePreDropColumnHook; + } + u_sess->hook_cxt.invokePreDropColumnHook = (void*)&pltsql_PreDropColumnHook; + + if (u_sess->hook_cxt.invokePreAddConstraintsHook) { + prev_InvokePreAddConstraintsHook = u_sess->hook_cxt.invokePreAddConstraintsHook; + } + u_sess->hook_cxt.invokePreAddConstraintsHook = (void*)&pltsql_PreAddConstraintsHook; + + if (u_sess->hook_cxt.invokeTransformSelectForLimitHook) { + prev_InvokeTransformSelectForLimitHook = u_sess->hook_cxt.invokeTransformSelectForLimitHook; + } + u_sess->hook_cxt.invokeTransformSelectForLimitHook = (void*)&pltsql_TransformSelectForLimitHook; + + if (u_sess->hook_cxt.recomputeLimitsHook) { + prev_RecomputeLimitsHook = u_sess->hook_cxt.recomputeLimitsHook; + } + u_sess->hook_cxt.recomputeLimitsHook = (void*)&pltsql_RecomputeLimitsHook; +} + +static void pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum) +{ + if (!DB_IS_CMPT(D_FORMAT)) { + return; + } + + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple depTup, tuple; + char *schema_name = NULL, + *minor_name = NULL; + + /* Call previous hook if exists */ + if (prev_InvokePreDropColumnHook) { + ((InvokePreDropColumnHookType)(prev_InvokePreDropColumnHook))(rel, attnum); + } + + /* + * Find everything that depends on the column. If we can find a + * computed column dependent on this column, will throw an error. + */ + depRel = relation_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(rel))); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum((int32) attnum)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 3, key); + + while (HeapTupleIsValid(depTup = systable_getnext(scan))) { + Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup); + ObjectAddress foundObject; + + foundObject.classId = foundDep->classid; + foundObject.objectId = foundDep->objid; + foundObject.objectSubId = foundDep->objsubid; + + /* + * Below logic has been taken from backend's ATExecAlterColumnType + * function + */ + if (getObjectClass(&foundObject) == OCLASS_CLASS) { + + if (IsComputedColumn(foundObject.objectId, foundObject.objectSubId) && + (foundObject.objectId != RelationGetRelid(rel) || + foundObject.objectSubId != attnum)) { + Form_pg_attribute att = TupleDescAttr(rel->rd_att, attnum - 1); + + /* + * This must be a reference from the expression of a generated + * column elsewhere in the same table. Dropping the type of a + * column that is used by a generated column is not allowed by + * SQL standard. + */ + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("cannot drop a column used by a generated column"), + errdetail("Column \"%s\" is used by generated column \"%s\".", + NameStr(att->attname), + get_attname(foundObject.objectId, foundObject.objectSubId, false)))); + } + } + } + + systable_endscan(scan); + relation_close(depRel, AccessShareLock); +} + +static void pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefaults) +{ + if (!DB_IS_CMPT(D_FORMAT)) { + return; + } + + ListCell *cell; + Relation attrelation = NULL; + ComputedColumnContext context; + + /* Call previous hook if exists */ + if (prev_InvokePreAddConstraintsHook) { + ((InvokePreAddConstraintsHookType)(prev_InvokePreAddConstraintsHook))(rel, pstate, newColDefaults); + } + + /* + * TSQL: Support for computed columns + * + * For a computed column, datatype is not provided by the user. Hence, + * we've to evaluate the computed column expression in order to determine + * the datatype. By now, we should've already made an entry for the + * relatio in the catalog, which means we can execute transformExpr on the + * computed column expression. Once we determine the datatype of the + * column, we'll update the corresponding entry in the catalog. + */ + context = (ComputedColumnContext)palloc0(sizeof(ComputedColumnContextData)); + context->pstate = pstate; + context->rel = rel; + context->gen_column_list = NIL; + + /* + * Collect the names of all computed columns first. We need this in order + * to detect nested computed columns later. + */ + foreach(cell, newColDefaults) { + RawColumnDefault *colDef = (RawColumnDefault *)lfirst(cell); + Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); + + if (colDef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + continue; + } + context->gen_column_list = lappend(context->gen_column_list, + NameStr(atp->attname)); + } + + foreach(cell, newColDefaults) { + RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); + Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); + Node *expr; + Oid targettype; + int32 targettypmod; + HeapTuple heapTup; + Type targetType; + Form_pg_attribute attTup; + Form_pg_type tform; + + /* skip if not a computed column */ + if (colDef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + continue; + } + + + /* + * Since we're using a dummy datatype for a computed column, we need + * to check for a nested computed column usage in the expression + * before evaluating the expression through transformExpr. N.B. When + * we add a new column through ALTER command, it's possible that the + * expression includes another computed column in the table. We'll + * not be able to detetct that case here. That'll be handled later in + * check_nested_generated that works on the executable expression. + */ + Assert(context->gen_column_list != NULL); + check_nested_computed_column(colDef->raw_default, context); + + /* + * transform raw parsetree to executable expression. + */ + expr = transformExpr(pstate, colDef->raw_default, EXPR_KIND_GENERATED_COLUMN); + + /* extract the type and other relevant information */ + targettype = exprType(expr); + targettypmod = exprTypmod(expr); + + /* now update the attribute catalog entry with the correct type */ + if (!RelationIsValid(attrelation)) { + attrelation = relation_open(AttributeRelationId, RowExclusiveLock); + } + + /* Look up the target column */ + heapTup = SearchSysCacheCopyAttNum(RelationGetRelid(rel), colDef->attnum); + if (!HeapTupleIsValid(heapTup)) { /* shouldn't happen */ + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column number %d of relation \"%s\" does not exist", + colDef->attnum, RelationGetRelationName(rel)))); + } + + attTup = (Form_pg_attribute) GETSTRUCT(heapTup); + + targetType = typeidType(targettype); + tform = (Form_pg_type) GETSTRUCT(targetType); + + attTup->atttypid = targettype; + attTup->atttypmod = targettypmod; + + /* + * The target column should already be having a collation associated + * with it due to explicit COLLATE clause If suppose collation is not + * valid or there is no explicit COLLATE clause, we try to find column + * collation from finished expession. + */ + if (!OidIsValid(attTup->attcollation)) { + Oid targetcollid; + + /* take care of collations in the finished expression */ + assign_expr_collations(pstate, expr); + targetcollid = exprCollation(expr); + + if (OidIsValid(targetcollid)) { + attTup->attcollation = targetcollid; + } else { + attTup->attcollation = tform->typcollation; + } + } + + attTup->attndims = tform->typndims; + attTup->attlen = tform->typlen; + attTup->attbyval = tform->typbyval; + attTup->attalign = tform->typalign; + attTup->attstorage = tform->typstorage; + + /* + * Instead of invalidating and refetching the relcache entry, just + * update the entry that we've fetched previously. This works because + * no one else can see our in-progress changes. Also note that we + * only updated the fixed part of Form_pg_attribute. + */ + errno_t rc = memcpy_s(atp, ATTRIBUTE_FIXED_PART_SIZE, attTup, ATTRIBUTE_FIXED_PART_SIZE); + securec_check(rc, "\0", "\0"); + + CatalogTupleUpdate(attrelation, &heapTup->t_self, heapTup); + ReleaseSysCache((HeapTuple) targetType); + + /* Cleanup */ + heap_freetuple(heapTup); + } + + if (RelationIsValid(attrelation)) { + relation_close(attrelation, RowExclusiveLock); + /* Make the updated catalog row versions visible */ + CommandCounterIncrement(); + } + + list_free(context->gen_column_list); + pfree(context); +} + +static void pltsql_TransformSelectForLimitHook(SelectStmt* stmt) +{ + if (DB_IS_CMPT(D_FORMAT) && stmt->limitWithTies && stmt->sortClause == NIL) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmodule(MOD_EXECUTOR), + errmsg("The WITH TIES clause is not allowed without a corresponding ORDER BY clause."))); + } +} + +static void pltsql_RecomputeLimitsHook(float8 val) +{ + if (DB_IS_CMPT(D_FORMAT) && (val < 0 || val > 100)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), + errmodule(MOD_EXECUTOR), + errmsg("Percent values must be between 0 and 100."))); + } +} + +static bool IsComputedColumn(Oid adrelid, int2 asnum) +{ + Relation attrdef; + ScanKeyData keys[2]; + SysScanDesc scan; + HeapTuple tup; + bool res = false; + + attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&keys[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(adrelid)); + ScanKeyInit(&keys[1], + Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, + F_INT2EQ, + Int16GetDatum(asnum)); + scan = systable_beginscan(attrdef, AttrDefaultIndexId, true, NULL, 2, keys); + if (HeapTupleIsValid(tup = systable_getnext(scan))) { + bool isnull = false; + char generatedCol = '\0'; + Datum adgencol = fastgetattr(tup, Anum_pg_attrdef_adgencol, attrdef->rd_att, &isnull); + if (!isnull) { + generatedCol = DatumGetChar(adgencol); + } + res = (generatedCol == ATTRIBUTE_GENERATED_PERSISTED); + } + + systable_endscan(scan); + relation_close(attrdef, AccessShareLock); + return res; +} + +/* + * Given a pg_attrdef OID, return the relation OID and column number of + * the owning column (represented as an ObjectAddress for convenience). + * + * Returns InvalidObjectAddress if there is no such pg_attrdef entry. + */ +static ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid) +{ + ObjectAddress result = InvalidObjectAddress; + Relation attrdef; + ScanKeyData skey[1]; + SysScanDesc scan; + HeapTuple tup; + + attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(attrdefoid)); + scan = systable_beginscan(attrdef, AttrDefaultOidIndexId, true, + NULL, 1, skey); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) { + Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tup); + + result.classId = RelationRelationId; + result.objectId = atdform->adrelid; + result.objectSubId = atdform->adnum; + } + + systable_endscan(scan); + relation_close(attrdef, AccessShareLock); + return result; +} + +static bool check_nested_computed_column(Node *node, void *context) +{ + if (node == NULL) { + return false; + } else if (IsA(node, ColumnRef)) { + ColumnRef *cref = (ColumnRef *)node; + ParseState *pstate = ((ComputedColumnContext) context)->pstate; + + switch (list_length(cref->fields)) { + case 1: { + Node *field1 = (Node *)linitial(cref->fields); + List *colList; + char *col1name; + ListCell *lc; + Relation rel; + + colList = ((ComputedColumnContext)context)->gen_column_list; + rel = ((ComputedColumnContext)context)->rel; + + Assert(IsA(field1, String)); + col1name = strVal(field1); + + foreach(lc, colList) { + char *col2name = (char *)lfirst(lc); + if (strcmp(col1name, col2name) == 0) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("computed column \"%s\" in table \"%s\" is not allowed to " + "be used in another computed-column definition", + col2name, RelationGetRelationName(rel)), + parser_errposition(pstate, cref->location))); + } + } + } break; + default: + + /* + * In CREATE/ALTER TABLE command, the name of the column + * should have only one field. + */ + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("improper column name in CREATE/ALTER TABLE(too many dotted names): %s", + NameListToString(cref->fields)), + parser_errposition(pstate, cref->location))); + } + } + + return raw_expression_tree_walker(node, (bool (*)())check_nested_computed_column, (void*)context); +} \ No newline at end of file diff --git a/src/bin/pg_dump/pg_dump.cpp b/src/bin/pg_dump/pg_dump.cpp index c0cd25e994..b578b57a94 100644 --- a/src/bin/pg_dump/pg_dump.cpp +++ b/src/bin/pg_dump/pg_dump.cpp @@ -20836,51 +20836,53 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo) continue; } - /* Attribute type */ - if ((tbinfo->reloftype != NULL) && !binary_upgrade) { - appendPQExpBuffer(q, "WITH OPTIONS"); - } else if (fout->remoteVersion >= 70100) { - if (isBcompatibility && hasSpecificExtension(fout, "dolphin") && strcmp(tbinfo->atttypnames[j], "numeric") == 0) { - free(tbinfo->atttypnames[j]); - tbinfo->atttypnames[j] = gs_strdup("number"); - } - appendPQExpBuffer(q, "%s", tbinfo->atttypnames[j]); - if (has_encrypted_column) { - char *encryption_type = NULL; - appendPQExpBuffer(q, " encrypted with (column_encryption_key = %s, ", - tbinfo->column_key_names[j]); - if (tbinfo->encryption_type[j] == 2) { - encryption_type = "DETERMINISTIC"; - } else if (tbinfo->encryption_type[j] == 1) { - encryption_type = "RANDOMIZED"; + if (!tbinfo->attrdefs[j] || tbinfo->attrdefs[j]->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + /* Attribute type */ + if ((tbinfo->reloftype != NULL) && !binary_upgrade) { + appendPQExpBuffer(q, "WITH OPTIONS"); + } else if (fout->remoteVersion >= 70100) { + if (isBcompatibility && hasSpecificExtension(fout, "dolphin") && strcmp(tbinfo->atttypnames[j], "numeric") == 0) { + free(tbinfo->atttypnames[j]); + tbinfo->atttypnames[j] = gs_strdup("number"); } - appendPQExpBuffer(q, "encryption_type = %s)", encryption_type); - } - } else { - /* If no format_type, fake it */ - name = myFormatType(tbinfo->atttypnames[j], tbinfo->atttypmod[j]); - appendPQExpBuffer(q, "%s", name); - GS_FREE(name); - } - if (tbinfo->attkvtype[j] != 0) { - if (tbinfo->attkvtype[j] == 1) { - appendPQExpBuffer(q, " %s", "TSTag"); - } else if (tbinfo->attkvtype[j] == 2) { - appendPQExpBuffer(q, " %s", "TSField"); - } else if (tbinfo->attkvtype[j] == 3) { - appendPQExpBuffer(q, " %s", "TSTime"); + appendPQExpBuffer(q, "%s", tbinfo->atttypnames[j]); + if (has_encrypted_column) { + char *encryption_type = NULL; + appendPQExpBuffer(q, " encrypted with (column_encryption_key = %s, ", + tbinfo->column_key_names[j]); + if (tbinfo->encryption_type[j] == 2) { + encryption_type = "DETERMINISTIC"; + } else if (tbinfo->encryption_type[j] == 1) { + encryption_type = "RANDOMIZED"; + } + appendPQExpBuffer(q, "encryption_type = %s)", encryption_type); + } + } else { + /* If no format_type, fake it */ + name = myFormatType(tbinfo->atttypnames[j], tbinfo->atttypmod[j]); + appendPQExpBuffer(q, "%s", name); + GS_FREE(name); } - } + if (tbinfo->attkvtype[j] != 0) { + if (tbinfo->attkvtype[j] == 1) { + appendPQExpBuffer(q, " %s", "TSTag"); + } else if (tbinfo->attkvtype[j] == 2) { + appendPQExpBuffer(q, " %s", "TSField"); + } else if (tbinfo->attkvtype[j] == 3) { + appendPQExpBuffer(q, " %s", "TSTime"); + } + } - /* Add collation if not default for the type */ - if (OidIsValid(tbinfo->attcollation[j])) { - CollInfo* coll = NULL; + /* Add collation if not default for the type */ + if (OidIsValid(tbinfo->attcollation[j])) { + CollInfo* coll = NULL; - coll = findCollationByOid(tbinfo->attcollation[j]); - if (NULL != coll) { - /* always schema-qualify, don't try to be smart */ - appendPQExpBuffer(q, " COLLATE %s.", fmtId(coll->dobj.nmspace->dobj.name)); - appendPQExpBuffer(q, "%s", fmtId(coll->dobj.name)); + coll = findCollationByOid(tbinfo->attcollation[j]); + if (NULL != coll) { + /* always schema-qualify, don't try to be smart */ + appendPQExpBuffer(q, " COLLATE %s.", fmtId(coll->dobj.nmspace->dobj.name)); + appendPQExpBuffer(q, "%s", fmtId(coll->dobj.name)); + } } } @@ -20914,13 +20916,17 @@ static void dumpTableSchema(Archive* fout, TableInfo* tbinfo) default_value = (char *)plaintext; } #endif - if (tbinfo->attrdefs[j]->generatedCol == ATTRIBUTE_GENERATED_STORED) + if (tbinfo->attrdefs[j]->generatedCol == ATTRIBUTE_GENERATED_STORED) { appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED", default_value); - else if (j + 1 == tbinfo->autoinc_attnum) + } else if(tbinfo->attrdefs[j]->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { + appendPQExpBuffer(q, " AS (%s) PERSISTED", + default_value); + } else if (j + 1 == tbinfo->autoinc_attnum) { appendPQExpBuffer(q, " %s", default_value); - else if (pg_strcasecmp(default_value, "") != 0) + } else if (pg_strcasecmp(default_value, "") != 0) { appendPQExpBuffer(q, " DEFAULT %s", default_value); + } if (hasOnUpdateFeature) { RemoveQuotes(onUpdate_value); diff --git a/src/common/backend/catalog/heap.cpp b/src/common/backend/catalog/heap.cpp index e326cdfb46..2dce8cd526 100644 --- a/src/common/backend/catalog/heap.cpp +++ b/src/common/backend/catalog/heap.cpp @@ -4033,7 +4033,7 @@ Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generated /* * Record dependencies on objects used in the expression, too. */ - if (generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (generatedCol == ATTRIBUTE_GENERATED_STORED || generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { /* * Generated column: Dropping anything that the generation expression * refers to automatically drops the generated column. @@ -4298,6 +4298,11 @@ List* AddRelationNewConstraints( pstate->p_rawdefaultlist = newColDefaults; + if (u_sess->hook_cxt.invokePreAddConstraintsHook) { + ((InvokePreAddConstraintsHookType)(u_sess->hook_cxt.invokePreAddConstraintsHook))(rel, pstate, + newColDefaults); + } + /* * Process column default expressions. */ @@ -4312,7 +4317,8 @@ List* AddRelationNewConstraints( } else { expr = cookDefault(pstate, colDef->raw_default, atp->atttypid, atp->atttypmod, atp->attcollation, NameStr(atp->attname), colDef->generatedCol); - if (colDef->generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (colDef->generatedCol == ATTRIBUTE_GENERATED_STORED || + colDef->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { pull_varattnos(expr, 1, &generated_by_attrs); } } @@ -4743,7 +4749,7 @@ Node *cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 att expr = transformExpr(pstate, raw_default, pstate->p_expr_kind); pstate->p_expr_kind = EXPR_KIND_NONE; - if (generatedCol == ATTRIBUTE_GENERATED_STORED) + if (generatedCol == ATTRIBUTE_GENERATED_STORED || generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { (void)CheckNestedGenerated(pstate, expr); diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 215d66b96c..a5f551f97f 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -3076,7 +3076,10 @@ static Query* transformSelectStmt(ParseState* pstate, SelectStmt* stmt, bool isF qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset, EXPR_KIND_OFFSET, "OFFSET"); qry->limitCount = transformLimitClause(pstate, stmt->limitCount, EXPR_KIND_LIMIT, "LIMIT"); qry->limitIsPercent = stmt->limitIsPercent; - qry->limitWithTies = stmt->limitWithTies; + qry->limitWithTies = stmt->limitWithTies && stmt->sortClause != NIL; + if (u_sess->hook_cxt.invokeTransformSelectForLimitHook) { + ((InvokeTransformSelectForLimitHookType)(u_sess->hook_cxt.invokeTransformSelectForLimitHook))(stmt); + } qry->isFetch = stmt->isFetch; /* transform window clauses after we have seen all window functions */ diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index 376a9cd108..a1ec888165 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -162,6 +162,7 @@ typedef struct FetchLimit bool isPercent; bool isWithTies; bool isFetch; + bool isTop; } FetchLimit; @@ -32942,9 +32943,9 @@ insertSelectOptions(SelectStmt *stmt, stmt->limitCount = limitCount; } stmt->isFetch = limitClause->isFetch; + stmt->limitIsPercent = limitClause && limitClause->isPercent; + stmt->limitWithTies = limitClause && limitClause->isWithTies; } - stmt->limitIsPercent = limitClause && limitClause->isPercent; - stmt->limitWithTies = limitClause && limitClause->isWithTies; if (withClause) { diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 0df499ad33..7667b668f9 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -1454,6 +1454,9 @@ static void TransformColumnDefinitionConstraints(CreateStmtContext* cxt, ColumnD parser_errposition(cxt->pstate, constraint->location))); } column->generatedCol = ATTRIBUTE_GENERATED_STORED; + if (constraint->generated_when == ATTRIBUTE_GENERATED_PERSISTED) { + column->generatedCol = ATTRIBUTE_GENERATED_PERSISTED; + } column->raw_default = constraint->raw_expr; Assert(constraint->cooked_expr == NULL); saw_generated = true; diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index ce24fda208..47d7a10396 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -1838,6 +1838,8 @@ static int get_table_attribute( const char* adsrc = TextDatumGetCString(txt); if (generatedCol == ATTRIBUTE_GENERATED_STORED) { appendStringInfo(buf, " GENERATED ALWAYS AS (%s) STORED", adsrc); + } else if (generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { + appendStringInfo(buf, "AS (%s) PERSISTED", adsrc); } else if (strcmp(adsrc, "AUTO_INCREMENT") == 0) { Node *adexpr = (Node*)stringToNode_skip_extern_fields(TextDatumGetCString(val)); find_nextval_seqoid_walker(adexpr, &tableinfo->autoinc_seqoid); diff --git a/src/common/backend/utils/cache/relcache.cpp b/src/common/backend/utils/cache/relcache.cpp index e0adb3db98..e1ea8a8e74 100755 --- a/src/common/backend/utils/cache/relcache.cpp +++ b/src/common/backend/utils/cache/relcache.cpp @@ -5965,7 +5965,7 @@ static void GeneratedColFetch(TupleConstr *constr, HeapTuple htup, Relation adre } } - if (generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (generatedCol == ATTRIBUTE_GENERATED_STORED || generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { attrdef[attrdefIndex].generatedCol = generatedCol; genCols[attrdef[attrdefIndex].adnum - 1] = generatedCol; constr->has_generated_stored = true; diff --git a/src/common/backend/utils/cache/syscache.cpp b/src/common/backend/utils/cache/syscache.cpp index 1a91330af2..a77eb9d6ab 100644 --- a/src/common/backend/utils/cache/syscache.cpp +++ b/src/common/backend/utils/cache/syscache.cpp @@ -1157,6 +1157,21 @@ HeapTuple SearchSysCacheAttName(Oid relid, const char* attname) return tuple; } +HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum) +{ + HeapTuple tuple; + + tuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(relid), Int16GetDatum(attnum)); + if (!HeapTupleIsValid(tuple)) { + return NULL; + } + if (((Form_pg_attribute)GETSTRUCT(tuple))->attisdropped) { + ReleaseSysCache(tuple); + return NULL; + } + return tuple; +} + /* * SearchSysCacheCopyAttName * @@ -1175,6 +1190,25 @@ HeapTuple SearchSysCacheCopyAttName(Oid relid, const char* attname) return newtuple; } +/* + * SearchSysCacheCopyAttNum + * + * As above, an attisdropped-aware version of SearchSysCacheCopy. + */ +HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum) +{ + HeapTuple tuple = NULL; + HeapTuple newtuple = NULL; + + tuple = SearchSysCacheAttNum(relid, attnum); + if (!HeapTupleIsValid(tuple)) { + return NULL; + } + newtuple = heap_copytuple(tuple); + ReleaseSysCache(tuple); + return newtuple; +} + /* * SearchSysCacheExistsAttName * diff --git a/src/common/pl/plpgsql/src/pl_exec.cpp b/src/common/pl/plpgsql/src/pl_exec.cpp index af153151a1..5c06962582 100644 --- a/src/common/pl/plpgsql/src/pl_exec.cpp +++ b/src/common/pl/plpgsql/src/pl_exec.cpp @@ -2386,7 +2386,8 @@ static void RecordSetGeneratedField(PLpgSQL_rec *recNew) securec_check(rc, "\0", "\0"); for (int i = 0; i < recNew->tupdesc->natts; i++) { - if (GetGeneratedCol(recNew->tupdesc, i) == ATTRIBUTE_GENERATED_STORED) { + if (GetGeneratedCol(recNew->tupdesc, i) == ATTRIBUTE_GENERATED_STORED || + GetGeneratedCol(recNew->tupdesc, i) == ATTRIBUTE_GENERATED_PERSISTED) { replaces[i] = true; values[i] = (Datum)0; nulls[i] = true; diff --git a/src/gausskernel/optimizer/commands/ddldeparse.cpp b/src/gausskernel/optimizer/commands/ddldeparse.cpp index 869a717eda..88f1776e5e 100644 --- a/src/gausskernel/optimizer/commands/ddldeparse.cpp +++ b/src/gausskernel/optimizer/commands/ddldeparse.cpp @@ -1623,12 +1623,20 @@ static ObjTree* deparse_ColumnDef_constraints(ObjTree *ret, Relation relation, saw_notnull ? "NOT NULL" : saw_autoincrement ? "NULL" : ""); /* GENERATED COLUMN EXPRESSION */ - tmp_obj = new_objtree("GENERATED ALWAYS AS"); + if (coldef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + tmp_obj = new_objtree("GENERATED ALWAYS AS"); + } if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { char *defstr; defstr = RelationGetColumnDefault(relation, attrForm->attnum, dpcontext, exprs); append_string_object(tmp_obj, "(%{generation_expr}s) STORED", "generation_expr", defstr); + } else if (coldef->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { + tmp_obj = new_objtree("AS"); + char *defstr; + + defstr = RelationGetColumnDefault(relation, attrForm->attnum, dpcontext, exprs); + append_string_object(tmp_obj, "(%{generation_expr}s) PERSISTED", "generation_expr", defstr); } else { append_not_present(tmp_obj, "(%{generation_expr}s) STORED"); } @@ -1639,6 +1647,7 @@ static ObjTree* deparse_ColumnDef_constraints(ObjTree *ret, Relation relation, if (attrForm->atthasdef && coldef->generatedCol != ATTRIBUTE_GENERATED_STORED && + coldef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED && !saw_autoincrement && !onupdate) { char *defstr; @@ -1766,6 +1775,7 @@ static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool compo if (attrForm->atthasdef && coldef->generatedCol != ATTRIBUTE_GENERATED_STORED && + coldef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED && !saw_autoincrement) { char *defstr = NULL; @@ -1812,7 +1822,9 @@ static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool compo append_string_object(ret, "%{not_null}s", "not_null", saw_notnull ? "NOT NULL" : ""); /* GENERATED COLUMN EXPRESSION */ - tmp_obj = new_objtree("GENERATED ALWAYS AS"); + if (coldef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + tmp_obj = new_objtree("GENERATED ALWAYS AS"); + } if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { char *defstr; @@ -1820,6 +1832,14 @@ static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool compo dpcontext, exprs); append_string_object(tmp_obj, "(%{generation_expr}s) STORED", "generation_expr", defstr); + } else if (coldef->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { + tmp_obj = new_objtree("AS"); + char *defstr; + + defstr = RelationGetColumnDefault(relation, attrForm->attnum, + dpcontext, exprs); + append_string_object(tmp_obj, "(%{generation_expr}s) PERSISTED", + "generation_expr", defstr); } else { append_not_present(tmp_obj, "(%{generation_expr}s) STORED"); } @@ -3111,7 +3131,8 @@ static List* deparse_AlterRelation_add_column_default(CollectedCommand *cmd) Oid typcollation; /* do nothing */ - if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (coldef->generatedCol == ATTRIBUTE_GENERATED_STORED || + coldef->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { break; } diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index f7de700db3..8906e23fa1 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -12320,7 +12320,8 @@ static void UpdateGenerateColFirstAfter(Relation rel, int startattnum, int endat } // update pg_attrdef_adbin - if (generated_col == ATTRIBUTE_GENERATED_STORED) { + if (generated_col == ATTRIBUTE_GENERATED_STORED || + generated_col == ATTRIBUTE_GENERATED_PERSISTED) { Datum adbin_datum; Node *adbin = NULL; Node *new_adbin = NULL; @@ -14667,6 +14668,10 @@ static ObjectAddress ATExecDropColumn(List** wqueue, Relation rel, const char* } } + if (u_sess->hook_cxt.invokePreDropColumnHook) { + ((InvokePreDropColumnHookType)(u_sess->hook_cxt.invokePreDropColumnHook))(rel, attnum); + } + /* * Propagate to children as appropriate. Unlike most other ALTER * routines, we have to do this one level of recursion at a time; we can't @@ -17981,7 +17986,7 @@ static ObjectAddress ATExecAlterColumnType(AlteredTableInfo* tab, Relation rel, if (RelAutoIncAttrNum(rel) == attnum) { defaultexpr = RecookAutoincAttrDefault(rel, attnum, targettype, targettypmod); if (defaultexpr == NULL) { - if (generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (generatedCol == ATTRIBUTE_GENERATED_STORED || generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s", colName, format_type_be(targettype)))); @@ -18007,7 +18012,7 @@ static ObjectAddress ATExecAlterColumnType(AlteredTableInfo* tab, Relation rel, NULL, -1); if (defaultexpr == NULL) { - if (generatedCol == ATTRIBUTE_GENERATED_STORED) { + if (generatedCol == ATTRIBUTE_GENERATED_STORED || generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { ereport(ERROR, (errmodule(MOD_GEN_COL), errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("generation expression for column \"%s\" cannot be cast automatically to type %s", colName, format_type_be(targettype)))); @@ -33966,7 +33971,8 @@ static void ATPrepAlterModifyColumn(List** wqueue, AlteredTableInfo* tab, Relati ColumnDef* def = (ColumnDef*)cmd->def; Node* tmp_expr = def->raw_default; char* tmp_name = cmd->name; - if (def->generatedCol != ATTRIBUTE_GENERATED_STORED && (tmp_expr == NULL || !IsA(tmp_expr, AutoIncrement))) { + if (def->generatedCol != ATTRIBUTE_GENERATED_STORED && def->generatedCol != ATTRIBUTE_GENERATED_PERSISTED && + (tmp_expr == NULL || !IsA(tmp_expr, AutoIncrement))) { ATPrepCheckDefault(tmp_expr); } @@ -34388,7 +34394,7 @@ static void ATAlterModifyColumnDefault(AlteredTableInfo* tab, Relation rel, Colu ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errmsg("generated column cannot refer to auto_increment column")))); } - } else if (def->generatedCol == ATTRIBUTE_GENERATED_STORED) { + } else if (def->generatedCol == ATTRIBUTE_GENERATED_STORED || def->generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { if (list_length(tab->changedGeneratedCols) > 0) { ereport(ERROR, (errcode(ERRCODE_INVALID_OPERATION), errmsg("Invalid modify column operation"), diff --git a/src/gausskernel/runtime/executor/nodeLimit.cpp b/src/gausskernel/runtime/executor/nodeLimit.cpp index 83ad361923..1059c4d27b 100644 --- a/src/gausskernel/runtime/executor/nodeLimit.cpp +++ b/src/gausskernel/runtime/executor/nodeLimit.cpp @@ -362,12 +362,17 @@ void recompute_limits(LimitState* node) node->noCount = false; } else if (node->isPercent) { node->count = 0; - node->fraction = DatumGetFloat8(val) / PERCENTAGE_BASE; - if (node->fraction < 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), - errmodule(MOD_EXECUTOR), - errmsg("LIMIT must not be negative"))); + float8 value = DatumGetFloat8(val); + node->fraction = value / PERCENTAGE_BASE; + + if (u_sess->hook_cxt.recomputeLimitsHook) { + ((RecomputeLimitsHookType)(u_sess->hook_cxt.recomputeLimitsHook))(value); + } else if (node->fraction < 0) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), + errmodule(MOD_EXECUTOR), + errmsg("LIMIT must not be negative"))); + } node->noCount = false; } } else { diff --git a/src/gausskernel/runtime/executor/nodeModifyTable.cpp b/src/gausskernel/runtime/executor/nodeModifyTable.cpp index 5a19c08b70..00beaa1d9f 100644 --- a/src/gausskernel/runtime/executor/nodeModifyTable.cpp +++ b/src/gausskernel/runtime/executor/nodeModifyTable.cpp @@ -326,7 +326,8 @@ static void RecoredGeneratedExpr(ResultRelInfo *resultRelInfo, EState *estate, C resultRelInfo->ri_NumGeneratedNeeded = 0; for (int i = 0; i < natts; i++) { - if (GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_STORED) { + if (GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_STORED || + GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_PERSISTED) { Expr *expr; /* @@ -391,7 +392,9 @@ void ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, EState *estate, Tu for (uint32 i = 0; i < natts; i++) { Form_pg_attribute attr = TupleDescAttr(tupdesc, i); - if (GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_STORED && resultRelInfo->ri_GeneratedExprs[i]) { + if ((GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_STORED || + GetGeneratedCol(tupdesc, i) == ATTRIBUTE_GENERATED_PERSISTED) && + resultRelInfo->ri_GeneratedExprs[i]) { ExprContext *econtext; Datum val; bool isnull; diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 5a20db9d3f..98c8cd0206 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -271,4 +271,5 @@ extern bool GetIndexEnableStateByTuple(HeapTuple indexTuple); extern void AddOrDropUidsAttr(Oid relOid, bool oldRelHasUids, bool newRelHasUids); extern char* heap_serialize_row_attr(Oid rel_oid, bool* depend_undefined); +typedef void (*InvokePreAddConstraintsHookType) (Relation rel, ParseState *pstate, List *newColDefaults); #endif /* HEAP_H */ diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 3f097ec831..fcc13de2d3 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -236,5 +236,6 @@ typedef FormData_pg_attribute *Form_pg_attribute; */ #define ATTRIBUTE_IDENTITY_ALWAYS 'a' #define ATTRIBUTE_GENERATED_STORED 's' +#define ATTRIBUTE_GENERATED_PERSISTED 'p' #endif /* PG_ATTRIBUTE_H */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index e04b8999f6..db7fa7fb51 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -271,4 +271,5 @@ extern char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_c #ifdef USE_SPQ extern void spq_btbuild_update_pg_class(Relation heap, Relation index); #endif +typedef void (*InvokePreDropColumnHookType) (Relation rel, AttrNumber attnum); #endif /* TABLECMDS_H */ diff --git a/src/include/executor/node/nodeLimit.h b/src/include/executor/node/nodeLimit.h index dc17023ece..a298223362 100644 --- a/src/include/executor/node/nodeLimit.h +++ b/src/include/executor/node/nodeLimit.h @@ -20,5 +20,5 @@ extern LimitState* ExecInitLimit(Limit* node, EState* estate, int eflags); extern void ExecEndLimit(LimitState* node); extern void ExecReScanLimit(LimitState* node); extern void recompute_limits(LimitState* node); - +typedef void (*RecomputeLimitsHookType) (float8 val); #endif /* NODELIMIT_H */ diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 43782e0a80..5b7cc75a52 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -3006,6 +3006,10 @@ typedef struct knl_u_hook_context { void *checkVaildUserHook; void *fetchStatusHook; void *rowcountHook; + void *invokePreDropColumnHook; + void *invokePreAddConstraintsHook; + void *invokeTransformSelectForLimitHook; + void *recomputeLimitsHook; } knl_u_hook_context; typedef struct knl_u_libsw_context { diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index 33dbdd0a64..38955f5e9f 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -82,6 +82,7 @@ typedef struct AnalyzerRoutine { } AnalyzerRoutine; typedef Query* (*transformStmtFunc)(ParseState* pstate, Node* parseTree, bool isFirstNode, bool isCreateView); +typedef void (*InvokeTransformSelectForLimitHookType) (SelectStmt* stmt); extern void transformOperatorPlus(ParseState* pstate, Node** whereClause); extern bool IsColumnRefPlusOuterJoin(const ColumnRef* cf); diff --git a/src/include/parser/keywords.h b/src/include/parser/keywords.h index 5152301ace..ac073b4788 100644 --- a/src/include/parser/keywords.h +++ b/src/include/parser/keywords.h @@ -34,6 +34,7 @@ typedef struct PlpgsqlKeywordValue { extern PGDLLIMPORT const ScanKeywordList ScanKeywords; extern PGDLLIMPORT const uint8 ScanKeywordCategories[]; +extern PGDLLIMPORT const bool ScanKeywordDirectLabel[]; /* Globals from keywords.c */ extern const ScanKeywordList SQLScanKeywords[]; diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index d29468c30c..69f32c4f33 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -212,6 +212,8 @@ extern Oid GetSysCacheOid(int cacheId, Datum key1, Datum key2, Datum key3, Datum extern HeapTuple SearchSysCacheAttName(Oid relid, const char* attname); extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char* attname); +extern HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum); +extern HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum); extern bool SearchSysCacheExistsAttName(Oid relid, const char* attname); extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool* isNull); -- Gitee From 0ddc4365b5d83c1971aebeefd3523a24cdab1e27 Mon Sep 17 00:00:00 2001 From: lukeman Date: Mon, 17 Mar 2025 22:02:59 +0800 Subject: [PATCH 07/11] =?UTF-8?q?D=E5=BA=93=E5=B8=B8=E7=94=A8=E8=AF=AD?= =?UTF-8?q?=E6=B3=95=E5=85=BC=E5=AE=B9-DDL/DML=E8=AF=AD=E6=B3=95=E5=85=BC?= =?UTF-8?q?=E5=AE=B9:=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=20&=20=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/test_ddl_and_dml.out | 22 +++---- contrib/shark/sql/test_ddl_and_dml.sql | 2 +- .../shark/src/backend_parser/gram-tsql-rule.y | 2 +- contrib/shark/src/backend_parser/kwlist.h | 3 +- contrib/shark/src/tablecmds.cpp | 57 +------------------ src/bin/psql/describe.cpp | 6 +- src/common/backend/utils/adt/ruleutils.cpp | 9 ++- .../optimizer/commands/ddldeparse.cpp | 26 +++++++-- .../optimizer/commands/tablecmds.cpp | 35 ++++++++++++ src/include/commands/tablecmds.h | 1 + 10 files changed, 83 insertions(+), 80 deletions(-) diff --git a/contrib/shark/expected/test_ddl_and_dml.out b/contrib/shark/expected/test_ddl_and_dml.out index 295cf42601..0fd616c201 100644 --- a/contrib/shark/expected/test_ddl_and_dml.out +++ b/contrib/shark/expected/test_ddl_and_dml.out @@ -20,13 +20,13 @@ select * from Products; (2 rows) \d+ Products - Table "test_ddl_and_dml.products" - Column | Type | Modifiers | Storage | Stats target | Description -----------------+----------+-----------------------------------------------------------------------------------------------------+---------+--------------+------------- - qtyavailable | smallint | | plain | | - unitprice | money | | plain | | - inventoryvalue | money | collate default generated always as ((qtyavailable * unitprice)) stored | plain | | - retailvalue | money | collate default generated always as (((qtyavailable * unitprice) * (1.5)::double precision)) stored | plain | | + Table "test_ddl_and_dml.products" + Column | Type | Modifiers | Storage | Stats target | Description +----------------+----------+-----------------------------------------------------------------------+---------+--------------+------------- + qtyavailable | smallint | | plain | | + unitprice | money | | plain | | + inventoryvalue | money | as ((qtyavailable * unitprice)) persisted | plain | | + retailvalue | money | as (((qtyavailable * unitprice) * (1.5)::double precision)) persisted | plain | | Has OIDs: no Options: orientation=row, compression=no @@ -1882,10 +1882,10 @@ SELECT 1 IP; 1 (1 row) -SELECT 1 IS; - is ----- - 1 +SELECT 1 CHECKIDENT; + checkident +------------ + 1 (1 row) SELECT 1 ISOLATION; diff --git a/contrib/shark/sql/test_ddl_and_dml.sql b/contrib/shark/sql/test_ddl_and_dml.sql index 6c79d5e239..4935303c50 100644 --- a/contrib/shark/sql/test_ddl_and_dml.sql +++ b/contrib/shark/sql/test_ddl_and_dml.sql @@ -358,7 +358,7 @@ SELECT 1 INTERVAL; SELECT 1 INVISIBLE; SELECT 1 INVOKER; SELECT 1 IP; -SELECT 1 IS; +SELECT 1 CHECKIDENT; SELECT 1 ISOLATION; SELECT 1 JOIN; SELECT 1 JSON_EXISTS; diff --git a/contrib/shark/src/backend_parser/gram-tsql-rule.y b/contrib/shark/src/backend_parser/gram-tsql-rule.y index 2edd3196b4..fc0b9e71dc 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -1022,6 +1022,7 @@ direct_label_keyword: ABORT_P | CHARACTERSET | CHARSET | CHECK + | CHECKIDENT | CHECKPOINT | CLASS | CLASS_ORIGIN @@ -1246,7 +1247,6 @@ direct_label_keyword: ABORT_P | INVISIBLE | INVOKER | IP - | IS | ISOLATION | JOIN | JSON_EXISTS diff --git a/contrib/shark/src/backend_parser/kwlist.h b/contrib/shark/src/backend_parser/kwlist.h index 3340ab8c0f..f7a37d046c 100644 --- a/contrib/shark/src/backend_parser/kwlist.h +++ b/contrib/shark/src/backend_parser/kwlist.h @@ -110,6 +110,7 @@ PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("characterset", CHARACTERSET, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("charset", CHARSET, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("checkident", CHECKIDENT, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("class_origin", CLASS_ORIGIN, UNRESERVED_KEYWORD, DIRECT_LABEL) @@ -354,7 +355,7 @@ PG_KEYWORD("into", INTO, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("invisible", INVISIBLE, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("ip", IP, UNRESERVED_KEYWORD, DIRECT_LABEL) -PG_KEYWORD("is", IS, RESERVED_KEYWORD, DIRECT_LABEL) +PG_KEYWORD("is", IS, RESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("isnull", ISNULL, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, DIRECT_LABEL) PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, DIRECT_LABEL) diff --git a/contrib/shark/src/tablecmds.cpp b/contrib/shark/src/tablecmds.cpp index 39eba8c6a5..b173e01165 100644 --- a/contrib/shark/src/tablecmds.cpp +++ b/contrib/shark/src/tablecmds.cpp @@ -46,7 +46,6 @@ static void pltsql_TransformSelectForLimitHook(SelectStmt* stmt); static void pltsql_RecomputeLimitsHook(float8 val); static ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid); static bool check_nested_computed_column(Node *node, void *context); -static bool IsComputedColumn(Oid adrelid, int2 asnum); /* Hook to tablecmds.cpp in the engine */ static void* prev_InvokePreDropColumnHook = NULL; @@ -259,26 +258,7 @@ static void pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List attTup->atttypid = targettype; attTup->atttypmod = targettypmod; - - /* - * The target column should already be having a collation associated - * with it due to explicit COLLATE clause If suppose collation is not - * valid or there is no explicit COLLATE clause, we try to find column - * collation from finished expession. - */ - if (!OidIsValid(attTup->attcollation)) { - Oid targetcollid; - - /* take care of collations in the finished expression */ - assign_expr_collations(pstate, expr); - targetcollid = exprCollation(expr); - - if (OidIsValid(targetcollid)) { - attTup->attcollation = targetcollid; - } else { - attTup->attcollation = tform->typcollation; - } - } + attTup->attcollation = 0; attTup->attndims = tform->typndims; attTup->attlen = tform->typlen; @@ -332,41 +312,6 @@ static void pltsql_RecomputeLimitsHook(float8 val) } } -static bool IsComputedColumn(Oid adrelid, int2 asnum) -{ - Relation attrdef; - ScanKeyData keys[2]; - SysScanDesc scan; - HeapTuple tup; - bool res = false; - - attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); - ScanKeyInit(&keys[0], - Anum_pg_attrdef_adrelid, - BTEqualStrategyNumber, - F_OIDEQ, - ObjectIdGetDatum(adrelid)); - ScanKeyInit(&keys[1], - Anum_pg_attrdef_adnum, - BTEqualStrategyNumber, - F_INT2EQ, - Int16GetDatum(asnum)); - scan = systable_beginscan(attrdef, AttrDefaultIndexId, true, NULL, 2, keys); - if (HeapTupleIsValid(tup = systable_getnext(scan))) { - bool isnull = false; - char generatedCol = '\0'; - Datum adgencol = fastgetattr(tup, Anum_pg_attrdef_adgencol, attrdef->rd_att, &isnull); - if (!isnull) { - generatedCol = DatumGetChar(adgencol); - } - res = (generatedCol == ATTRIBUTE_GENERATED_PERSISTED); - } - - systable_endscan(scan); - relation_close(attrdef, AccessShareLock); - return res; -} - /* * Given a pg_attrdef OID, return the relation OID and column number of * the owning column (represented as an ObjectAddress for convenience). diff --git a/src/bin/psql/describe.cpp b/src/bin/psql/describe.cpp index a60fae0d44..98152bf9f5 100644 --- a/src/bin/psql/describe.cpp +++ b/src/bin/psql/describe.cpp @@ -1967,8 +1967,10 @@ static bool describeOneTableDetails(const char* schemaname, const char* relation appendPQExpBufferStr(&tmpbuf, " "); } /* translator: default values of column definitions */ - if (strlen(PQgetvalue(res, i, PQfnumber(res, "generated_column"))) > 0) { - appendPQExpBuffer(&tmpbuf, _("generated always as (%s) stored"), default_value); + char* gencolType = PQgetvalue(res, i, PQfnumber(res, "generated_column")); + if (gencolType && strlen(gencolType) > 0) { + appendPQExpBuffer(&tmpbuf, (strcmp(gencolType, "p") == 0 ? _("as (%s) persisted") : + _("generated always as (%s) stored")), default_value); } else if (strcmp(default_value, "AUTO_INCREMENT") == 0) { appendPQExpBuffer(&tmpbuf, _("%s"), default_value); } else { diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index 47d7a10396..df5a641309 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -1751,8 +1751,13 @@ static int get_table_attribute( appendStringInfo(buf, "\n "); actual_atts++; + bool iscomputedcol = IsComputedColumn(tableoid, i + 1); /* Attribute name */ - appendStringInfo(buf, "%s %s", quote_identifier(NameStr(att_tup->attname)), result); + if (iscomputedcol) { + appendStringInfo(buf, "%s", quote_identifier(NameStr(att_tup->attname))); + } else { + appendStringInfo(buf, "%s %s", quote_identifier(NameStr(att_tup->attname)), result); + } if (att_tup->attkvtype == ATT_KV_TAG) appendStringInfo(buf, " TSTag"); else if (att_tup->attkvtype == ATT_KV_FIELD) @@ -1839,7 +1844,7 @@ static int get_table_attribute( if (generatedCol == ATTRIBUTE_GENERATED_STORED) { appendStringInfo(buf, " GENERATED ALWAYS AS (%s) STORED", adsrc); } else if (generatedCol == ATTRIBUTE_GENERATED_PERSISTED) { - appendStringInfo(buf, "AS (%s) PERSISTED", adsrc); + appendStringInfo(buf, " AS (%s) PERSISTED", adsrc); } else if (strcmp(adsrc, "AUTO_INCREMENT") == 0) { Node *adexpr = (Node*)stringToNode_skip_extern_fields(TextDatumGetCString(val)); find_nextval_seqoid_walker(adexpr, &tableinfo->autoinc_seqoid); diff --git a/src/gausskernel/optimizer/commands/ddldeparse.cpp b/src/gausskernel/optimizer/commands/ddldeparse.cpp index 88f1776e5e..394ac06399 100644 --- a/src/gausskernel/optimizer/commands/ddldeparse.cpp +++ b/src/gausskernel/optimizer/commands/ddldeparse.cpp @@ -1710,12 +1710,26 @@ static ObjTree* deparse_ColumnDef(Relation relation, List *dpcontext, bool compo get_atttypetypmodcoll(relid, attrForm->attnum, &typid, &typmod, &typcollation); - ret = new_objtree_VA("%{name}I %{coltype}T", 3, - "type", ObjTypeString, "column", - "name", ObjTypeString, coldef->colname, - "coltype", ObjTypeObject, - new_objtree_for_type(typid, typmod)); - + constexpr int numThree = 3; + constexpr int numFour = 3; + if (coldef->generatedCol != ATTRIBUTE_GENERATED_PERSISTED) { + ret = new_objtree_VA("%{name}I %{coltype}T", numThree, + "type", ObjTypeString, "column", + "name", ObjTypeString, coldef->colname, + "coltype", ObjTypeObject, + new_objtree_for_type(typid, typmod)); + } else { + ObjTree* dummy = new_objtree_VA(NULL, numFour, + "schemaname", ObjTypeString, "", + "typename", ObjTypeString, "", + "typmod", ObjTypeString, "", + "typarray", ObjTypeBool, false); + append_not_present(dummy, NULL); + ret = new_objtree_VA("%{name}I", numThree, + "type", ObjTypeString, "column", + "name", ObjTypeString, coldef->colname, + "coltype", ObjTypeObject, dummy); + } tmp_obj = new_objtree("COLLATE"); if (OidIsValid(typcollation)) { append_object_object(tmp_obj, "%{name}D", diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index 8906e23fa1..dc3d75c1de 100755 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -34749,3 +34749,38 @@ static void check_unsupported_charset_for_column(Oid collation, const char* col_ col_name))); } } + +bool IsComputedColumn(Oid adrelid, int2 asnum) +{ + Relation attrdef; + ScanKeyData keys[2]; + SysScanDesc scan; + HeapTuple tup; + bool res = false; + + attrdef = relation_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&keys[0], + Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(adrelid)); + ScanKeyInit(&keys[1], + Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, + F_INT2EQ, + Int16GetDatum(asnum)); + scan = systable_beginscan(attrdef, AttrDefaultIndexId, true, NULL, 2, keys); + if (HeapTupleIsValid(tup = systable_getnext(scan))) { + bool isnull = false; + char generatedCol = '\0'; + Datum adgencol = fastgetattr(tup, Anum_pg_attrdef_adgencol, attrdef->rd_att, &isnull); + if (!isnull) { + generatedCol = DatumGetChar(adgencol); + } + res = (generatedCol == ATTRIBUTE_GENERATED_PERSISTED); + } + + systable_endscan(scan); + relation_close(attrdef, AccessShareLock); + return res; +} \ No newline at end of file diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index db7fa7fb51..1bde9f1153 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -272,4 +272,5 @@ extern char* GetCreateViewCommand(const char *rel_name, HeapTuple tup, Form_pg_c extern void spq_btbuild_update_pg_class(Relation heap, Relation index); #endif typedef void (*InvokePreDropColumnHookType) (Relation rel, AttrNumber attnum); +extern bool IsComputedColumn(Oid adrelid, int2 asnum); #endif /* TABLECMDS_H */ -- Gitee From f42299e92e32d25ae64b855370501c2d394be91b Mon Sep 17 00:00:00 2001 From: wangpingyun <2418191738@qq.com> Date: Wed, 19 Mar 2025 15:07:40 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dday=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=B8=8Eobject=5Fid=E5=87=BD=E6=95=B0=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/day_test.out | 2 +- contrib/shark/expected/objectproperty.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/shark/expected/day_test.out b/contrib/shark/expected/day_test.out index 87333de074..fe60c75767 100644 --- a/contrib/shark/expected/day_test.out +++ b/contrib/shark/expected/day_test.out @@ -119,7 +119,7 @@ SELECT DAY('2023-10-01') AS DayPart; -- 预期结果:1 SELECT DAY(CURRENT_DATE) AS DayPart; -- 预期结果:当前日期的天数部分 daypart --------- - 9 +--?.* (1 row) SELECT DAY(CURRENT_STAMP) AS DayPart; -- 预期结果:当前日期的天数部分 diff --git a/contrib/shark/expected/objectproperty.out b/contrib/shark/expected/objectproperty.out index 869e90df3e..93561b4103 100644 --- a/contrib/shark/expected/objectproperty.out +++ b/contrib/shark/expected/objectproperty.out @@ -795,7 +795,7 @@ select object_id('', 'U'); select object_id('students', ''); object_id ----------- - 16414 +--?.* (1 row) select object_id('students', 'FN'); -- Gitee From db54fc769065e33adfc0fbc76d97a6ac0a879b7c Mon Sep 17 00:00:00 2001 From: zhubin79 <18784715772@163.com> Date: Thu, 20 Mar 2025 11:02:56 +0800 Subject: [PATCH 09/11] =?UTF-8?q?max=5Flength=20=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E5=AF=B9decimal=E7=B1=BB=E5=9E=8B=E5=A4=84?= =?UTF-8?q?=E7=90=86=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/test_sysviews.out | 13 ++++++-- contrib/shark/shark--1.0.sql | 41 +++++++++++------------- contrib/shark/sql/test_sysviews.sql | 7 ++++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/contrib/shark/expected/test_sysviews.out b/contrib/shark/expected/test_sysviews.out index c993d8a3c7..9e71a2ed66 100644 --- a/contrib/shark/expected/test_sysviews.out +++ b/contrib/shark/expected/test_sysviews.out @@ -185,6 +185,11 @@ CREATE TABLE course credit DOUBLE PRECISION ); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "course_pkey" for table "course" +create table teacher_salary +( + tec_id int, + tec_salary decimal(10, 2) +); create or replace view teacher_info as select c.cla_name, t.tec_name, t.tec_job, t.tec_sex, t.tec_age from teacher t @@ -246,6 +251,7 @@ order by id; fk_depart_tec_id | F | F course | U | U course_pkey | PK | K + teacher_salary | U | U teacher_info | V | V t_log | U | U t_seq | SO | SO @@ -254,7 +260,7 @@ order by id; test_sub | FN | FN syn_tbl | SN | SN syn_tr | SN | SN -(21 rows) +(22 rows) select col.name, col.length, col.colid, col.status, col.prec, col.scale, col.iscomputed, col.isoutparam, col.isnullable, col.collation from sys.syscolumns col @@ -286,6 +292,8 @@ order by id, colid; cor_name | 34 | 2 | 0 | 0 | 34 | 0 | 0 | 1 | default cor_type | 24 | 3 | 8 | 0 | 24 | 0 | 0 | 0 | default credit | 8 | 4 | 8 | 0 | | 0 | 0 | 0 | + tec_id | 4 | 1 | 8 | 10 | | 0 | 0 | 0 | + tec_salary | 15 | 2 | 8 | 10 | 2 | 0 | 0 | 0 | cla_name | 24 | 1 | 8 | 0 | 24 | 0 | 0 | 0 | default tec_name | 24 | 2 | 8 | 0 | 24 | 0 | 0 | 0 | default tec_job | 19 | 3 | 8 | 0 | 19 | 0 | 0 | 0 | default @@ -294,7 +302,7 @@ order by id, colid; c1 | 4 | 1 | 8 | 10 | | 0 | 0 | 0 | c2 | 24 | 2 | 8 | 0 | 24 | 0 | 0 | 0 | default c3 | 8 | 3 | 8 | 26 | | 0 | 0 | 0 | -(30 rows) +(32 rows) select ind.name, ind.keycnt, ind."OrigFillFactor", ind.rows from sys.sysindexes ind left join pg_class c on c.oid = ind.indid @@ -331,6 +339,7 @@ drop function test_sub; drop procedure test_sum; drop table t_log; drop view teacher_info; +drop table teacher_salary; drop table course; drop table school_department; drop table class; diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index 7b1d04d6d3..7e1713921a 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -293,7 +293,7 @@ select from pg_synonym y; grant select on sys.sysobjects to public; -create or replace function sys.tsql_type_max_length_helper(in type text, in typelen int, in typemod int) +create or replace function sys.tsql_type_max_length_helper(in type text, in typelen smallint, in typemod int) returns smallint as $$ declare @@ -303,19 +303,19 @@ begin max_length := -1; if typelen != -1 then - case - when lower(type) in ('numeric', 'decimal') then - precision := ((typemod - 4) >> 16) & 65535; - /* Each four bits (decimal bits) takes up two bytes and then adds an additional overhead of eight bytes to the entire data. */ - max_length := (ceil((precision / 4 + 1) * 2 + 8))::smallint; - else max_length := typelen; - end case; - return max_length; + return typelen; end if; if typemod != -1 then - max_length = typemod; + if lower(type) in ('numeric', 'decimal') then + precision := ((typemod - 4) >> 16) & 65535; + /* Each four bits (decimal bits) takes up two bytes and then adds an additional overhead of eight bytes to the entire data. */ + max_length := (ceil((precision / 4 + 1) * 2 + 8))::smallint; + return max_length; + end if; + max_length = typemod::smallint; end if; + return max_length; end; $$ language plpgsql immutable strict; @@ -380,23 +380,20 @@ $$ language plpgsql immutable strict; create or replace function sys.tsql_type_scale_helper(in type text, in typemod int) returns int as $$ -declare - scale int; begin if type is null then - return -1; + return null; end if; + + if typemod = -1 then + return null; + end if; - if typemod != -1 then - return typemod; - end if; + if lower(type) in ('numeric', 'decimal') then + return (typemod - 4) & 65535; + end if; - case lower(type) - when 'decimal' then scale = (typemod - 4) & 65535; - when 'numeric' then scale = (typemod - 4) & 65535; - else scale = null; - end case; - return scale; + return typemod; end; $$ language plpgsql immutable strict; diff --git a/contrib/shark/sql/test_sysviews.sql b/contrib/shark/sql/test_sysviews.sql index 68e7cfb876..b54c0b95b3 100644 --- a/contrib/shark/sql/test_sysviews.sql +++ b/contrib/shark/sql/test_sysviews.sql @@ -59,6 +59,12 @@ CREATE TABLE course credit DOUBLE PRECISION ); +create table teacher_salary +( + tec_id int, + tec_salary decimal(10, 2) +); + create or replace view teacher_info as select c.cla_name, t.tec_name, t.tec_job, t.tec_sex, t.tec_age from teacher t @@ -135,6 +141,7 @@ drop function test_sub; drop procedure test_sum; drop table t_log; drop view teacher_info; +drop table teacher_salary; drop table course; drop table school_department; drop table class; -- Gitee From 6971f6baee904a394ebd5616147baf6c0a71a8ac Mon Sep 17 00:00:00 2001 From: wangpingyun <2418191738@qq.com> Date: Fri, 21 Mar 2025 17:32:12 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dobject=5Fid=E4=B8=8Eobj?= =?UTF-8?q?ectproperty=E6=9F=A5=E6=89=BE=E7=BA=A6=E6=9D=9F=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/objectproperty.out | 128 +++++++++++++++++++++- contrib/shark/sql/objectproperty.sql | 24 +++- contrib/shark/varlena.cpp | 72 +++++++++--- 3 files changed, 205 insertions(+), 19 deletions(-) diff --git a/contrib/shark/expected/objectproperty.out b/contrib/shark/expected/objectproperty.out index 93561b4103..21719f109e 100644 --- a/contrib/shark/expected/objectproperty.out +++ b/contrib/shark/expected/objectproperty.out @@ -1,7 +1,7 @@ CREATE TABLE sys.students ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, - age INT, + age INT DEFAULT 0, grade DECIMAL(5, 2) ); NOTICE: CREATE TABLE will create implicit sequence "students_id_seq" for serial column "students.id" @@ -749,6 +749,132 @@ select objectproperty(object_id('trigger_update_total_grade'), 'istrigger') as i 1 (1 row) +select objectproperty(object_id('students_pkey'), 'istable') as istable; + istable +--------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'ownerid') as ownerid; + ownerid +--------- +--?.* +(1 row) + +select objectproperty(object_id('students_pkey'), 'isdefaultcnst') as isdefaultcnst; + isdefaultcnst +--------------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'execisquotedidenton') as execisquotedidenton; + execisquotedidenton +--------------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'isschemabound') as isschemabound; + isschemabound +--------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'execisansinullson') as execisansinullson; + execisansinullson +------------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; + tablefulltextpopulatestatus +----------------------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; + tablehasvardecimalstorageformat +--------------------------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'issysshipped') as issysshipped; + issysshipped +-------------- + 1 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isdeterministic') as isdeterministic; + isdeterministic +----------------- + +(1 row) + +select objectproperty(object_id('students_pkey'), 'isprocedure') asisprocedure; + asisprocedure +--------------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isview') as isview; + isview +-------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isusertable') as isusertable; + isusertable +------------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'istablefunction') as istablefunction; + istablefunction +----------------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isinlinefunction') as isinlinefunction; + isinlinefunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isscalarfunction') as isscalarfunction; + isscalarfunction +------------------ + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isprimarykey') as isprimarykey; + isprimarykey +-------------- + 1 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isindexed') as isindexed; + isindexed +----------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isdefault') as isdefault; + isdefault +----------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'isrule') as isrule; + isrule +-------- + 0 +(1 row) + +select objectproperty(object_id('students_pkey'), 'istrigger') as istrigger; + istrigger +----------- + 0 +(1 row) + --异常用例 CREATE TEMP TABLE sys.temp_sales ( product_name VARCHAR(255), diff --git a/contrib/shark/sql/objectproperty.sql b/contrib/shark/sql/objectproperty.sql index cb98d571f2..59b3970379 100644 --- a/contrib/shark/sql/objectproperty.sql +++ b/contrib/shark/sql/objectproperty.sql @@ -1,7 +1,7 @@ CREATE TABLE sys.students ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, - age INT, + age INT DEFAULT 0, grade DECIMAL(5, 2) ); @@ -170,6 +170,28 @@ select objectproperty(object_id('trigger_update_total_grade'), 'isdefault') as i select objectproperty(object_id('trigger_update_total_grade'), 'isrule') as isrule; select objectproperty(object_id('trigger_update_total_grade'), 'istrigger') as istrigger; +select objectproperty(object_id('students_pkey'), 'istable') as istable; +select objectproperty(object_id('students_pkey'), 'ownerid') as ownerid; +select objectproperty(object_id('students_pkey'), 'isdefaultcnst') as isdefaultcnst; +select objectproperty(object_id('students_pkey'), 'execisquotedidenton') as execisquotedidenton; +select objectproperty(object_id('students_pkey'), 'isschemabound') as isschemabound; +select objectproperty(object_id('students_pkey'), 'execisansinullson') as execisansinullson; +select objectproperty(object_id('students_pkey'), 'tablefulltextpopulatestatus') as tablefulltextpopulatestatus; +select objectproperty(object_id('students_pkey'), 'tablehasvardecimalstorageformat') as tablehasvardecimalstorageformat; +select objectproperty(object_id('students_pkey'), 'issysshipped') as issysshipped; +select objectproperty(object_id('students_pkey'), 'isdeterministic') as isdeterministic; +select objectproperty(object_id('students_pkey'), 'isprocedure') asisprocedure; +select objectproperty(object_id('students_pkey'), 'isview') as isview; +select objectproperty(object_id('students_pkey'), 'isusertable') as isusertable; +select objectproperty(object_id('students_pkey'), 'istablefunction') as istablefunction; +select objectproperty(object_id('students_pkey'), 'isinlinefunction') as isinlinefunction; +select objectproperty(object_id('students_pkey'), 'isscalarfunction') as isscalarfunction; +select objectproperty(object_id('students_pkey'), 'isprimarykey') as isprimarykey; +select objectproperty(object_id('students_pkey'), 'isindexed') as isindexed; +select objectproperty(object_id('students_pkey'), 'isdefault') as isdefault; +select objectproperty(object_id('students_pkey'), 'isrule') as isrule; +select objectproperty(object_id('students_pkey'), 'istrigger') as istrigger; + --异常用例 CREATE TEMP TABLE sys.temp_sales ( product_name VARCHAR(255), diff --git a/contrib/shark/varlena.cpp b/contrib/shark/varlena.cpp index f5daaa580f..66064376b4 100644 --- a/contrib/shark/varlena.cpp +++ b/contrib/shark/varlena.cpp @@ -29,6 +29,7 @@ #include #include +#include "access/sysattr.h" #include "knl/knl_variable.h" #include "commands/extension.h" #include "commands/dbcommands.h" @@ -82,8 +83,10 @@ Oid tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id); static char* get_physical_schema_name(char *db_name, const char *schema_name); static bool is_shared_schema(const char *name); static char* get_current_physical_schema_name(char* schema_name); +static Oid search_oid_in_class(char* obj_name, Oid schema_oid); static Oid search_oid_in_proc(char* obj_name, Oid schema_oid); static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid); +static Oid search_oid_in_cons(char* obj_name, Oid schema_oid); static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type); static int search_type_in_class(Oid* schema_id, Oid object_id, char* object_name); static int search_type_in_proc(Oid* schema_id, Oid object_id, char* object_name); @@ -91,7 +94,6 @@ static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name) static int search_type_in_cons(Oid* schema_id, Oid object_id, char* object_name); static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_name); static int dealwith_property(int type, Oid schema_id, Oid object_id, char* property); -static inline Oid search_oid_in_nsp(int cacheId, char* obj_name, Oid schema_oid); static inline int dealwith_type_ownerid(int type, Oid schema_id); static inline int dealwith_type_defcnst(int type); static inline int dealwith_type_exec_bound(int type, char* property); @@ -159,6 +161,53 @@ static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid) return id; } +static Oid search_oid_in_cons(char* obj_name, Oid schema_oid) +{ + Oid id = InvalidOid; + Relation tgrel; + ScanKeyData skeys[2]; + SysScanDesc tgscan; + HeapTuple tuple; + + ScanKeyInit(&skeys[0], Anum_pg_constraint_conname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(obj_name)); + + ScanKeyInit(&skeys[1], + Anum_pg_constraint_connamespace, + BTEqualStrategyNumber, + F_OIDEQ, + ObjectIdGetDatum(schema_oid)); + + tgrel = heap_open(ConstraintRelationId, AccessShareLock); + tgscan = systable_beginscan(tgrel, ConstraintNameNspIndexId, true, SnapshotNow, 2, skeys); + if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { + id = HeapTupleGetOid(tuple); + } + systable_endscan(tgscan); + heap_close(tgrel, AccessShareLock); + return id; +} + +static Oid search_oid_in_class(char* obj_name, Oid schema_oid) +{ + Oid id = InvalidOid; + HeapTuple tuple; + Form_pg_class classform; + + tuple = SearchSysCache2(RELNAMENSP, PointerGetDatum(obj_name), ObjectIdGetDatum(schema_oid)); + if (HeapTupleIsValid(tuple)) + { + classform = (Form_pg_class) GETSTRUCT(tuple); + if (classform->relkind == 'i' || classform->relkind == 'l') { + ReleaseSysCache(tuple); + return InvalidOid; + } + id = HeapTupleGetOid(tuple); + ReleaseSysCache(tuple); + } + + return id; +} + static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type) { Oid schema_oid = InvalidOid; @@ -190,10 +239,10 @@ static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_ if (strcmp(type_name, "S") == 0 || strcmp(type_name, "U") == 0 || strcmp(type_name, "V") == 0 || strcmp(type_name, "SO") == 0) { - id = search_oid_in_nsp(RELNAMENSP, obj_name, schema_oid); + id = search_oid_in_class(obj_name, schema_oid); } else if (strcmp(type_name, "C") == 0 || strcmp(type_name, "D") == 0 || strcmp(type_name, "F") == 0 || strcmp(type_name, "PK") == 0 || strcmp(type_name, "UQ") == 0) { - id = search_oid_in_nsp(CONNAMENSP, obj_name, schema_oid); + id = search_oid_in_cons(obj_name, schema_oid); } else if (strcmp(type_name, "AF") == 0 || strcmp(type_name, "FN") == 0 || strcmp(type_name, "P") == 0 || strcmp(type_name, "PC") == 0) { id = search_oid_in_proc(obj_name, schema_oid); @@ -206,10 +255,10 @@ static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_ } } else { if (id == InvalidOid) { - id = search_oid_in_nsp(RELNAMENSP, obj_name, schema_oid); + id = search_oid_in_class(obj_name, schema_oid); } if (id == InvalidOid) { - id = search_oid_in_nsp(CONNAMENSP, obj_name, schema_oid); + id = search_oid_in_cons(obj_name, schema_oid); } if (id == InvalidOid) { id = search_oid_in_proc(obj_name, schema_oid); @@ -375,7 +424,7 @@ static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name) attrdefrel = table_open(AttrDefaultRelationId, AccessShareLock); ScanKeyInit(&key, - Anum_pg_attrdef_adrelid, + ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object_id)); @@ -490,17 +539,6 @@ static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_na return type; } -static inline Oid search_oid_in_nsp(int cache_id, char* obj_name, Oid schema_oid) -{ - Oid id = InvalidOid; - HeapTuple relTuple = SearchSysCache2(cache_id, PointerGetDatum(obj_name), ObjectIdGetDatum(schema_oid)); - if (HeapTupleIsValid(relTuple)) { - id = HeapTupleGetOid(relTuple); - ReleaseSysCache(relTuple); - } - return id; -} - extern "C" Datum rand_seed(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(rand_seed); Datum rand_seed(PG_FUNCTION_ARGS) -- Gitee From ab447e83aef9a3c31d0cbbd31017c1bf72d694d1 Mon Sep 17 00:00:00 2001 From: wangpingyun <2418191738@qq.com> Date: Tue, 25 Mar 2025 16:53:39 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0dbcc=E7=9A=84=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/shark/expected/test_dbcc.out | 61 +++++++++++++++++++ contrib/shark/sql/test_dbcc.sql | 44 +++++++++++++ src/common/backend/parser/analyze.cpp | 2 +- .../optimizer/commands/sequence/sequence.cpp | 21 ++++--- 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/contrib/shark/expected/test_dbcc.out b/contrib/shark/expected/test_dbcc.out index f059f1940c..6b41a6ea24 100644 --- a/contrib/shark/expected/test_dbcc.out +++ b/contrib/shark/expected/test_dbcc.out @@ -340,6 +340,67 @@ CONTEXT: referenced column: dbcc_check_ident_reseed drop table Employees_no; drop table Employees_mu; drop table Employees_mi; +-- permission + CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); +NOTICE: CREATE TABLE will create implicit sequence "employees_employeeid_seq" for serial column "employees.employeeid" +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); +create user normalrole_user_001 password 'Gauss@123'; +create user normalrole_user_002 password 'Gauss@123'; +create user normalrole_user_003 password 'Gauss@123'; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_001; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_002; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_003; +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 +DBCC CHECKIDENT ('Employees', RESEED, 1); +ERROR: permission denied for sequence employees +CONTEXT: referenced column: dbcc_check_ident_reseed +RESET SESSION AUTHORIZATION; +SET SESSION AUTHORIZATION normalrole_user_002 PASSWORD 'Gauss@123'; +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees', RESEED, 1); +ERROR: permission denied for sequence employees +CONTEXT: referenced column: dbcc_check_ident_reseed +RESET SESSION AUTHORIZATION; +SET SESSION AUTHORIZATION normalrole_user_003 PASSWORD 'Gauss@123'; +DBCC CHECKIDENT ('Employees', NORESEED); +NOTICE: "Checking identity information: current identity value '4', current column value '4'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed + dbcc_check_ident_no_reseed +-------------------------------------------------------------------------------------- + Checking identity information: current identity value '4', current column value '4'. +(1 row) + +DBCC CHECKIDENT ('Employees', RESEED, 1); +NOTICE: "Checking identity information: current identity value '4'." +CONTEXT: referenced column: dbcc_check_ident_reseed + dbcc_check_ident_reseed +------------------------------------------------------------ + Checking identity information: current identity value '4'. +(1 row) + +RESET SESSION AUTHORIZATION; +drop user normalrole_user_001 cascade; +drop user normalrole_user_002 cascade; +drop user normalrole_user_003 cascade; +drop table Employees; -- 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 7a638a7869..fc5b833750 100644 --- a/contrib/shark/sql/test_dbcc.sql +++ b/contrib/shark/sql/test_dbcc.sql @@ -186,6 +186,50 @@ drop table Employees_no; drop table Employees_mu; drop table Employees_mi; + +-- permission + CREATE TABLE Employees ( + EmployeeID serial , + Name VARCHAR(100) NOT NULL + ); + +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); +insert into Employees(Name) values ('wangwu'); +insert into Employees(Name) values ('heliu'); + + + +create user normalrole_user_001 password 'Gauss@123'; +create user normalrole_user_002 password 'Gauss@123'; +create user normalrole_user_003 password 'Gauss@123'; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_001; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_002; +GRANT USAGE ON SCHEMA shark_test_dbcc TO normalrole_user_003; +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); +DBCC CHECKIDENT ('Employees', RESEED, 1); +RESET SESSION AUTHORIZATION; + + +SET SESSION AUTHORIZATION normalrole_user_002 PASSWORD 'Gauss@123'; +DBCC CHECKIDENT ('Employees', NORESEED); +DBCC CHECKIDENT ('Employees', RESEED, 1); +RESET SESSION AUTHORIZATION; + +SET SESSION AUTHORIZATION normalrole_user_003 PASSWORD 'Gauss@123'; +DBCC CHECKIDENT ('Employees', NORESEED); +DBCC CHECKIDENT ('Employees', RESEED, 1); +RESET SESSION AUTHORIZATION; + +drop user normalrole_user_001 cascade; +drop user normalrole_user_002 cascade; +drop user normalrole_user_003 cascade; +drop table Employees; + -- create table as create table t2(id int, name int); insert into t2 values (1, 1); diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index a5f551f97f..97b18c8a09 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -3076,7 +3076,7 @@ static Query* transformSelectStmt(ParseState* pstate, SelectStmt* stmt, bool isF qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset, EXPR_KIND_OFFSET, "OFFSET"); qry->limitCount = transformLimitClause(pstate, stmt->limitCount, EXPR_KIND_LIMIT, "LIMIT"); qry->limitIsPercent = stmt->limitIsPercent; - qry->limitWithTies = stmt->limitWithTies && stmt->sortClause != NIL; + qry->limitWithTies = stmt->limitWithTies; if (u_sess->hook_cxt.invokeTransformSelectForLimitHook) { ((InvokeTransformSelectForLimitHookType)(u_sess->hook_cxt.invokeTransformSelectForLimitHook))(stmt); } diff --git a/src/gausskernel/optimizer/commands/sequence/sequence.cpp b/src/gausskernel/optimizer/commands/sequence/sequence.cpp index 7edd6a9de1..edb1a5f49b 100644 --- a/src/gausskernel/optimizer/commands/sequence/sequence.cpp +++ b/src/gausskernel/optimizer/commands/sequence/sequence.cpp @@ -83,7 +83,7 @@ static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* ne bool* need_seq_rewrite); #endif template -static void do_setval(Oid relid, int128 next, bool iscalled); +static void do_setval(Oid relid, int128 next, bool iscalled, bool skip_perm_check = false); static void process_owned_by(const Relation seqrel, List* owned_by); template static GTM_UUID get_uuid_from_tuple(const void* seq_p, const Relation rel, const HeapTuple seqtuple); @@ -1748,7 +1748,7 @@ int128 autoinc_get_nextval(Oid relid) * sequence. */ template -static void do_setval(Oid relid, int128 next, bool iscalled) +static void do_setval(Oid relid, int128 next, bool iscalled, bool skip_perm_check) { SeqTable elm = NULL; Relation seqrel; @@ -1768,7 +1768,7 @@ static void do_setval(Oid relid, int128 next, bool iscalled) TrForbidAccessRbObject(RelationRelationId, relid, RelationGetRelationName(seqrel)); - if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + if (!skip_perm_check && pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); @@ -3202,7 +3202,7 @@ static Oid adbin_to_relid(char* adbin) return seqoid; } -char* get_serial_column_and_seq_table(List* range_var, char* table_name, Oid* seq_table_oid) +char* get_serial_column_and_seq_table(List* range_var, char* table_name, Oid* seq_table_oid, AclMode perm_required) { Relation rel = NULL; ScanKeyData skey; @@ -3213,6 +3213,13 @@ char* get_serial_column_and_seq_table(List* range_var, char* table_name, Oid* se rel = HeapOpenrvExtended(makeRangeVarFromNameList(range_var), AccessShareLock, false, true); check_relation_valid(rel, table_name); + if (pg_class_aclcheck(rel->rd_id, GetUserId(), perm_required, false) != ACLCHECK_OK) { + relation_close(rel, AccessShareLock); + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence %s", RelationGetRelationName(rel)))); + } + ScanKeyInit(&skey, Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(rel))); Relation adrel = heap_open(AttrDefaultRelationId, AccessShareLock); @@ -3273,7 +3280,7 @@ void get_last_value_and_max_value(text* txt, int64* last_value, int64* current_m char* table_name = TextDatumGetCString(txt); List* range_var = textToQualifiedNameList(txt); - serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid); + serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid, ACL_SELECT); /* open and lock sequence */ init_sequence(relid, &elm, &seqrel); @@ -3302,7 +3309,7 @@ int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed) List* range_var = textToQualifiedNameList(txt); char* table_name = TextDatumGetCString(txt); - serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid); + serial_column_name = get_serial_column_and_seq_table(range_var, table_name, &relid, ACL_UPDATE); /* open and lock sequence */ init_sequence(relid, &elm, &seqrel); @@ -3311,7 +3318,7 @@ int64 get_and_reset_last_value(text* txt, int64 new_value, bool need_reseed) // set new reseed if (need_reseed) { - do_setval(relid, new_value, true); + do_setval(relid, new_value, true, true); } pfree(serial_column_name); -- Gitee