diff --git a/src/common/pl/plpgsql/src/gram.y b/src/common/pl/plpgsql/src/gram.y index 64d200c1f..7e6f69ed6 100755 --- a/src/common/pl/plpgsql/src/gram.y +++ b/src/common/pl/plpgsql/src/gram.y @@ -11290,8 +11290,8 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict, int firstto errmsg("Improper use of '.*'. The '.*' operator cannot be used with a row type variable."), parser_errposition(yylloc))); } - if (tok == T_DATUM || tok == T_VARRAY_VAR - || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE) { + if (!DB_IS_CMPT(PG_FORMAT) && (tok == T_DATUM || tok == T_VARRAY_VAR + || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE)) { const char* message = "syntax error, expected \",\""; InsertErrorMessage(message, plpgsql_yylloc); ereport(errstate, @@ -11314,8 +11314,8 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict, int firstto errmsg("record or row variable cannot be part of multiple-item INTO list"), parser_errposition(yylloc))); } - if (tok == T_DATUM || tok == T_VARRAY_VAR - || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE) { + if (!DB_IS_CMPT(PG_FORMAT) && (tok == T_DATUM || tok == T_VARRAY_VAR + || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE)) { const char* message = "syntax error, expected \",\""; InsertErrorMessage(message, plpgsql_yylloc); ereport(errstate, @@ -11742,8 +11742,8 @@ read_into_array_table_scalar_list(char *initial_name, } } - if (tok == T_DATUM || tok == T_VARRAY_VAR - || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE) { + if (!DB_IS_CMPT(PG_FORMAT) && (tok == T_DATUM || tok == T_VARRAY_VAR + || tok == T_TABLE_VAR || tok == T_PACKAGE_VARIABLE)) { const char* message = "syntax error, expected \",\""; InsertErrorMessage(message, plpgsql_yylloc); ereport(errstate, diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp index 4965f4a03..a5e822161 100644 --- a/src/gausskernel/runtime/executor/execQual.cpp +++ b/src/gausskernel/runtime/executor/execQual.cpp @@ -1905,6 +1905,7 @@ static void init_fcache( fcache->funcResultSlot = NULL; fcache->setArgsValid = false; fcache->shutdown_reg = false; + fcache->setArgByVal = false; if(fcache->xprstate.is_flt_frame){ fcache->is_plpgsql_func_with_outparam = is_function_with_plpgsql_language_and_outparam(fcache->func.fn_oid); fcache->has_refcursor = func_has_refcursor_args(fcache->func.fn_oid, &fcache->fcinfo_data); @@ -1936,6 +1937,7 @@ extern void ShutdownFuncExpr(Datum arg) /* Clear any active set-argument state */ fcache->setArgsValid = false; + fcache->setArgByVal = false; /* execUtils will deregister the callback... */ fcache->shutdown_reg = false; @@ -2188,6 +2190,16 @@ void set_result_for_plpgsql_language_function_with_outparam(FuncExprState *fcach pfree(nulls); } +bool ExecSetArgIsByValue(FunctionCallInfo fcinfo) +{ + for (int i = 0; i < fcinfo->nargs; i++) { + if (!fcinfo->argnull[i] && !get_typbyval(fcinfo->argTypes[i])) { + return false; + } + } + return true; +} + /* * ExecMakeFunctionResult * @@ -2338,6 +2350,7 @@ restart: } else { hasSetArg = (argDone != ExprSingleResult); } + fcache->setArgByVal = ExecSetArgIsByValue(fcinfo); } else { /* Re-use callinfo from previous evaluation */ hasSetArg = fcache->setHasSetArg; @@ -2497,6 +2510,10 @@ restart: if (fcache->func.fn_retset && *isDone == ExprMultipleResult) { fcache->setHasSetArg = hasSetArg; fcache->setArgsValid = true; + /* arg not by value, memory can not be reset */ + if (!fcache->setArgByVal) { + econtext->hasSetResultStore = true; + } /* Register cleanup callback if we didn't already */ if (!fcache->shutdown_reg) { RegisterExprContextCallback(econtext, ShutdownFuncExpr, PointerGetDatum(fcache)); diff --git a/src/gausskernel/runtime/executor/nodeResult.cpp b/src/gausskernel/runtime/executor/nodeResult.cpp index 830b42d79..8ee6da135 100644 --- a/src/gausskernel/runtime/executor/nodeResult.cpp +++ b/src/gausskernel/runtime/executor/nodeResult.cpp @@ -91,13 +91,6 @@ static TupleTableSlot* ExecResult(PlanState* state) } } - /* - * Reset per-tuple memory context to free any expression evaluation - * storage allocated in the previous tuple cycle. Note this can't happen - * until we're done projecting out tuples from a scan tuple. - */ - ResetExprContext(econtext); - /* * Reset per-tuple memory context to free any expression evaluation * storage allocated in the previous tuple cycle. Note this can't happen @@ -124,7 +117,8 @@ static TupleTableSlot* ExecResult(PlanState* state) if (econtext->hasSetResultStore) { /* return values all store in ResultStore, could not free early one */ - + ResetExprContext(econtext); + econtext->hasSetResultStore = false; } /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 14ee0ad6a..49358b835 100755 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -246,6 +246,7 @@ extern void EvalPlanQualFetchRowMarksUHeap(EPQState* epqstate); extern TupleTableSlot* EvalPlanQualNext(EPQState* epqstate); extern void EvalPlanQualBegin(EPQState* epqstate, EState* parentestate, bool isUHeap = false); extern void EvalPlanQualEnd(EPQState* epqstate); +extern bool ExecSetArgIsByValue(FunctionCallInfoData* fcinfo); /* * functions in execProcnode.c diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index fbc391a2f..d4fa660ae 100755 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -964,6 +964,8 @@ typedef struct FuncExprState { */ bool setArgsValid; + bool setArgByVal; /* all args are by val? */ + bool setHasSetArg; bool is_plpgsql_func_with_outparam; diff --git a/src/test/regress/expected/exec_result_test.out b/src/test/regress/expected/exec_result_test.out new file mode 100644 index 000000000..35231f187 --- /dev/null +++ b/src/test/regress/expected/exec_result_test.out @@ -0,0 +1,24 @@ +drop schema if exists orafce cascade; +NOTICE: schema "orafce" does not exist, skipping +create schema orafce; +CREATE OR REPLACE FUNCTION orafce.regexp_substr(text, text, integer, integer, text, int) +RETURNS text +AS $$ +DECLARE + v_substr text; + v_pattern text := $2; + modifiers text := $5; + v_subexpr integer := $6; + has_group integer := 2; +BEGIN + v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[v_subexpr] OFFSET $4 - 1 LIMIT 1); + RETURN v_substr; +END; +$$ +LANGUAGE plpgsql; +SELECT orafce.REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3); + regexp_substr +--------------- + +(1 row) + diff --git a/src/test/regress/parallel_schedule0A b/src/test/regress/parallel_schedule0A index 1be0c5363..d5b012998 100644 --- a/src/test/regress/parallel_schedule0A +++ b/src/test/regress/parallel_schedule0A @@ -29,7 +29,7 @@ test: replace_func_with_two_args trunc_func_for_date nlssort_pinyin updatable_vi # test multiple statistics test: functional_dependency -test: pg_proc_test test_row_type_in_proc +test: pg_proc_test test_row_type_in_proc exec_result_test # test fdw # NOTICE: In the "fdw_prepare", we copy the fdw test to be used from contrib into regress sql set. diff --git a/src/test/regress/sql/exec_result_test.sql b/src/test/regress/sql/exec_result_test.sql new file mode 100644 index 000000000..ee522bc37 --- /dev/null +++ b/src/test/regress/sql/exec_result_test.sql @@ -0,0 +1,19 @@ +drop schema if exists orafce cascade; +create schema orafce; +CREATE OR REPLACE FUNCTION orafce.regexp_substr(text, text, integer, integer, text, int) +RETURNS text +AS $$ +DECLARE + v_substr text; + v_pattern text := $2; + modifiers text := $5; + v_subexpr integer := $6; + has_group integer := 2; +BEGIN + v_substr := (SELECT (regexp_matches(substr($1, $3), v_pattern, modifiers))[v_subexpr] OFFSET $4 - 1 LIMIT 1); + RETURN v_substr; +END; +$$ +LANGUAGE plpgsql; + +SELECT orafce.REGEXP_SUBSTR('1234567890 1234557890', '(123)(4(5[56])(78))', 1, 2, 'i', 3);