From 00bd5eb0e4d64a85249d2728108552b91d4a987a Mon Sep 17 00:00:00 2001 From: totaj Date: Wed, 8 Mar 2023 20:23:34 +0800 Subject: [PATCH] fixed 64e79b1 from https://gitee.com/totaj/openGauss-server/pulls/3071 Add select into return null. --- src/common/backend/utils/misc/guc/guc_sql.cpp | 3 ++- src/common/pl/plpgsql/src/gram.y | 21 ++++++++++----- src/common/pl/plpgsql/src/pl_exec.cpp | 8 +++++- src/include/miscadmin.h | 5 +++- src/test/regress/expected/b_compatibility.out | 26 +++++++++++++++++++ src/test/regress/expected/function.out | 26 +++++++++++++++++++ src/test/regress/sql/b_compatibility.sql | 19 ++++++++++++++ src/test/regress/sql/function.sql | 17 ++++++++++++ 8 files changed, 116 insertions(+), 9 deletions(-) diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 3845f066f..420529c78 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -379,7 +379,8 @@ static const struct behavior_compat_entry behavior_compat_options[OPT_MAX] = { {"char_coerce_compat", OPT_CHAR_COERCE_COMPAT}, {"pgformat_substr", OPT_PGFORMAT_SUBSTR}, {"truncate_numeric_tail_zero", OPT_TRUNC_NUMERIC_TAIL_ZERO}, - {"allow_orderby_undistinct_column", OPT_ALLOW_ORDERBY_UNDISTINCT_COLUMN} + {"allow_orderby_undistinct_column", OPT_ALLOW_ORDERBY_UNDISTINCT_COLUMN}, + {"select_into_return_null", OPT_SELECT_INTO_RETURN_NULL} }; // increase SQL_IGNORE_STRATEGY_NUM if we need more strategy diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index 2a783fa43..39c7d8d49 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -181,7 +181,7 @@ static char *NameOfDatum(PLwdatum *wdatum); static char *CopyNameOfDatum(PLwdatum *wdatum); static void check_assignable(PLpgSQL_datum *datum, int location); static bool read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, - bool *strict, bool bulk_collect); + bool *strict, int firsttoken, bool bulk_collect); static PLpgSQL_row *read_into_scalar_list(char *initial_name, PLpgSQL_datum *initial_datum, int initial_dno, @@ -5060,7 +5060,7 @@ stmt_dynexecute : K_EXECUTE if (newp->into) /* multiple INTO */ yyerror("syntax error"); newp->into = true; - (void)read_into_target(&newp->rec, &newp->row, &newp->strict, false); + (void)read_into_target(&newp->rec, &newp->row, &newp->strict, K_EXECUTE, false); endtoken = yylex(); } /* If we found "USING", collect the argument */ @@ -5209,7 +5209,7 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO PLpgSQL_row *row; /* We have already parsed everything through the INTO keyword */ - (void)read_into_target(&rec, &row, NULL, false); + (void)read_into_target(&rec, &row, NULL, -1, false); if (yylex() != ';') yyerror("syntax error"); @@ -5308,7 +5308,7 @@ fetch_into_target : PLpgSQL_datum *datum = NULL; PLpgSQL_rec *rec; PLpgSQL_row *row; - (void)read_into_target(&rec, &row, NULL, true); + (void)read_into_target(&rec, &row, NULL, -1, true); if (rec != NULL) { datum = (PLpgSQL_datum *)rec; @@ -9388,7 +9388,7 @@ make_execsql_stmt(int firsttoken, int location) into_start_loc = yylloc; } u_sess->plsql_cxt.curr_compile_context->plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; - is_user_var = read_into_target(&rec, &row, &have_strict, have_bulk_collect); + is_user_var = read_into_target(&rec, &row, &have_strict, firsttoken, have_bulk_collect); if (is_user_var) { u_sess->plsql_cxt.curr_compile_context->plpgsql_IdentifierLookup = save_IdentifierLookup; have_into = false; @@ -10770,15 +10770,24 @@ read_into_using_add_tableelem(char **fieldnames, int *varnos, int *nfields, int * INTO keyword. If it is into_user_defined_variable_list_clause return true. */ static bool -read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict, bool bulk_collect) +read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict, int firsttoken, bool bulk_collect) { int tok; /* Set default results */ *rec = NULL; *row = NULL; + if (strict) { + if (DB_IS_CMPT(PG_FORMAT | B_FORMAT) && firsttoken == K_SELECT && SELECT_INTO_RETURN_NULL) { + *strict = false; + } else { + *strict = true; + } + } +#ifdef ENABLE_MULTIPLE_NODES if (strict) *strict = true; +#endif tok = yylex(); if (tok == '@' || tok == SET_USER_IDENT) { return true; diff --git a/src/common/pl/plpgsql/src/pl_exec.cpp b/src/common/pl/plpgsql/src/pl_exec.cpp index 12f1b9b7c..d57f0cb3a 100644 --- a/src/common/pl/plpgsql/src/pl_exec.cpp +++ b/src/common/pl/plpgsql/src/pl_exec.cpp @@ -5895,10 +5895,16 @@ static int exec_stmt_execsql(PLpgSQL_execstate* estate, PLpgSQL_stmt_execsql* st * to enforce strictness. */ if (stmt->into) { + if (!stmt->mod_stmt & !stmt->bulk_collect) { + if (!DB_IS_CMPT(PG_FORMAT | B_FORMAT) || SELECT_INTO_RETURN_NULL == 0) { + stmt->strict = true; + } + } +#ifdef ENABLE_MULTIPLE_NODES if (!stmt->mod_stmt & !stmt->bulk_collect) { stmt->strict = true; } - +#endif if (stmt->bulk_collect) { tcount = 0; } else if (stmt->strict || stmt->mod_stmt) { diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f745b1a94..f7f203cf6 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -178,7 +178,8 @@ extern bool contain_backend_version(uint32 version_number); #define OPT_PGFORMAT_SUBSTR 8388608 #define OPT_TRUNC_NUMERIC_TAIL_ZERO 16777216 #define OPT_ALLOW_ORDERBY_UNDISTINCT_COLUMN 33554432 -#define OPT_MAX 26 +#define OPT_SELECT_INTO_RETURN_NULL 67108864 +#define OPT_MAX 27 #define PLPSQL_OPT_FOR_LOOP 1 #define PLPSQL_OPT_OUTPARAM 2 @@ -217,6 +218,8 @@ extern bool contain_backend_version(uint32 version_number); #define PLSQL_COMPILE_FOR_LOOP (u_sess->utils_cxt.plsql_compile_behavior_compat_flags & PLPSQL_OPT_FOR_LOOP) #define PLSQL_COMPILE_OUTPARAM (u_sess->utils_cxt.plsql_compile_behavior_compat_flags & PLPSQL_OPT_OUTPARAM) + +#define SELECT_INTO_RETURN_NULL (u_sess->utils_cxt.behavior_compat_flags & OPT_SELECT_INTO_RETURN_NULL) /* define database compatibility Attribute */ typedef struct { diff --git a/src/test/regress/expected/b_compatibility.out b/src/test/regress/expected/b_compatibility.out index e194ad628..78fe41d31 100644 --- a/src/test/regress/expected/b_compatibility.out +++ b/src/test/regress/expected/b_compatibility.out @@ -2462,6 +2462,32 @@ until i >p1 end repeat; raise notice '%',i; end drop function if exists dorepeat; +set behavior_compat_options='select_into_return_null'; +create table test_table_030(id int, name text); +insert into test_table_030 values(1,'a'),(2,'b'); +CREATE OR REPLACE FUNCTION select_into_null_func(canshu varchar(16)) +returns int +as $$ +DECLARE test_table_030a int; +begin + SELECT ID into test_table_030a FROM test_table_030 WHERE NAME = canshu; + return test_table_030a; +end; $$ language plpgsql; +select select_into_null_func('aaa'); + select_into_null_func +----------------------- + +(1 row) + +select select_into_null_func('aaa') is null; + ?column? +---------- + t +(1 row) + +drop table test_table_030; +drop function select_into_null_func; +reset behavior_compat_options; \c regression drop database b; DROP USER test_c; diff --git a/src/test/regress/expected/function.out b/src/test/regress/expected/function.out index 3c2c9e675..871e0bbf0 100644 --- a/src/test/regress/expected/function.out +++ b/src/test/regress/expected/function.out @@ -1617,5 +1617,31 @@ DROP FUNCTION func_increment_sql_1; DROP FUNCTION func_increment_sql_2; DROP FUNCTION fun_test_1; DROP FUNCTION fun_test_2; +set behavior_compat_options='select_into_return_null'; +create table test_table_030(id int, name text); +insert into test_table_030 values(1,'a'),(2,'b'); +CREATE OR REPLACE FUNCTION select_into_null_func(canshu varchar(16)) +returns int +as $$ +DECLARE test_table_030a int; +begin + SELECT ID into test_table_030a FROM test_table_030 WHERE NAME = canshu; + return test_table_030a; +end; $$ language plpgsql; +select select_into_null_func('aaa'); + select_into_null_func +----------------------- + +(1 row) + +select select_into_null_func('aaa') is null; + ?column? +---------- + t +(1 row) + +drop table test_table_030; +drop function select_into_null_func; +reset behavior_compat_options; \c regression; drop database IF EXISTS pl_test_funcion; diff --git a/src/test/regress/sql/b_compatibility.sql b/src/test/regress/sql/b_compatibility.sql index 305ab4a2e..c0cff721d 100644 --- a/src/test/regress/sql/b_compatibility.sql +++ b/src/test/regress/sql/b_compatibility.sql @@ -1481,6 +1481,25 @@ end; / drop function if exists dorepeat; + +set behavior_compat_options='select_into_return_null'; +create table test_table_030(id int, name text); +insert into test_table_030 values(1,'a'),(2,'b'); +CREATE OR REPLACE FUNCTION select_into_null_func(canshu varchar(16)) +returns int +as $$ +DECLARE test_table_030a int; +begin + SELECT ID into test_table_030a FROM test_table_030 WHERE NAME = canshu; + return test_table_030a; +end; $$ language plpgsql; +select select_into_null_func('aaa'); +select select_into_null_func('aaa') is null; + +drop table test_table_030; +drop function select_into_null_func; +reset behavior_compat_options; + \c regression drop database b; DROP USER test_c; diff --git a/src/test/regress/sql/function.sql b/src/test/regress/sql/function.sql index a733cfe8d..4968cf482 100644 --- a/src/test/regress/sql/function.sql +++ b/src/test/regress/sql/function.sql @@ -934,5 +934,22 @@ DROP FUNCTION func_increment_sql_2; DROP FUNCTION fun_test_1; DROP FUNCTION fun_test_2; +set behavior_compat_options='select_into_return_null'; +create table test_table_030(id int, name text); +insert into test_table_030 values(1,'a'),(2,'b'); +CREATE OR REPLACE FUNCTION select_into_null_func(canshu varchar(16)) +returns int +as $$ +DECLARE test_table_030a int; +begin + SELECT ID into test_table_030a FROM test_table_030 WHERE NAME = canshu; + return test_table_030a; +end; $$ language plpgsql; +select select_into_null_func('aaa'); +select select_into_null_func('aaa') is null; + +drop table test_table_030; +drop function select_into_null_func; +reset behavior_compat_options; \c regression; drop database IF EXISTS pl_test_funcion;