From df8982a2cdee9cbc4c7e98214a24d403c1c043d5 Mon Sep 17 00:00:00 2001 From: wangfeihuo Date: Tue, 22 Apr 2025 11:49:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8C=BF=E5=90=8D=E5=9D=97?= =?UTF-8?q?=E4=B8=AD=E4=BD=BF=E7=94=A8dbcc=E6=8A=A5=E9=94=99=E7=9A=84?= =?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/test_dbcc.out | 60 +++++++++ contrib/shark/shark--1.0.sql | 15 +-- contrib/shark/sql/test_dbcc.sql | 38 ++++++ .../shark/src/backend_parser/gram-tsql-decl.y | 2 +- .../backend_parser/gram-tsql-epilogue.y.cpp | 42 ++++++ .../src/backend_parser/gram-tsql-prologue.y.h | 4 +- .../shark/src/backend_parser/gram-tsql-rule.y | 125 +++++++++++++++++- 7 files changed, 274 insertions(+), 12 deletions(-) diff --git a/contrib/shark/expected/test_dbcc.out b/contrib/shark/expected/test_dbcc.out index 19bf43b165..c56f76a987 100644 --- a/contrib/shark/expected/test_dbcc.out +++ b/contrib/shark/expected/test_dbcc.out @@ -555,6 +555,66 @@ CONTEXT: referenced column: dbcc_check_ident_no_reseed (1 row) drop table Employees1; +-- ANONYMOUS BLOCK +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'); +begin + DBCC CHECKIDENT ('Employees', NORESEED); +end; +/ +NOTICE: "Checking identity information: current identity value '2', current column value '2'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed +SQL statement "DBCC CHECKIDENT ('Employees', NORESEED)" +PL/pgSQL function inline_code_block line 2 at PERFORM +begin + DBCC CHECKIDENT ('Employees', RESEED, 5); +end; +/ +NOTICE: "Checking identity information: current identity value '2'." +CONTEXT: referenced column: dbcc_check_ident_reseed +SQL statement "DBCC CHECKIDENT ('Employees', RESEED, 5)" +PL/pgSQL function inline_code_block line 2 at PERFORM +CREATE FUNCTION func_20_1() RETURN integer +AS +BEGIN + DBCC CHECKIDENT ('Employees', NORESEED); + RETURN 0; +END; +/ +select func_20_1(); +NOTICE: "Checking identity information: current identity value '5', current column value '2'." +CONTEXT: referenced column: dbcc_check_ident_no_reseed +SQL statement "DBCC CHECKIDENT ('Employees', NORESEED)" +PL/pgSQL function func_20_1() line 2 at PERFORM +referenced column: func_20_1 + func_20_1 +----------- + 0 +(1 row) + +CREATE FUNCTION func_20_2() RETURN integer +AS +BEGIN + DBCC CHECKIDENT ('Employees', RESEED, 5); + RETURN 0; +END; +/ +select func_20_2(); +NOTICE: "Checking identity information: current identity value '5'." +CONTEXT: referenced column: dbcc_check_ident_reseed +SQL statement "DBCC CHECKIDENT ('Employees', RESEED, 5)" +PL/pgSQL function func_20_2() line 2 at PERFORM +referenced column: func_20_2 + func_20_2 +----------- + 0 +(1 row) + +drop TABLE Employees; +drop FUNCTION func_20_2(); +drop FUNCTION func_20_1(); -- create table as create table t2(id int, name int); insert into t2 values (1, 1); diff --git a/contrib/shark/shark--1.0.sql b/contrib/shark/shark--1.0.sql index 5ce296042b..dd91971d4f 100644 --- a/contrib/shark/shark--1.0.sql +++ b/contrib/shark/shark--1.0.sql @@ -11,6 +11,13 @@ create function pltsql_validator(oid) create function pltsql_inline_handler(internal) returns void as 'MODULE_PATHNAME' language C; +create trusted language pltsql + handler pltsql_call_handler + inline pltsql_inline_handler + validator pltsql_validator; + +grant usage on language pltsql to public; + 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)'; @@ -44,16 +51,8 @@ RETURNS INT AS '$libdir/shark', 'objectproperty_internal' LANGUAGE C STABLE; -create trusted language pltsql - handler pltsql_call_handler - inline pltsql_inline_handler - validator pltsql_validator; - - CREATE FUNCTION dbcc_check_ident_no_reseed(varchar, boolean, 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() returns int as 'MODULE_PATHNAME' language C; diff --git a/contrib/shark/sql/test_dbcc.sql b/contrib/shark/sql/test_dbcc.sql index 5f7a61d1b9..1bed7f0bdb 100644 --- a/contrib/shark/sql/test_dbcc.sql +++ b/contrib/shark/sql/test_dbcc.sql @@ -289,6 +289,44 @@ DBCC CHECKIDENT ('Employees1', NORESEED); drop table Employees1; + +-- ANONYMOUS BLOCK +CREATE TABLE Employees (EmployeeID serial ,Name VARCHAR(100) NOT NULL); +insert into Employees(Name) values ('zhangsan'); +insert into Employees(Name) values ('lisi'); + +begin + DBCC CHECKIDENT ('Employees', NORESEED); +end; +/ + +begin + DBCC CHECKIDENT ('Employees', RESEED, 5); +end; +/ + +CREATE FUNCTION func_20_1() RETURN integer +AS +BEGIN + DBCC CHECKIDENT ('Employees', NORESEED); + RETURN 0; +END; +/ +select func_20_1(); + +CREATE FUNCTION func_20_2() RETURN integer +AS +BEGIN + DBCC CHECKIDENT ('Employees', RESEED, 5); + RETURN 0; +END; +/ +select func_20_2(); + +drop TABLE Employees; +drop FUNCTION func_20_2(); +drop FUNCTION func_20_1(); + -- create table as create table t2(id int, name int); insert into t2 values (1, 1); diff --git a/contrib/shark/src/backend_parser/gram-tsql-decl.y b/contrib/shark/src/backend_parser/gram-tsql-decl.y index b284521b6a..c7a876f72e 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-decl.y +++ b/contrib/shark/src/backend_parser/gram-tsql-decl.y @@ -5,7 +5,7 @@ %type tsql_opt_clustered tsql_opt_columnstore %token TSQL_ATAT_IDENT %type opt_with_no_infomsgs -%type TSQL_computed_column +%type TSQL_computed_column TSQL_AnonyBlockStmt TSQL_CreateFunctionStmt %type tsql_top_clause tsql_select_top_value %type tsql_opt_ties tsql_opt_percent %type DirectColLabel 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 122b724fdf..fdf977b494 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp +++ b/contrib/shark/src/backend_parser/gram-tsql-epilogue.y.cpp @@ -67,5 +67,47 @@ static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner) } } +// To make a node for anonymous block +static Node * +TsqlMakeAnonyBlockFuncStmt(int flag, const char *str) +{ + DoStmt *n = makeNode(DoStmt); + char *str_body = NULL; + DefElem * body = NULL; + errno_t rc = EOK; + + if (BEGIN_P == flag) + { + int len1 = strlen("DECLARE \nBEGIN "); + int len2 = strlen(str); + str_body = (char *)palloc(len1 + len2 + 1); + rc = strncpy_s(str_body, len1 + len2 + 1, "DECLARE \nBEGIN ",len1); + securec_check(rc, "\0", "\0"); + rc = strcpy_s(str_body + len1, len2 + 1, str); + securec_check(rc, "\0", "\0"); + } + else + { + int len1 = strlen("DECLARE "); + int len2 = strlen(str); + str_body = (char *)palloc(len1 + len2 + 1); + rc = strncpy_s(str_body, len1 + len2 + 1, "DECLARE ", len1); + securec_check(rc, "\0", "\0"); + rc = strcpy_s(str_body + len1, len2 + 1, str); + securec_check(rc, "\0", "\0"); + } + + body = makeDefElem("as", (Node*)makeString(str_body)); + if (get_language_oid("pltsql", true) != InvalidOid) { + n->args = list_make1(makeDefElem("language", (Node *)makeString("pltsql"))); + } else { + n->args = list_make1(makeDefElem("language", (Node *)makeString("plpgsql"))); + } + + n->args = lappend( n->args, body); + + return (Node*)n; +} + #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 53123d6cec..dc3c7cc60f 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/shark/src/backend_parser/gram-tsql-prologue.y.h @@ -3,4 +3,6 @@ List *TsqlSystemFuncName2(char *name); static List* make_no_reseed_func(char* table_name, bool with_no_msgs, bool reseed_to_max); 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 +static char* quote_identifier_wrapper(char* ident, core_yyscan_t yyscanner); +static Node* TsqlMakeAnonyBlockFuncStmt(int flag, const char *str); +extern Oid get_language_oid(const char* langname, bool missing_ok); \ 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 5e032592c9..2c11055c81 100644 --- a/contrib/shark/src/backend_parser/gram-tsql-rule.y +++ b/contrib/shark/src/backend_parser/gram-tsql-rule.y @@ -573,6 +573,127 @@ DBCCStmt: DBCCCheckIdentStmt } ; +TSQL_AnonyBlockStmt: + DECLARE { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = false; } subprogram_body + { + $$ = (Node *)TsqlMakeAnonyBlockFuncStmt(DECLARE, ((FunctionSources*)$3)->bodySrc); + } + | BEGIN_P { u_sess->parser_cxt.eaten_declare = true; u_sess->parser_cxt.eaten_begin = true; } subprogram_body + { + $$ = (Node *)TsqlMakeAnonyBlockFuncStmt(BEGIN_P, ((FunctionSources*)$3)->bodySrc); + } + ; + + +TSQL_CreateFunctionStmt: + CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args + RETURNS func_return createfunc_opt_list opt_definition + { + set_function_style_pg(); + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + n->isOraStyle = false; + n->isPrivate = false; + n->replace = $2; + n->definer = $3; + if (n->replace && NULL != n->definer) { + parser_yyerror("not support DEFINER function"); + } + n->funcname = $5; + n->parameters = $6; + n->returnType = $8; + n->options = $9; + n->withClause = $10; + n->isProcedure = false; + $$ = (Node *)n; + } + | CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args + RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition + { + set_function_style_pg(); + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + n->isOraStyle = false; + n->isPrivate = false; + n->replace = $2; + n->definer = $3; + if (n->replace && NULL != n->definer) { + parser_yyerror("not support DEFINER function"); + } + n->funcname = $5; + n->parameters = mergeTableFuncParameters($6, $10); + n->returnType = TableFuncTypeName($10); + n->returnType->location = @8; + n->options = $12; + n->withClause = $13; + n->isProcedure = false; + $$ = (Node *)n; + } + | CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args + createfunc_opt_list opt_definition + { + set_function_style_pg(); + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + n->isOraStyle = false; + n->isPrivate = false; + n->replace = $2; + n->definer = $3; + if (n->replace && NULL != n->definer) { + parser_yyerror("not support DEFINER function"); + } + n->funcname = $5; + n->parameters = $6; + n->returnType = NULL; + n->options = $7; + n->withClause = $8; + n->isProcedure = false; + $$ = (Node *)n; + } + | CREATE opt_or_replace definer_user FUNCTION func_name_opt_arg proc_args + RETURN func_return opt_createproc_opt_list as_is { + u_sess->parser_cxt.eaten_declare = false; + u_sess->parser_cxt.eaten_begin = false; + pg_yyget_extra(yyscanner)->core_yy_extra.include_ora_comment = true; + u_sess->parser_cxt.isCreateFuncOrProc = true; + if (set_is_create_plsql_type()) { + set_create_plsql_type_start(); + set_function_style_a(); + } + } subprogram_body + { + int rc = 0; + rc = CompileWhich(); + if (rc == PLPGSQL_COMPILE_PROC || rc == PLPGSQL_COMPILE_NULL) { + u_sess->plsql_cxt.procedure_first_line = GetLineNumber(t_thrd.postgres_cxt.debug_query_string, @10); + } + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); + FunctionSources *funcSource = (FunctionSources *)$12; + n->isOraStyle = true; + n->isPrivate = false; + n->replace = $2; + n->definer = $3; + if (n->replace && NULL != n->definer) { + parser_yyerror("not support DEFINER function"); + } + n->funcname = $5; + n->parameters = $6; + n->inputHeaderSrc = FormatFuncArgType(yyscanner, funcSource->headerSrc, n->parameters); + if (enable_plpgsql_gsdependency_guc()) { + n->funcHeadSrc = ParseFuncHeadSrc(yyscanner); + } + n->returnType = $8; + n->options = $9; + n->options = lappend(n->options, makeDefElem("as", + (Node *)list_make1(makeString(funcSource->bodySrc)))); + n->options = lappend(n->options, makeDefElem("language", + (Node *)makeString("pltsql"))); + + n->withClause = NIL; + n->withClause = NIL; + n->isProcedure = false; + u_sess->parser_cxt.isCreateFuncOrProc = false; + $$ = (Node *)n; + } + ; + tsql_stmt : AlterAppWorkloadGroupMappingStmt @@ -617,7 +738,7 @@ tsql_stmt : | AlterUserStmt | AlterWorkloadGroupStmt | AnalyzeStmt - | AnonyBlockStmt + | TSQL_AnonyBlockStmt | BarrierStmt | CreateAppWorkloadGroupMappingStmt | CallFuncStmt @@ -644,7 +765,7 @@ tsql_stmt : | CreateForeignServerStmt | CreateForeignTableStmt | CreateDataSourceStmt - | CreateFunctionStmt + | TSQL_CreateFunctionStmt | CreateEventStmt | AlterEventStmt | DropEventStmt -- Gitee