!4114 修复ExecResult错误释放内存上下文的bug
Merge pull request !4114 from Cross-罗/fix_memory
This commit is contained in:
@ -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,
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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
|
||||
|
||||
@ -964,6 +964,8 @@ typedef struct FuncExprState {
|
||||
*/
|
||||
bool setArgsValid;
|
||||
|
||||
bool setArgByVal; /* all args are by val? */
|
||||
|
||||
bool setHasSetArg;
|
||||
|
||||
bool is_plpgsql_func_with_outparam;
|
||||
|
||||
24
src/test/regress/expected/exec_result_test.out
Normal file
24
src/test/regress/expected/exec_result_test.out
Normal file
@ -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)
|
||||
|
||||
@ -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.
|
||||
|
||||
19
src/test/regress/sql/exec_result_test.sql
Normal file
19
src/test/regress/sql/exec_result_test.sql
Normal file
@ -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);
|
||||
Reference in New Issue
Block a user