diff --git a/src/common/pl/plpgsql/src/pl_exec.cpp b/src/common/pl/plpgsql/src/pl_exec.cpp index 41ab2a0d4..1359a67eb 100644 --- a/src/common/pl/plpgsql/src/pl_exec.cpp +++ b/src/common/pl/plpgsql/src/pl_exec.cpp @@ -258,7 +258,7 @@ static PLpgSQL_rec* copyPLpgsqlRec(PLpgSQL_rec* src); static PLpgSQL_recfield* copyPLpgsqlRecfield(PLpgSQL_recfield* src); static List* invalid_depend_func_and_packgae(Oid pkgOid); static void ReportCompileConcurrentError(const char* objName, bool isPackage); - +static Datum CopyFcinfoArgValue(Oid typOid, Datum value); /* ---------- * plpgsql_check_line_validity Called by the debugger plugin for * validating a given linenumber @@ -1083,12 +1083,12 @@ Datum plpgsql_exec_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, boo while (argmodes[outArgCnt] == PROARGMODE_OUT) { outArgCnt++; } - var->value = fcinfo->arg[outArgCnt]; + var->value = CopyFcinfoArgValue(fcinfo->argTypes[outArgCnt], fcinfo->arg[outArgCnt]); var->isnull = fcinfo->argnull[outArgCnt]; var->freeval = false; outArgCnt++; } else { - var->value = fcinfo->arg[i]; + var->value = CopyFcinfoArgValue(fcinfo->argTypes[i], fcinfo->arg[i]); var->isnull = fcinfo->argnull[i]; var->freeval = false; } @@ -1469,6 +1469,25 @@ Datum plpgsql_exec_function(PLpgSQL_function* func, FunctionCallInfo fcinfo, boo return estate.retval; } +static Datum CopyFcinfoArgValue(Oid typOid, Datum value) +{ +#ifdef ENABLE_MULTIPLE_NODES + return value; +#endif + if (!OidIsValid(typOid)) { + return value; + } + /* + * For centralized database, package value may be in param. + * In this case, the value should be copyed, becaues the ref + * value may be influenced by procedure. + */ + bool typByVal = false; + int16 typLen; + get_typlenbyval(typOid, &typLen, &typByVal); + return datumCopy(value, typByVal, typLen); +} + static void RecordSetGeneratedField(PLpgSQL_rec *recNew) { int natts = recNew->tupdesc->natts; diff --git a/src/gausskernel/runtime/executor/nodeAgg.cpp b/src/gausskernel/runtime/executor/nodeAgg.cpp index 4e7d88075..d23e39f7f 100644 --- a/src/gausskernel/runtime/executor/nodeAgg.cpp +++ b/src/gausskernel/runtime/executor/nodeAgg.cpp @@ -474,6 +474,7 @@ static void advance_transition_function( *fcinfo, &(peraggstate->transfn), numTransInputs + 1, peraggstate->aggCollation, (Node*)aggstate, NULL); fcinfo->arg[0] = pergroupstate->transValue; fcinfo->argnull[0] = pergroupstate->transValueIsNull; + fcinfo->argTypes[0] = InvalidOid; fcinfo->isnull = false; /* just in case transfn doesn't set it */ Node *origin_fcxt = fcinfo->context; @@ -577,6 +578,7 @@ static void advance_collection_function( InitFunctionCallInfoData(*fcinfo, &(peraggstate->collectfn), 2, peraggstate->aggCollation, (Node*)aggstate, NULL); fcinfo->arg[0] = pergroupstate->collectValue; fcinfo->argnull[0] = pergroupstate->collectValueIsNull; + fcinfo->argTypes[0] = InvalidOid; newVal = FunctionCallInvoke(fcinfo); /* @@ -665,6 +667,7 @@ static void advance_aggregates(AggState* aggstate, AggStatePerGroup pergroup) for (i = 0; i < numTransInputs; i++) { fcinfo.arg[i + 1] = slot->tts_values[i]; fcinfo.argnull[i + 1] = slot->tts_isnull[i]; + fcinfo.argTypes[i + 1] = InvalidOid; } for (setno = 0; setno < numGroupingSets; setno++) { AggStatePerGroup pergroupstate = &pergroup[aggno + (setno * numAggs)]; @@ -896,6 +899,7 @@ static void finalize_aggregate(AggState* aggstate, AggStatePerAgg peraggstate, A foreach (lc, peraggstate->aggrefstate->aggdirectargs) { fcinfo.arg[args_pos] = ExecEvalExpr((ExprState*)lfirst(lc), aggstate->ss.ps.ps_ExprContext, &fcinfo.argnull[args_pos], NULL); + fcinfo.argTypes[args_pos] = ((ExprState*)lfirst(lc))->resultType; if (anynull == true || fcinfo.argnull[args_pos] == true) anynull = true; else @@ -928,6 +932,7 @@ static void finalize_aggregate(AggState* aggstate, AggStatePerAgg peraggstate, A fcinfo, &(peraggstate->finalfn), numFinalArgs, peraggstate->aggCollation, (Node*)aggstate, NULL); fcinfo.arg[0] = pergroupstate->transValue; fcinfo.argnull[0] = pergroupstate->transValueIsNull; + fcinfo.argTypes[0] = InvalidOid; if (anynull == true || pergroupstate->transValueIsNull == true) anynull = true; else @@ -936,6 +941,7 @@ static void finalize_aggregate(AggState* aggstate, AggStatePerAgg peraggstate, A while (args_pos < numFinalArgs) { fcinfo.arg[args_pos] = (Datum)0; fcinfo.argnull[args_pos] = true; + fcinfo.argTypes[args_pos] = InvalidOid; args_pos++; anynull = true; } diff --git a/src/gausskernel/runtime/executor/nodeWindowAgg.cpp b/src/gausskernel/runtime/executor/nodeWindowAgg.cpp index 8fb83c323..d40c7879c 100644 --- a/src/gausskernel/runtime/executor/nodeWindowAgg.cpp +++ b/src/gausskernel/runtime/executor/nodeWindowAgg.cpp @@ -126,6 +126,7 @@ static void advance_windowaggregate( ExprState* arg_state = (ExprState*)lfirst(arg); fcinfo->arg[i] = ExecEvalExpr(arg_state, econtext, &fcinfo->argnull[i], NULL); + fcinfo->argTypes[i] = arg_state->resultType; i++; } @@ -176,6 +177,7 @@ static void advance_windowaggregate( *fcinfo, &(peraggstate->transfn), num_arguments + 1, perfuncstate->winCollation, (Node*)winstate, NULL); fcinfo->arg[0] = peraggstate->transValue; fcinfo->argnull[0] = peraggstate->transValueIsNull; + fcinfo->argTypes[0] = InvalidOid; new_val = FunctionCallInvoke(fcinfo); /* * If pass-by-ref datatype, must copy the new value into aggcontext and @@ -216,6 +218,7 @@ static void finalize_windowaggregate(WindowAggState* winstate, WindowStatePerFun InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), 1, perfuncstate->winCollation, (Node*)winstate, NULL); fcinfo.arg[0] = peraggstate->transValue; fcinfo.argnull[0] = peraggstate->transValueIsNull; + fcinfo.argTypes[0] = InvalidOid; if (fcinfo.flinfo->fn_strict && peraggstate->transValueIsNull) { /* don't call a strict function with NULL inputs */ *result = (Datum)0; diff --git a/src/test/regress/expected/hw_package_variable.out b/src/test/regress/expected/hw_package_variable.out index 2120467d6..6c4e85a3d 100644 --- a/src/test/regress/expected/hw_package_variable.out +++ b/src/test/regress/expected/hw_package_variable.out @@ -2873,6 +2873,68 @@ drop procedure pp1; drop package pck1; NOTICE: drop cascades to function pkg_val_2.p1() drop table t1; +-- test package variable as in param +create type o1 as (a int, b varchar2); +create or replace package pck1 as +va varchar2; +vb varchar2 := 'vb'; +vc o1; +procedure p1; +end pck1; +/ +create or replace package body pck1 as +procedure p1 as +begin +va := 'hahahah'; +vc := (1,'cccc'); +end; +end pck1; +/ +create table testlog(a int); +create or replace procedure insertlog() is +PRAGMA AUTONOMOUS_TRANSACTION; +begin +insert into testlog values(1); +pck1.va := 'bbbbbbb'; +pck1.vc := (123,'ayayayayay'); +exception +when others then +raise notice 'sqlerrm:%',sqlerrm; +raise; +end; +/ +create or replace procedure p1(va in varchar2, vb in varchar2, vc in o1) is +begin +raise info 'before auto: %,%', vb,vc; +insertlog(); +raise info 'after auto: %,%', vb,vc; +exception +when others then +raise notice 'sqlerrm:%',sqlerrm; +raise; +end; +/ +declare +begin +pck1.p1(); +p1(150,pck1.va,pck1.vc); +raise info 'after p1: %,%', pck1.va,pck1.vc; +end; +/ +INFO: before auto: hahahah,(1,cccc) +CONTEXT: SQL statement "CALL p1(150,pck1.va,pck1.vc)" +PL/pgSQL function inline_code_block line 4 at PERFORM +INFO: after auto: hahahah,(1,cccc) +CONTEXT: SQL statement "CALL p1(150,pck1.va,pck1.vc)" +PL/pgSQL function inline_code_block line 4 at PERFORM +INFO: after p1: bbbbbbb,(123,ayayayayay) + +drop procedure p1; +drop procedure insertlog; +drop package pck1; +NOTICE: drop cascades to function pkg_val_2.p1() +drop table testlog; +drop type o1; -- clean DROP SCHEMA IF EXISTS pkg_val_1 CASCADE; DROP SCHEMA IF EXISTS pkg_val_2 CASCADE; diff --git a/src/test/regress/sql/hw_package_variable.sql b/src/test/regress/sql/hw_package_variable.sql index 09d7980e5..08c0f5969 100644 --- a/src/test/regress/sql/hw_package_variable.sql +++ b/src/test/regress/sql/hw_package_variable.sql @@ -2238,6 +2238,61 @@ drop procedure pp1; drop package pck1; drop table t1; +-- test package variable as in param +create type o1 as (a int, b varchar2); +create or replace package pck1 as +va varchar2; +vb varchar2 := 'vb'; +vc o1; +procedure p1; +end pck1; +/ +create or replace package body pck1 as +procedure p1 as +begin +va := 'hahahah'; +vc := (1,'cccc'); +end; +end pck1; +/ +create table testlog(a int); +create or replace procedure insertlog() is +PRAGMA AUTONOMOUS_TRANSACTION; +begin +insert into testlog values(1); +pck1.va := 'bbbbbbb'; +pck1.vc := (123,'ayayayayay'); +exception +when others then +raise notice 'sqlerrm:%',sqlerrm; +raise; +end; +/ +create or replace procedure p1(va in varchar2, vb in varchar2, vc in o1) is +begin +raise info 'before auto: %,%', vb,vc; +insertlog(); +raise info 'after auto: %,%', vb,vc; +exception +when others then +raise notice 'sqlerrm:%',sqlerrm; +raise; +end; +/ +declare +begin +pck1.p1(); +p1(150,pck1.va,pck1.vc); +raise info 'after p1: %,%', pck1.va,pck1.vc; +end; +/ + +drop procedure p1; +drop procedure insertlog; +drop package pck1; +drop table testlog; +drop type o1; + -- clean DROP SCHEMA IF EXISTS pkg_val_1 CASCADE; DROP SCHEMA IF EXISTS pkg_val_2 CASCADE;