From 611444bb8b3a8d9521cb21b5a05434bd53b68278 Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Wed, 12 Jun 2024 21:34:05 +0200 Subject: [PATCH 1/3] use strict rules for parsing PL/pgSQL expressions Originally the rule PLpgSQL_Expr allows almost all SQL clauses. It was designed to allow old undocumented syntax var := col FROM tab; The reason for support of this "strange" syntax was technical. The PLpgSQL parser cannot use SQL parser accurately (it was really primitive), and people found this undocumented syntax. Lattery, when it was possible to do exact parsing, from compatibility reasons, the parsing of PL/pgSQL expressions allows described syntax. Unfortunately, with support almost all SQL clauses, the PLpgSQL can accept really broken code like DO $$ DECLARE l_cnt int; BEGIN l_cnt := 1 DELETE FROM foo3 WHERE id=1; END; $$; proposed patch introduce new extra error check strict_expr_check, that solve this issue. --- doc/src/sgml/plpgsql.sgml | 19 ++++ src/pl/plpgsql/src/pl_comp.c | 7 ++ src/pl/plpgsql/src/pl_gram.y | 138 ++++++++++++++++++++++---- src/pl/plpgsql/src/pl_handler.c | 2 + src/pl/plpgsql/src/plpgsql.h | 1 + src/test/regress/expected/plpgsql.out | 14 +++ src/test/regress/sql/plpgsql.sql | 14 +++ 7 files changed, 177 insertions(+), 18 deletions(-) diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index e937491e6b89..cbe5c2be28b8 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -5388,6 +5388,25 @@ a_output := a_output || $$ if v_$$ || referrer_keys.kind || $$ like '$$ + + + strict_expr_check + + + Enabling this check will cause PL/pgSQL to + check if a PL/pgSQL expression is just an + expression without any SQL clauses like FROM, + ORDER BY. This undocumented form of expressions + is allowed for compatibility reasons, but in some special cases + it doesn't allow to detect broken code. + + + + This check is allowed only when plpgsql.extra_errors + is set to "strict_expr_check". + + + The following example shows the effect of plpgsql.extra_warnings diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 519f7695d7c1..c015e4de9888 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -786,6 +786,13 @@ plpgsql_compile_inline(char *proc_source) function->extra_warnings = 0; function->extra_errors = 0; + /* + * Although function->extra_errors is disabled, we want to + * do strict_expr_check inside annoymous block too. + */ + if (plpgsql_extra_errors & PLPGSQL_XCHECK_STRICTEXPRCHECK) + function->extra_errors = PLPGSQL_XCHECK_STRICTEXPRCHECK; + function->nstatements = 0; function->requires_procedure_resowner = false; function->has_exception_block = false; diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 5612e66d0239..dcc581afdbf2 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -18,6 +18,7 @@ #include "catalog/namespace.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "nodes/nodeFuncs.h" #include "parser/parser.h" #include "parser/parse_type.h" #include "parser/scanner.h" @@ -71,6 +72,7 @@ static PLpgSQL_expr *read_sql_construct(int until, const char *expected, RawParseMode parsemode, bool isexpression, + bool allowlist, bool valid_sql, int *startloc, int *endtoken, @@ -106,7 +108,7 @@ static PLpgSQL_row *make_scalar_list1(char *initial_name, PLpgSQL_datum *initial_datum, int lineno, int location, yyscan_t yyscanner); static void check_sql_expr(const char *stmt, - RawParseMode parseMode, int location, yyscan_t yyscanner); + RawParseMode parseMode, bool allowlist, int location, yyscan_t yyscanner); static void plpgsql_sql_error_callback(void *arg); static PLpgSQL_type *parse_datatype(const char *string, int location, yyscan_t yyscanner); static void check_labels(const char *start_label, @@ -117,6 +119,7 @@ static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static List *read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner); static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); +static bool is_strict_expr(List *parsetree, int *errpos, bool allowlist); %} @@ -193,6 +196,7 @@ static void check_raise_parameters(PLpgSQL_stmt_raise *stmt); %type expr_until_semi %type expr_until_then expr_until_loop opt_expr_until_when %type opt_exitcond +%type expressions_until_then %type cursor_variable %type decl_cursor_arg @@ -914,7 +918,7 @@ stmt_perform : K_PERFORM */ new->expr = read_sql_construct(';', 0, 0, ";", RAW_PARSE_DEFAULT, - false, false, + false, false, false, &startloc, NULL, &yylval, &yylloc, yyscanner); /* overwrite "perform" ... */ @@ -924,7 +928,7 @@ stmt_perform : K_PERFORM strlen(new->expr->query)); /* offset syntax error position to account for that */ check_sql_expr(new->expr->query, new->expr->parseMode, - startloc + 1, yyscanner); + false, startloc + 1, yyscanner); $$ = (PLpgSQL_stmt *) new; } @@ -1001,7 +1005,7 @@ stmt_assign : T_DATUM plpgsql_push_back_token(T_DATUM, &yylval, &yylloc, yyscanner); new->expr = read_sql_construct(';', 0, 0, ";", pmode, - false, true, + false, false, true, NULL, NULL, &yylval, &yylloc, yyscanner); mark_expr_as_assignment_source(new->expr, $1.datum); @@ -1262,7 +1266,7 @@ case_when_list : case_when_list case_when } ; -case_when : K_WHEN expr_until_then proc_sect +case_when : K_WHEN expressions_until_then proc_sect { PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when)); @@ -1292,6 +1296,15 @@ opt_case_else : } ; +expressions_until_then : + { + $$ = read_sql_construct(K_THEN, 0, 0, "THEN", + RAW_PARSE_PLPGSQL_EXPR, /* expr_list */ + true, true, true, NULL, NULL, + &yylval, &yylloc, yyscanner); + } + ; + stmt_loop : opt_loop_label K_LOOP loop_body { PLpgSQL_stmt_loop *new; @@ -1495,6 +1508,7 @@ for_control : for_variable K_IN RAW_PARSE_DEFAULT, true, false, + false, &expr1loc, &tok, &yylval, &yylloc, yyscanner); @@ -1513,7 +1527,7 @@ for_control : for_variable K_IN */ expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR; check_sql_expr(expr1->query, expr1->parseMode, - expr1loc, yyscanner); + false, expr1loc, yyscanner); /* Read and check the second one */ expr2 = read_sql_expression2(K_LOOP, K_BY, @@ -1570,7 +1584,7 @@ for_control : for_variable K_IN /* Check syntax as a regular query */ check_sql_expr(expr1->query, expr1->parseMode, - expr1loc, yyscanner); + false, expr1loc, yyscanner); new = palloc0(sizeof(PLpgSQL_stmt_fors)); new->cmd_type = PLPGSQL_STMT_FORS; @@ -1902,7 +1916,7 @@ stmt_raise : K_RAISE expr = read_sql_construct(',', ';', K_USING, ", or ; or USING", RAW_PARSE_PLPGSQL_EXPR, - true, true, + true, false, true, NULL, &tok, &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); @@ -2040,7 +2054,7 @@ stmt_dynexecute : K_EXECUTE expr = read_sql_construct(K_INTO, K_USING, ';', "INTO or USING or ;", RAW_PARSE_PLPGSQL_EXPR, - true, true, + true, false, true, NULL, &endtoken, &yylval, &yylloc, yyscanner); @@ -2080,7 +2094,7 @@ stmt_dynexecute : K_EXECUTE expr = read_sql_construct(',', ';', K_INTO, ", or ; or INTO", RAW_PARSE_PLPGSQL_EXPR, - true, true, + true, false, true, NULL, &endtoken, &yylval, &yylloc, yyscanner); new->params = lappend(new->params, expr); @@ -2713,7 +2727,7 @@ read_sql_expression(int until, const char *expected, YYSTYPE *yylvalp, YYLTYPE * { return read_sql_construct(until, 0, 0, expected, RAW_PARSE_PLPGSQL_EXPR, - true, true, NULL, NULL, + true, false, true, NULL, NULL, yylvalp, yyllocp, yyscanner); } @@ -2724,7 +2738,7 @@ read_sql_expression2(int until, int until2, const char *expected, { return read_sql_construct(until, until2, 0, expected, RAW_PARSE_PLPGSQL_EXPR, - true, true, NULL, endtoken, + true, false, true, NULL, endtoken, yylvalp, yyllocp, yyscanner); } @@ -2734,7 +2748,7 @@ read_sql_stmt(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) { return read_sql_construct(';', 0, 0, ";", RAW_PARSE_DEFAULT, - false, true, NULL, NULL, + false, false, true, NULL, NULL, yylvalp, yyllocp, yyscanner); } @@ -2747,6 +2761,7 @@ read_sql_stmt(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner) * expected: text to use in complaining that terminator was not found * parsemode: raw_parser() mode to use * isexpression: whether to say we're reading an "expression" or a "statement" + * allowlist: the result can be list of expressions * valid_sql: whether to check the syntax of the expr * startloc: if not NULL, location of first token is stored at *startloc * endtoken: if not NULL, ending token is stored at *endtoken @@ -2759,6 +2774,7 @@ read_sql_construct(int until, const char *expected, RawParseMode parsemode, bool isexpression, + bool allowlist, bool valid_sql, int *startloc, int *endtoken, @@ -2854,7 +2870,7 @@ read_sql_construct(int until, pfree(ds.data); if (valid_sql) - check_sql_expr(expr->query, expr->parseMode, startlocation, yyscanner); + check_sql_expr(expr->query, expr->parseMode, allowlist, startlocation, yyscanner); return expr; } @@ -3175,7 +3191,7 @@ make_execsql_stmt(int firsttoken, int location, PLword *word, YYSTYPE *yylvalp, expr = make_plpgsql_expr(ds.data, RAW_PARSE_DEFAULT); pfree(ds.data); - check_sql_expr(expr->query, expr->parseMode, location, yyscanner); + check_sql_expr(expr->query, expr->parseMode, false, location, yyscanner); execsql = palloc0(sizeof(PLpgSQL_stmt_execsql)); execsql->cmd_type = PLPGSQL_STMT_EXECSQL; @@ -3775,11 +3791,15 @@ make_scalar_list1(char *initial_name, * If no error cursor is provided, we'll just point at "location". */ static void -check_sql_expr(const char *stmt, RawParseMode parseMode, int location, yyscan_t yyscanner) +check_sql_expr(const char *stmt, + RawParseMode parseMode, bool allowlist, + int location, yyscan_t yyscanner) { sql_error_callback_arg cbarg; ErrorContextCallback syntax_errcontext; MemoryContext oldCxt; + List *parsetree; + int errpos; if (!plpgsql_check_syntax) return; @@ -3793,11 +3813,25 @@ check_sql_expr(const char *stmt, RawParseMode parseMode, int location, yyscan_t error_context_stack = &syntax_errcontext; oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt); - (void) raw_parser(stmt, parseMode); + parsetree = raw_parser(stmt, parseMode); MemoryContextSwitchTo(oldCxt); /* Restore former ereport callback */ error_context_stack = syntax_errcontext.previous; + + if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_STRICTEXPRCHECK || + plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_STRICTEXPRCHECK) + { + /* do this check only for expressions */ + if (parseMode == RAW_PARSE_DEFAULT) + return; + + if (!is_strict_expr(parsetree, &errpos, allowlist)) + ereport(plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_STRICTEXPRCHECK ? ERROR : WARNING, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("syntax of expression is not strict"), + parser_errposition(errpos != -1 ? location + errpos : location))); + } } static void @@ -3831,6 +3865,74 @@ plpgsql_sql_error_callback(void *arg) errposition(0); } +/* + * Returns true, when the only targetList is in parsetree. Cursors + * can require list of expressions or list of named expressions. + */ +static bool +is_strict_expr(List *parsetree, int *errpos, bool allowlist) +{ + RawStmt *rawstmt; + SelectStmt *select; + int targets = 0; + ListCell *lc; + + /* Top should be RawStmt */ + rawstmt = castNode(RawStmt, linitial(parsetree)); + + if (IsA(rawstmt->stmt, SelectStmt)) + { + select = (SelectStmt *) rawstmt->stmt; + } + else if (IsA(rawstmt->stmt, PLAssignStmt)) + { + select = castNode(SelectStmt, ((PLAssignStmt *) rawstmt->stmt)->val); + } + else + elog(ERROR, "unexpected node type"); + + if (!select->targetList) + { + *errpos = -1; + return false; + } + else + *errpos = exprLocation((Node *) select->targetList); + + if (select->distinctClause || + select->fromClause || + select->whereClause || + select->groupClause || + select->groupDistinct || + select->havingClause || + select->windowClause || + select->sortClause || + select->limitOffset || + select->limitCount || + select->limitOption || + select->lockingClause) + return false; + + foreach(lc, select->targetList) + { + ResTarget *rt = castNode(ResTarget, lfirst(lc)); + + if (targets++ >= 1 && !allowlist) + { + *errpos = exprLocation((Node *) rt); + return false; + } + + if (rt->name) + { + *errpos = exprLocation((Node *) rt); + return false; + } + } + + return true; +} + /* * Parse a SQL datatype name and produce a PLpgSQL_type structure. * @@ -4014,7 +4116,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, YYSTYPE *yylvalp, YYLTYPE *yyll item = read_sql_construct(',', ')', 0, ",\" or \")", RAW_PARSE_PLPGSQL_EXPR, - true, true, + true, false, true, NULL, &endtoken, yylvalp, yyllocp, yyscanner); diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index e9a729299470..b3ba3163e9a6 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -97,6 +97,8 @@ plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source) extrachecks |= PLPGSQL_XCHECK_TOOMANYROWS; else if (pg_strcasecmp(tok, "strict_multi_assignment") == 0) extrachecks |= PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT; + else if (pg_strcasecmp(tok, "strict_expr_check") == 0) + extrachecks |= PLPGSQL_XCHECK_STRICTEXPRCHECK; else if (pg_strcasecmp(tok, "all") == 0 || pg_strcasecmp(tok, "none") == 0) { GUC_check_errdetail("Key word \"%s\" cannot be combined with other key words.", tok); diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 41e52b8ce718..459f5f2e2232 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -1195,6 +1195,7 @@ extern bool plpgsql_check_asserts; #define PLPGSQL_XCHECK_SHADOWVAR (1 << 1) #define PLPGSQL_XCHECK_TOOMANYROWS (1 << 2) #define PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT (1 << 3) +#define PLPGSQL_XCHECK_STRICTEXPRCHECK (1 << 4) #define PLPGSQL_XCHECK_ALL ((int) ~0) extern int plpgsql_extra_warnings; diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index d8ce39dba3c1..8f4f5cb1183f 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -3084,6 +3084,20 @@ select shadowtest(1); t (1 row) +-- test of strict expression check +set plpgsql.extra_errors to 'strict_expr_check'; +create or replace function strict_expr_check_func() +returns void as $$ +declare var int; +begin + var = 1 + delete from pg_class where false; +end; +$$ language plpgsql; +ERROR: syntax of expression is not strict +LINE 5: var = 1 + ^ +reset plpgsql.extra_errors; -- runtime extra checks set plpgsql.extra_warnings to 'too_many_rows'; do $$ diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index d413d995d17e..dd0d908d4220 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -2618,6 +2618,20 @@ declare f1 int; begin return 1; end $$ language plpgsql; select shadowtest(1); +-- test of strict expression check +set plpgsql.extra_errors to 'strict_expr_check'; + +create or replace function strict_expr_check_func() +returns void as $$ +declare var int; +begin + var = 1 + delete from pg_class where false; +end; +$$ language plpgsql; + +reset plpgsql.extra_errors; + -- runtime extra checks set plpgsql.extra_warnings to 'too_many_rows'; From 09e054374eca5d57bb4de09434b825e594a3f106 Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Sun, 16 Jun 2024 08:13:53 +0200 Subject: [PATCH 2/3] simply check of strict-expr-check on regress test This patch enable strict-expr-check by default to be possible to see the impact of this option on regress test. Next commit will revert this option. The strict-expr-check should not be enabled by default. This commit is done just for testing. --- .../basic_archive/expected/basic_archive.out | 4 +-- contrib/basic_archive/sql/basic_archive.sql | 4 +-- src/pl/plpgsql/src/expected/plpgsql_array.out | 34 +++++++++++-------- src/pl/plpgsql/src/pl_handler.c | 4 +-- src/pl/plpgsql/src/sql/plpgsql_array.sql | 14 ++++---- .../recovery/t/026_overwrite_contrecord.pl | 4 +-- src/test/regress/expected/alter_table.out | 2 +- src/test/regress/expected/plancache.out | 2 +- src/test/regress/expected/plpgsql.out | 12 +++---- src/test/regress/expected/stats_ext.out | 2 +- src/test/regress/expected/transactions.out | 4 +-- src/test/regress/sql/alter_table.sql | 2 +- src/test/regress/sql/plancache.sql | 2 +- src/test/regress/sql/plpgsql.sql | 12 +++---- src/test/regress/sql/stats_ext.sql | 2 +- src/test/regress/sql/transactions.sql | 4 +-- 16 files changed, 56 insertions(+), 52 deletions(-) diff --git a/contrib/basic_archive/expected/basic_archive.out b/contrib/basic_archive/expected/basic_archive.out index 0015053e0f29..280ff3e022e1 100644 --- a/contrib/basic_archive/expected/basic_archive.out +++ b/contrib/basic_archive/expected/basic_archive.out @@ -11,8 +11,8 @@ DECLARE loops int := 0; BEGIN LOOP - archived := count(*) > 0 FROM pg_ls_dir('.', false, false) a - WHERE a ~ '^[0-9A-F]{24}$'; + archived := (SELECT count(*) > 0 FROM pg_ls_dir('.', false, false) a + WHERE a ~ '^[0-9A-F]{24}$'); IF archived OR loops > 120 * 10 THEN EXIT; END IF; PERFORM pg_sleep(0.1); loops := loops + 1; diff --git a/contrib/basic_archive/sql/basic_archive.sql b/contrib/basic_archive/sql/basic_archive.sql index 14e236d57ab5..2c127a821f17 100644 --- a/contrib/basic_archive/sql/basic_archive.sql +++ b/contrib/basic_archive/sql/basic_archive.sql @@ -7,8 +7,8 @@ DECLARE loops int := 0; BEGIN LOOP - archived := count(*) > 0 FROM pg_ls_dir('.', false, false) a - WHERE a ~ '^[0-9A-F]{24}$'; + archived := (SELECT count(*) > 0 FROM pg_ls_dir('.', false, false) a + WHERE a ~ '^[0-9A-F]{24}$'); IF archived OR loops > 120 * 10 THEN EXIT; END IF; PERFORM pg_sleep(0.1); loops := loops + 1; diff --git a/src/pl/plpgsql/src/expected/plpgsql_array.out b/src/pl/plpgsql/src/expected/plpgsql_array.out index 4c6b3ce998ab..caf07e834e59 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_array.out +++ b/src/pl/plpgsql/src/expected/plpgsql_array.out @@ -50,7 +50,7 @@ do $$ declare a quadarray; begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; NOTICE: a = ("{""(,11)""}",), a.c1[1].i = 11 do $$ declare a int[]; -begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; +begin a := (select array_agg(x) from (values(1),(2),(3)) v(x)); raise notice 'a = %', a; end$$; NOTICE: a = {1,2,3} do $$ declare a int[] := array[1,2,3]; begin @@ -64,30 +64,34 @@ end$$; NOTICE: a = {1,1,2,3,42,3,1,1,2,3,42,3} create temp table onecol as select array[1,2] as f1; do $$ declare a int[]; -begin a := f1 from onecol; raise notice 'a = %', a; end$$; +begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; NOTICE: a = {1,2} do $$ declare a int[]; -begin a := * from onecol for update; raise notice 'a = %', a; end$$; +begin a := (select * from onecol for update); raise notice 'a = %', a; end$$; NOTICE: a = {1,2} -- error cases: do $$ declare a int[]; -begin a := from onecol; raise notice 'a = %', a; end$$; -ERROR: assignment source returned 0 columns -CONTEXT: PL/pgSQL assignment "a := from onecol" -PL/pgSQL function inline_code_block line 2 at assignment +begin a := (select from onecol); raise notice 'a = %', a; end$$; +ERROR: subquery must return only one column +LINE 1: a := (select from onecol) + ^ +QUERY: a := (select from onecol) +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment do $$ declare a int[]; -begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; -ERROR: assignment source returned 2 columns -CONTEXT: PL/pgSQL assignment "a := f1, f1 from onecol" -PL/pgSQL function inline_code_block line 2 at assignment +begin a := (select f1, f1 from onecol); raise notice 'a = %', a; end$$; +ERROR: subquery must return only one column +LINE 1: a := (select f1, f1 from onecol) + ^ +QUERY: a := (select f1, f1 from onecol) +CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment insert into onecol values(array[11]); do $$ declare a int[]; -begin a := f1 from onecol; raise notice 'a = %', a; end$$; -ERROR: query returned more than one row -CONTEXT: query: a := f1 from onecol +begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; +ERROR: more than one row returned by a subquery used as an expression +CONTEXT: PL/pgSQL assignment "a := (select f1 from onecol)" PL/pgSQL function inline_code_block line 2 at assignment do $$ declare a int[]; -begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; +begin a := (select f1 from onecol limit 1); raise notice 'a = %', a; end$$; NOTICE: a = {1,2} do $$ declare a real; begin a[1] := 2; raise notice 'a = %', a; end$$; diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index b3ba3163e9a6..11e4dd1b62ce 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -53,7 +53,7 @@ bool plpgsql_check_asserts = true; static char *plpgsql_extra_warnings_string = NULL; static char *plpgsql_extra_errors_string = NULL; int plpgsql_extra_warnings; -int plpgsql_extra_errors; +int plpgsql_extra_errors = PLPGSQL_XCHECK_STRICTEXPRCHECK; /* Hook for plugins */ PLpgSQL_plugin **plpgsql_plugin_ptr = NULL; @@ -196,7 +196,7 @@ _PG_init(void) gettext_noop("List of programming constructs that should produce an error."), NULL, &plpgsql_extra_errors_string, - "none", + "strict_expr_check", PGC_USERSET, GUC_LIST_INPUT, plpgsql_extra_checks_check_hook, plpgsql_extra_errors_assign_hook, diff --git a/src/pl/plpgsql/src/sql/plpgsql_array.sql b/src/pl/plpgsql/src/sql/plpgsql_array.sql index da984a99414d..09a76a8416b3 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_array.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_array.sql @@ -46,7 +46,7 @@ do $$ declare a quadarray; begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; do $$ declare a int[]; -begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; +begin a := (select array_agg(x) from (values(1),(2),(3)) v(x)); raise notice 'a = %', a; end$$; do $$ declare a int[] := array[1,2,3]; begin @@ -61,26 +61,26 @@ end$$; create temp table onecol as select array[1,2] as f1; do $$ declare a int[]; -begin a := f1 from onecol; raise notice 'a = %', a; end$$; +begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := * from onecol for update; raise notice 'a = %', a; end$$; +begin a := (select * from onecol for update); raise notice 'a = %', a; end$$; -- error cases: do $$ declare a int[]; -begin a := from onecol; raise notice 'a = %', a; end$$; +begin a := (select from onecol); raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; +begin a := (select f1, f1 from onecol); raise notice 'a = %', a; end$$; insert into onecol values(array[11]); do $$ declare a int[]; -begin a := f1 from onecol; raise notice 'a = %', a; end$$; +begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; +begin a := (select f1 from onecol limit 1); raise notice 'a = %', a; end$$; do $$ declare a real; begin a[1] := 2; raise notice 'a = %', a; end$$; diff --git a/src/test/recovery/t/026_overwrite_contrecord.pl b/src/test/recovery/t/026_overwrite_contrecord.pl index f408d4f69b6e..7d004b040317 100644 --- a/src/test/recovery/t/026_overwrite_contrecord.pl +++ b/src/test/recovery/t/026_overwrite_contrecord.pl @@ -33,7 +33,7 @@ 'postgres', q{ DO $$ DECLARE - wal_segsize int := setting::int FROM pg_settings WHERE name = 'wal_segment_size'; + wal_segsize int := (SELECT setting::int FROM pg_settings WHERE name = 'wal_segment_size'); remain int; iters int := 0; BEGIN @@ -43,7 +43,7 @@ BEGIN from generate_series(1, 10) g; remain := wal_segsize - (pg_current_wal_insert_lsn() - '0/0') % wal_segsize; - IF remain < 2 * setting::int from pg_settings where name = 'block_size' THEN + IF (SELECT remain < 2 * setting::int from pg_settings where name = 'block_size') THEN RAISE log 'exiting after % iterations, % bytes to end of WAL segment', iters, remain; EXIT; END IF; diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 476266e3f4b0..e2e6dc7e8ef6 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2691,7 +2691,7 @@ LANGUAGE plpgsql AS $$ DECLARE v_relfilenode oid; BEGIN - v_relfilenode := relfilenode FROM pg_class WHERE oid = p_tablename; + v_relfilenode := (SELECT relfilenode FROM pg_class WHERE oid = p_tablename); EXECUTE p_ddl; diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out index 4e59188196c9..faae99515f7a 100644 --- a/src/test/regress/expected/plancache.out +++ b/src/test/regress/expected/plancache.out @@ -139,7 +139,7 @@ create temp view v1 as select 2+2 as f1; create function cache_test_2() returns int as $$ begin - return f1 from v1; + return (select f1 from v1); end$$ language plpgsql; select cache_test_2(); cache_test_2 diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 8f4f5cb1183f..5545858c968f 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -121,7 +121,7 @@ create trigger tg_room_ad after delete -- ************************************************************ create function tg_wslot_biu() returns trigger as $$ begin - if count(*) = 0 from Room where roomno = new.roomno then + if (select count(*) = 0 from Room where roomno = new.roomno) then raise exception 'Room % does not exist', new.roomno; end if; return new; @@ -286,7 +286,7 @@ begin raise exception ''no manual manipulation of HSlot''; end if; if tg_op = ''UPDATE'' and new.hubname != old.hubname then - if count(*) > 0 from Hub where name = old.hubname then + if (select count(*) > 0 from Hub where name = old.hubname) then raise exception ''no manual manipulation of HSlot''; end if; end if; @@ -942,12 +942,12 @@ begin return retval || pslot_backlink_view(psrec.slotlink); end if; if sltype = ''HS'' then - retval := comment from Hub H, HSlot HS + retval := (select comment from Hub H, HSlot HS where HS.slotname = psrec.slotlink - and H.name = HS.hubname; + and H.name = HS.hubname); retval := retval || '' slot ''; - retval := retval || slotno::text from HSlot - where slotname = psrec.slotlink; + retval := (select retval || slotno::text from HSlot + where slotname = psrec.slotlink); return retval; end if; return psrec.slotlink; diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 6359e5fb689c..4d41e791ed1f 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -350,7 +350,7 @@ CREATE STATISTICS tststats.s8 ON a, b FROM tststats.pt; CREATE STATISTICS tststats.s9 ON a, b FROM tststats.pt1; DO $$ DECLARE - relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; + relname text := (SELECT reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass); BEGIN EXECUTE 'CREATE STATISTICS tststats.s10 ON a, b FROM ' || relname; EXCEPTION WHEN wrong_object_type THEN diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out index 7f5757e89c42..3458dad1749c 100644 --- a/src/test/regress/expected/transactions.out +++ b/src/test/regress/expected/transactions.out @@ -543,7 +543,7 @@ select * from xacttest; rollback; -- Now the same test with plpgsql (since it depends on SPI which is different) create or replace function max_xacttest() returns smallint language plpgsql as -'begin return max(a) from xacttest; end' stable; +'begin return (select max(a) from xacttest); end' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; @@ -558,7 +558,7 @@ select * from xacttest; rollback; create or replace function max_xacttest() returns smallint language plpgsql as -'begin return max(a) from xacttest; end' volatile; +'begin return (select max(a) from xacttest); end' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 5ce9d1e429f8..9542043d1e81 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1678,7 +1678,7 @@ LANGUAGE plpgsql AS $$ DECLARE v_relfilenode oid; BEGIN - v_relfilenode := relfilenode FROM pg_class WHERE oid = p_tablename; + v_relfilenode := (SELECT relfilenode FROM pg_class WHERE oid = p_tablename); EXECUTE p_ddl; diff --git a/src/test/regress/sql/plancache.sql b/src/test/regress/sql/plancache.sql index 4b2f11dcc641..a3dbd93468e0 100644 --- a/src/test/regress/sql/plancache.sql +++ b/src/test/regress/sql/plancache.sql @@ -81,7 +81,7 @@ create temp view v1 as create function cache_test_2() returns int as $$ begin - return f1 from v1; + return (select f1 from v1); end$$ language plpgsql; select cache_test_2(); diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index dd0d908d4220..238e0ec67f2d 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -161,7 +161,7 @@ create trigger tg_room_ad after delete -- ************************************************************ create function tg_wslot_biu() returns trigger as $$ begin - if count(*) = 0 from Room where roomno = new.roomno then + if (select count(*) = 0 from Room where roomno = new.roomno) then raise exception 'Room % does not exist', new.roomno; end if; return new; @@ -348,7 +348,7 @@ begin raise exception ''no manual manipulation of HSlot''; end if; if tg_op = ''UPDATE'' and new.hubname != old.hubname then - if count(*) > 0 from Hub where name = old.hubname then + if (select count(*) > 0 from Hub where name = old.hubname) then raise exception ''no manual manipulation of HSlot''; end if; end if; @@ -1071,12 +1071,12 @@ begin return retval || pslot_backlink_view(psrec.slotlink); end if; if sltype = ''HS'' then - retval := comment from Hub H, HSlot HS + retval := (select comment from Hub H, HSlot HS where HS.slotname = psrec.slotlink - and H.name = HS.hubname; + and H.name = HS.hubname); retval := retval || '' slot ''; - retval := retval || slotno::text from HSlot - where slotname = psrec.slotlink; + retval := (select retval || slotno::text from HSlot + where slotname = psrec.slotlink); return retval; end if; return psrec.slotlink; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index da4f2fe9c938..6c6e2719b7dc 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -223,7 +223,7 @@ CREATE STATISTICS tststats.s8 ON a, b FROM tststats.pt; CREATE STATISTICS tststats.s9 ON a, b FROM tststats.pt1; DO $$ DECLARE - relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; + relname text := (SELECT reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass); BEGIN EXECUTE 'CREATE STATISTICS tststats.s10 ON a, b FROM ' || relname; EXCEPTION WHEN wrong_object_type THEN diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql index 51ae1b31b30b..1981955ac65c 100644 --- a/src/test/regress/sql/transactions.sql +++ b/src/test/regress/sql/transactions.sql @@ -320,7 +320,7 @@ rollback; -- Now the same test with plpgsql (since it depends on SPI which is different) create or replace function max_xacttest() returns smallint language plpgsql as -'begin return max(a) from xacttest; end' stable; +'begin return (select max(a) from xacttest); end' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; @@ -328,7 +328,7 @@ select * from xacttest; rollback; create or replace function max_xacttest() returns smallint language plpgsql as -'begin return max(a) from xacttest; end' volatile; +'begin return (select max(a) from xacttest); end' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0; From 354dba4bd66819f2dabbd1078cd1cc53a1b8275d Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Sun, 16 Jun 2024 15:52:38 +0200 Subject: [PATCH 3/3] set plpgsql.extra_errors to "none" Purpose of previous commit was to run tests with active strict_expr_check. Now, reset to default and revert all changes from previous commit. --- .../basic_archive/expected/basic_archive.out | 4 +-- contrib/basic_archive/sql/basic_archive.sql | 4 +-- src/pl/plpgsql/src/expected/plpgsql_array.out | 34 ++++++++----------- src/pl/plpgsql/src/pl_handler.c | 4 +-- src/pl/plpgsql/src/sql/plpgsql_array.sql | 14 ++++---- .../recovery/t/026_overwrite_contrecord.pl | 4 +-- src/test/regress/expected/alter_table.out | 2 +- src/test/regress/expected/plancache.out | 2 +- src/test/regress/expected/plpgsql.out | 12 +++---- src/test/regress/expected/stats_ext.out | 2 +- src/test/regress/expected/transactions.out | 4 +-- src/test/regress/sql/alter_table.sql | 2 +- src/test/regress/sql/plancache.sql | 2 +- src/test/regress/sql/plpgsql.sql | 12 +++---- src/test/regress/sql/stats_ext.sql | 2 +- src/test/regress/sql/transactions.sql | 4 +-- 16 files changed, 52 insertions(+), 56 deletions(-) diff --git a/contrib/basic_archive/expected/basic_archive.out b/contrib/basic_archive/expected/basic_archive.out index 280ff3e022e1..0015053e0f29 100644 --- a/contrib/basic_archive/expected/basic_archive.out +++ b/contrib/basic_archive/expected/basic_archive.out @@ -11,8 +11,8 @@ DECLARE loops int := 0; BEGIN LOOP - archived := (SELECT count(*) > 0 FROM pg_ls_dir('.', false, false) a - WHERE a ~ '^[0-9A-F]{24}$'); + archived := count(*) > 0 FROM pg_ls_dir('.', false, false) a + WHERE a ~ '^[0-9A-F]{24}$'; IF archived OR loops > 120 * 10 THEN EXIT; END IF; PERFORM pg_sleep(0.1); loops := loops + 1; diff --git a/contrib/basic_archive/sql/basic_archive.sql b/contrib/basic_archive/sql/basic_archive.sql index 2c127a821f17..14e236d57ab5 100644 --- a/contrib/basic_archive/sql/basic_archive.sql +++ b/contrib/basic_archive/sql/basic_archive.sql @@ -7,8 +7,8 @@ DECLARE loops int := 0; BEGIN LOOP - archived := (SELECT count(*) > 0 FROM pg_ls_dir('.', false, false) a - WHERE a ~ '^[0-9A-F]{24}$'); + archived := count(*) > 0 FROM pg_ls_dir('.', false, false) a + WHERE a ~ '^[0-9A-F]{24}$'; IF archived OR loops > 120 * 10 THEN EXIT; END IF; PERFORM pg_sleep(0.1); loops := loops + 1; diff --git a/src/pl/plpgsql/src/expected/plpgsql_array.out b/src/pl/plpgsql/src/expected/plpgsql_array.out index caf07e834e59..4c6b3ce998ab 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_array.out +++ b/src/pl/plpgsql/src/expected/plpgsql_array.out @@ -50,7 +50,7 @@ do $$ declare a quadarray; begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; NOTICE: a = ("{""(,11)""}",), a.c1[1].i = 11 do $$ declare a int[]; -begin a := (select array_agg(x) from (values(1),(2),(3)) v(x)); raise notice 'a = %', a; end$$; +begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; NOTICE: a = {1,2,3} do $$ declare a int[] := array[1,2,3]; begin @@ -64,34 +64,30 @@ end$$; NOTICE: a = {1,1,2,3,42,3,1,1,2,3,42,3} create temp table onecol as select array[1,2] as f1; do $$ declare a int[]; -begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; NOTICE: a = {1,2} do $$ declare a int[]; -begin a := (select * from onecol for update); raise notice 'a = %', a; end$$; +begin a := * from onecol for update; raise notice 'a = %', a; end$$; NOTICE: a = {1,2} -- error cases: do $$ declare a int[]; -begin a := (select from onecol); raise notice 'a = %', a; end$$; -ERROR: subquery must return only one column -LINE 1: a := (select from onecol) - ^ -QUERY: a := (select from onecol) -CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +begin a := from onecol; raise notice 'a = %', a; end$$; +ERROR: assignment source returned 0 columns +CONTEXT: PL/pgSQL assignment "a := from onecol" +PL/pgSQL function inline_code_block line 2 at assignment do $$ declare a int[]; -begin a := (select f1, f1 from onecol); raise notice 'a = %', a; end$$; -ERROR: subquery must return only one column -LINE 1: a := (select f1, f1 from onecol) - ^ -QUERY: a := (select f1, f1 from onecol) -CONTEXT: PL/pgSQL function inline_code_block line 2 at assignment +begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; +ERROR: assignment source returned 2 columns +CONTEXT: PL/pgSQL assignment "a := f1, f1 from onecol" +PL/pgSQL function inline_code_block line 2 at assignment insert into onecol values(array[11]); do $$ declare a int[]; -begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; -ERROR: more than one row returned by a subquery used as an expression -CONTEXT: PL/pgSQL assignment "a := (select f1 from onecol)" +begin a := f1 from onecol; raise notice 'a = %', a; end$$; +ERROR: query returned more than one row +CONTEXT: query: a := f1 from onecol PL/pgSQL function inline_code_block line 2 at assignment do $$ declare a int[]; -begin a := (select f1 from onecol limit 1); raise notice 'a = %', a; end$$; +begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; NOTICE: a = {1,2} do $$ declare a real; begin a[1] := 2; raise notice 'a = %', a; end$$; diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 11e4dd1b62ce..b3ba3163e9a6 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -53,7 +53,7 @@ bool plpgsql_check_asserts = true; static char *plpgsql_extra_warnings_string = NULL; static char *plpgsql_extra_errors_string = NULL; int plpgsql_extra_warnings; -int plpgsql_extra_errors = PLPGSQL_XCHECK_STRICTEXPRCHECK; +int plpgsql_extra_errors; /* Hook for plugins */ PLpgSQL_plugin **plpgsql_plugin_ptr = NULL; @@ -196,7 +196,7 @@ _PG_init(void) gettext_noop("List of programming constructs that should produce an error."), NULL, &plpgsql_extra_errors_string, - "strict_expr_check", + "none", PGC_USERSET, GUC_LIST_INPUT, plpgsql_extra_checks_check_hook, plpgsql_extra_errors_assign_hook, diff --git a/src/pl/plpgsql/src/sql/plpgsql_array.sql b/src/pl/plpgsql/src/sql/plpgsql_array.sql index 09a76a8416b3..da984a99414d 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_array.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_array.sql @@ -46,7 +46,7 @@ do $$ declare a quadarray; begin a.c1[1].i := 11; raise notice 'a = %, a.c1[1].i = %', a, a.c1[1].i; end$$; do $$ declare a int[]; -begin a := (select array_agg(x) from (values(1),(2),(3)) v(x)); raise notice 'a = %', a; end$$; +begin a := array_agg(x) from (values(1),(2),(3)) v(x); raise notice 'a = %', a; end$$; do $$ declare a int[] := array[1,2,3]; begin @@ -61,26 +61,26 @@ end$$; create temp table onecol as select array[1,2] as f1; do $$ declare a int[]; -begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := (select * from onecol for update); raise notice 'a = %', a; end$$; +begin a := * from onecol for update; raise notice 'a = %', a; end$$; -- error cases: do $$ declare a int[]; -begin a := (select from onecol); raise notice 'a = %', a; end$$; +begin a := from onecol; raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := (select f1, f1 from onecol); raise notice 'a = %', a; end$$; +begin a := f1, f1 from onecol; raise notice 'a = %', a; end$$; insert into onecol values(array[11]); do $$ declare a int[]; -begin a := (select f1 from onecol); raise notice 'a = %', a; end$$; +begin a := f1 from onecol; raise notice 'a = %', a; end$$; do $$ declare a int[]; -begin a := (select f1 from onecol limit 1); raise notice 'a = %', a; end$$; +begin a := f1 from onecol limit 1; raise notice 'a = %', a; end$$; do $$ declare a real; begin a[1] := 2; raise notice 'a = %', a; end$$; diff --git a/src/test/recovery/t/026_overwrite_contrecord.pl b/src/test/recovery/t/026_overwrite_contrecord.pl index 7d004b040317..f408d4f69b6e 100644 --- a/src/test/recovery/t/026_overwrite_contrecord.pl +++ b/src/test/recovery/t/026_overwrite_contrecord.pl @@ -33,7 +33,7 @@ 'postgres', q{ DO $$ DECLARE - wal_segsize int := (SELECT setting::int FROM pg_settings WHERE name = 'wal_segment_size'); + wal_segsize int := setting::int FROM pg_settings WHERE name = 'wal_segment_size'; remain int; iters int := 0; BEGIN @@ -43,7 +43,7 @@ BEGIN from generate_series(1, 10) g; remain := wal_segsize - (pg_current_wal_insert_lsn() - '0/0') % wal_segsize; - IF (SELECT remain < 2 * setting::int from pg_settings where name = 'block_size') THEN + IF remain < 2 * setting::int from pg_settings where name = 'block_size' THEN RAISE log 'exiting after % iterations, % bytes to end of WAL segment', iters, remain; EXIT; END IF; diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index e2e6dc7e8ef6..476266e3f4b0 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2691,7 +2691,7 @@ LANGUAGE plpgsql AS $$ DECLARE v_relfilenode oid; BEGIN - v_relfilenode := (SELECT relfilenode FROM pg_class WHERE oid = p_tablename); + v_relfilenode := relfilenode FROM pg_class WHERE oid = p_tablename; EXECUTE p_ddl; diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out index faae99515f7a..4e59188196c9 100644 --- a/src/test/regress/expected/plancache.out +++ b/src/test/regress/expected/plancache.out @@ -139,7 +139,7 @@ create temp view v1 as select 2+2 as f1; create function cache_test_2() returns int as $$ begin - return (select f1 from v1); + return f1 from v1; end$$ language plpgsql; select cache_test_2(); cache_test_2 diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 5545858c968f..8f4f5cb1183f 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -121,7 +121,7 @@ create trigger tg_room_ad after delete -- ************************************************************ create function tg_wslot_biu() returns trigger as $$ begin - if (select count(*) = 0 from Room where roomno = new.roomno) then + if count(*) = 0 from Room where roomno = new.roomno then raise exception 'Room % does not exist', new.roomno; end if; return new; @@ -286,7 +286,7 @@ begin raise exception ''no manual manipulation of HSlot''; end if; if tg_op = ''UPDATE'' and new.hubname != old.hubname then - if (select count(*) > 0 from Hub where name = old.hubname) then + if count(*) > 0 from Hub where name = old.hubname then raise exception ''no manual manipulation of HSlot''; end if; end if; @@ -942,12 +942,12 @@ begin return retval || pslot_backlink_view(psrec.slotlink); end if; if sltype = ''HS'' then - retval := (select comment from Hub H, HSlot HS + retval := comment from Hub H, HSlot HS where HS.slotname = psrec.slotlink - and H.name = HS.hubname); + and H.name = HS.hubname; retval := retval || '' slot ''; - retval := (select retval || slotno::text from HSlot - where slotname = psrec.slotlink); + retval := retval || slotno::text from HSlot + where slotname = psrec.slotlink; return retval; end if; return psrec.slotlink; diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 4d41e791ed1f..6359e5fb689c 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -350,7 +350,7 @@ CREATE STATISTICS tststats.s8 ON a, b FROM tststats.pt; CREATE STATISTICS tststats.s9 ON a, b FROM tststats.pt1; DO $$ DECLARE - relname text := (SELECT reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass); + relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; BEGIN EXECUTE 'CREATE STATISTICS tststats.s10 ON a, b FROM ' || relname; EXCEPTION WHEN wrong_object_type THEN diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out index 3458dad1749c..7f5757e89c42 100644 --- a/src/test/regress/expected/transactions.out +++ b/src/test/regress/expected/transactions.out @@ -543,7 +543,7 @@ select * from xacttest; rollback; -- Now the same test with plpgsql (since it depends on SPI which is different) create or replace function max_xacttest() returns smallint language plpgsql as -'begin return (select max(a) from xacttest); end' stable; +'begin return max(a) from xacttest; end' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; @@ -558,7 +558,7 @@ select * from xacttest; rollback; create or replace function max_xacttest() returns smallint language plpgsql as -'begin return (select max(a) from xacttest); end' volatile; +'begin return max(a) from xacttest; end' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0; select * from xacttest; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 9542043d1e81..5ce9d1e429f8 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1678,7 +1678,7 @@ LANGUAGE plpgsql AS $$ DECLARE v_relfilenode oid; BEGIN - v_relfilenode := (SELECT relfilenode FROM pg_class WHERE oid = p_tablename); + v_relfilenode := relfilenode FROM pg_class WHERE oid = p_tablename; EXECUTE p_ddl; diff --git a/src/test/regress/sql/plancache.sql b/src/test/regress/sql/plancache.sql index a3dbd93468e0..4b2f11dcc641 100644 --- a/src/test/regress/sql/plancache.sql +++ b/src/test/regress/sql/plancache.sql @@ -81,7 +81,7 @@ create temp view v1 as create function cache_test_2() returns int as $$ begin - return (select f1 from v1); + return f1 from v1; end$$ language plpgsql; select cache_test_2(); diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 238e0ec67f2d..dd0d908d4220 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -161,7 +161,7 @@ create trigger tg_room_ad after delete -- ************************************************************ create function tg_wslot_biu() returns trigger as $$ begin - if (select count(*) = 0 from Room where roomno = new.roomno) then + if count(*) = 0 from Room where roomno = new.roomno then raise exception 'Room % does not exist', new.roomno; end if; return new; @@ -348,7 +348,7 @@ begin raise exception ''no manual manipulation of HSlot''; end if; if tg_op = ''UPDATE'' and new.hubname != old.hubname then - if (select count(*) > 0 from Hub where name = old.hubname) then + if count(*) > 0 from Hub where name = old.hubname then raise exception ''no manual manipulation of HSlot''; end if; end if; @@ -1071,12 +1071,12 @@ begin return retval || pslot_backlink_view(psrec.slotlink); end if; if sltype = ''HS'' then - retval := (select comment from Hub H, HSlot HS + retval := comment from Hub H, HSlot HS where HS.slotname = psrec.slotlink - and H.name = HS.hubname); + and H.name = HS.hubname; retval := retval || '' slot ''; - retval := (select retval || slotno::text from HSlot - where slotname = psrec.slotlink); + retval := retval || slotno::text from HSlot + where slotname = psrec.slotlink; return retval; end if; return psrec.slotlink; diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 6c6e2719b7dc..da4f2fe9c938 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -223,7 +223,7 @@ CREATE STATISTICS tststats.s8 ON a, b FROM tststats.pt; CREATE STATISTICS tststats.s9 ON a, b FROM tststats.pt1; DO $$ DECLARE - relname text := (SELECT reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass); + relname text := reltoastrelid::regclass FROM pg_class WHERE oid = 'tststats.t'::regclass; BEGIN EXECUTE 'CREATE STATISTICS tststats.s10 ON a, b FROM ' || relname; EXCEPTION WHEN wrong_object_type THEN diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql index 1981955ac65c..51ae1b31b30b 100644 --- a/src/test/regress/sql/transactions.sql +++ b/src/test/regress/sql/transactions.sql @@ -320,7 +320,7 @@ rollback; -- Now the same test with plpgsql (since it depends on SPI which is different) create or replace function max_xacttest() returns smallint language plpgsql as -'begin return (select max(a) from xacttest); end' stable; +'begin return max(a) from xacttest; end' stable; begin; update xacttest set a = max_xacttest() + 10 where a > 0; @@ -328,7 +328,7 @@ select * from xacttest; rollback; create or replace function max_xacttest() returns smallint language plpgsql as -'begin return (select max(a) from xacttest); end' volatile; +'begin return max(a) from xacttest; end' volatile; begin; update xacttest set a = max_xacttest() + 10 where a > 0;