Thread

Commits

  1. Fix plpgsql's handling of "return simple_record_variable".

  1. 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
    
  2. 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
    
    
  3. 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