Thread
Commits
-
Fix plpgsql's handling of "return simple_record_variable".
- dfd850980304 17.9 landed
- ce4b7e3a1058 18.3 landed
- c66f4cff1a2e 16.13 landed
- 9863c90759ec 19 (unreleased) landed
- 2b93d382055b 14.22 landed
- 254b15cbf1e9 15.17 landed
-
plpgsql: variables of domain of composite types are not correctly initialized
Pavel Stehule <pavel.stehule@gmail.com> — 2026-02-11T20:14:14Z
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(); select fx2(); 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; and then it works. Breakpoint 1, getTypeOutputInfo (type=0, typOutput=0x7ffe419d27dc, typIsVarlena=0x7ffe419d27db) at lsyscache.c:3064 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 -
Re: plpgsql: variables of domain of composite types are not correctly initialized
Tom Lane <tgl@sss.pgh.pa.us> — 2026-02-11T21:10:26Z
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
-
Re: plpgsql: variables of domain of composite types are not correctly initialized
Pavel Stehule <pavel.stehule@gmail.com> — 2026-02-12T05:18:26Z
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