Обсуждение: plpgsql: variables of domain of composite types are not correctly initialized
plpgsql: variables of domain of composite types are not correctly initialized
От
Pavel Stehule
Дата:
Hi
I got a bug report for plpgsql_check related to domains of composite types.
While I played with code, maybe I found a bug:
create type t2 as (a int, b numeric);
create or replace function fx1()
returns t2 as $$
declare v t2;
begin
return v;
end
$$ language plpgsql;
select fx1(); -- ok
create domain t2d as t2;
create or replace function fx2()
returns t2d as $$
declare v t2d;
begin
return v;
end
$$ language plpgsql;
select fx2();
create or replace function fx1()
returns t2 as $$
declare v t2;
begin
return v;
end
$$ language plpgsql;
select fx1(); -- ok
create domain t2d as t2;
create or replace function fx2()
returns t2d as $$
declare v t2d;
begin
return v;
end
$$ language plpgsql;
select fx2();
select fx2();
ERROR: cache lookup failed for type 0
CONTEXT: PL/pgSQL function fx2() while casting return value to function's return type
ERROR: cache lookup failed for type 0
CONTEXT: PL/pgSQL function fx2() while casting return value to function's return type
I found a workaround - the variable must be initialized as NULL composite value.
create or replace function fx2()
returns t2d as $$
declare v t2d;
begin v := (null, null);
return v;
end
$$ language plpgsql;
returns t2d as $$
declare v t2d;
begin v := (null, null);
return v;
end
$$ language plpgsql;
and then it works.
3064 elog(ERROR, "cache lookup failed for type %u", type);
(gdb) bt
#0 getTypeOutputInfo (type=0, typOutput=0x7ffe419d27dc, typIsVarlena=0x7ffe419d27db) at lsyscache.c:3064
#1 0x00000000008ad217 in eval_const_expressions_mutator (node=0x1c473170, context=0x7ffe419d2f40) at clauses.c:3088
#2 0x00000000008ae9da in eval_const_expressions_mutator (node=0x1c4731a0, context=0x7ffe419d2f40) at clauses.c:3803
#3 0x00000000008aba3a in eval_const_expressions (root=0x7ffe419d2fa0, node=0x1c4731a0) at clauses.c:2279
#4 0x0000000000887d7e in expression_planner_with_deps (expr=0x1c4731a0, relationOids=0x7ffe419d33f0, invalItems=0x7ffe419d33e8)
at planner.c:6869
#5 0x0000000000bbdbbc in GetCachedExpression (expr=0x1c4731a0) at plancache.c:1827
#6 0x00007ff91f3953d1 in get_cast_hashentry (estate=0x7ffe419d35d0, srctype=0, srctypmod=-1, dsttype=16393, dsttypmod=-1)
at pl_exec.c:8085
#7 0x00007ff91f3950e2 in do_cast_value (estate=0x7ffe419d35d0, value=0, isnull=0x1c467924, valtype=0, valtypmod=-1, reqtype=16393,
reqtypmod=-1) at pl_exec.c:7918
#8 0x00007ff91f39509a in exec_cast_value (estate=0x7ffe419d35d0, value=0, isnull=0x1c467924, valtype=0, valtypmod=-1, reqtype=16393,
reqtypmod=-1) at pl_exec.c:7899
#9 0x00007ff91f387915 in plpgsql_exec_function (func=0x1c3a51f0, fcinfo=0x1c467908, simple_eval_estate=0x0, simple_eval_resowner=0x0,
procedure_resowner=0x0, atomic=true) at pl_exec.c:782
#10 0x00007ff91f3a6b88 in plpgsql_call_handler (fcinfo=0x1c467908) at pl_handler.c:278
#11 0x00000000006f5abd in ExecInterpExpr (state=0x1c4677b0, econtext=0x1c467458, isnull=0x0) at execExprInterp.c:926
#12 0x00000000006f810a in ExecInterpExprStillValid (state=0x1c4677b0, econtext=0x1c467458, isNull=0x0) at execExprInterp.c:2299
#13 0x0000000000757adf in ExecEvalExprNoReturn (state=0x1c4677b0, econtext=0x1c467458) at ../../../src/include/executor/executor.h:423
#14 0x0000000000757b93 in ExecEvalExprNoReturnSwitchContext (state=0x1c4677b0, econtext=0x1c467458)
at ../../../src/include/executor/executor.h:464
#15 0x0000000000757bf4 in ExecProject (projInfo=0x1c4677a8) at ../../../src/include/executor/executor.h:496
#16 0x0000000000757ddc in ExecResult (pstate=0x1c467348) at nodeResult.c:135
#17 0x00000000007116c8 in ExecProcNodeFirst (node=0x1c467348) at execProcnode.c:469
#18 0x00000000007039d9 in ExecProcNode (node=0x1c467348) at ../../../src/include/executor/executor.h:319
#19 0x000000000070674d in ExecutePlan (queryDesc=0x1c38fe10, operation=CMD_SELECT, sendTuples=true, numberTuples=0,
direction=ForwardScanDirection, dest=0x1c392058) at execMain.c:1711
#20 0x0000000000703ff6 in standard_ExecutorRun (queryDesc=0x1c38fe10, direction=ForwardScanDirection, count=0) at execMain.c:366
#21 0x0000000000703e80 in ExecutorRun (queryDesc=0x1c38fe10, direction=ForwardScanDirection, count=0) at execMain.c:303
#22 0x00000000009ee61c in PortalRunSelect (portal=0x1c3e6240, forward=true, count=0, dest=0x1c392058) at pquery.c:916
#23 0x00000000009ee2d4 in PortalRun (portal=0x1c3e6240, count=9223372036854775807, isTopLevel=true, dest=0x1c392058,
altdest=0x1c392058, qc=0x7ffe419d3f50) at pquery.c:760
#24 0x00000000009e7391 in exec_simple_query (query_string=0x1c3640a0 "select fx2();") at postgres.c:1277
Regards
Pavel
Pavel Stehule <pavel.stehule@gmail.com> writes:
> I got a bug report for plpgsql_check related to domains of composite types.
> While I played with code, maybe I found a bug:
Indeed. Looks like exec_stmt_return's special case for a simple
variable reference forgets to fill estate->rettype when the variable
is a null record. This is an old bug, but I think we'd managed not
to notice because that value isn't consulted unless we have to cast
to a domain.
The behavior we want is what exec_eval_datum does, and after looking
at it for a minute I wondered why we don't just use exec_eval_datum
instead of duplicating logic. The ROW case already does that, so
we can fix the bug with strictly less code.
regards, tom lane
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index f80264e184e..723048ab833 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3255,28 +3255,14 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
}
break;
- case PLPGSQL_DTYPE_REC:
- {
- PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
-
- /* If record is empty, we return NULL not a row of nulls */
- if (rec->erh && !ExpandedRecordIsEmpty(rec->erh))
- {
- estate->retval = ExpandedRecordGetDatum(rec->erh);
- estate->retisnull = false;
- estate->rettype = rec->rectypeid;
- }
- }
- break;
-
case PLPGSQL_DTYPE_ROW:
+ case PLPGSQL_DTYPE_REC:
{
- PLpgSQL_row *row = (PLpgSQL_row *) retvar;
+ /* exec_eval_datum can handle these cases */
int32 rettypmod;
- /* We get here if there are multiple OUT parameters */
exec_eval_datum(estate,
- (PLpgSQL_datum *) row,
+ retvar,
&estate->rettype,
&rettypmod,
&estate->retval,
Re: plpgsql: variables of domain of composite types are not correctly initialized
От
Pavel Stehule
Дата:
st 11. 2. 2026 v 22:10 odesílatel Tom Lane <tgl@sss.pgh.pa.us> napsal:
Pavel Stehule <pavel.stehule@gmail.com> writes:
> I got a bug report for plpgsql_check related to domains of composite types.
> While I played with code, maybe I found a bug:
Indeed. Looks like exec_stmt_return's special case for a simple
variable reference forgets to fill estate->rettype when the variable
is a null record. This is an old bug, but I think we'd managed not
to notice because that value isn't consulted unless we have to cast
to a domain.
The behavior we want is what exec_eval_datum does, and after looking
at it for a minute I wondered why we don't just use exec_eval_datum
instead of duplicating logic. The ROW case already does that, so
we can fix the bug with strictly less code.
regards, tom lane
Nice, Thank you
Pavel