postgres.git / summary / log / commit / refs

commit    254b15cbf1e91ca33620027ca016e67668a321c1
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Wed Feb 11 21:53:14 2026 +0000
First released in: 14.22, 15.17, 16.13, 17.9, 18.3

    Fix plpgsql's handling of "return simple_record_variable".
    
    If the variable's value is null, exec_stmt_return() missed filling
    in estate->rettype.  This is a pretty old bug, but we'd managed not
    to notice because that value isn't consulted for a null result ...
    unless we have to cast it to a domain.  That case led to a failure
    with "cache lookup failed for type 0".
    
    The correct way to assign the data type is known by exec_eval_datum.
    While we could copy-and-paste that logic, it seems like a better
    idea to just invoke exec_eval_datum, as the ROW case already does.
    
    Reported-by: Pavel Stehule <pavel.stehule@gmail.com>
    Author: Tom Lane <tgl@sss.pgh.pa.us>
    Discussion: https://postgr.es/m/CAFj8pRBT_ahexDf-zT-cyH8bMR_qcySKM8D5nv5MvTWPiatYGA@mail.gmail.com
    Backpatch-through: 14


src/pl/plpgsql/src/expected/plpgsql_domain.out | 13 +++++++++++++ src/pl/plpgsql/src/pl_exec.c | 20 +++----------------- src/pl/plpgsql/src/sql/plpgsql_domain.sql | 10 ++++++++++ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/pl/plpgsql/src/expected/plpgsql_domain.out b/src/pl/plpgsql/src/expected/plpgsql_domain.out index 516c2b9e08e..11c012ea024 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_domain.out +++ b/src/pl/plpgsql/src/expected/plpgsql_domain.out @@ -395,3 +395,16 @@ SELECT * FROM test_assign_ordered_named_pairs(1,2,0); -- should fail someday {"(1,2)"} (1 row) +CREATE FUNCTION test_null_ordered_named_pair() + RETURNS ordered_named_pair AS $$ +declare v ordered_named_pair; +begin +return v; +end +$$ LANGUAGE plpgsql; +SELECT * FROM test_null_ordered_named_pair(); + i | j +---+--- + | +(1 row) + diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index cff9c74e668..2f841d5af21 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3238,28 +3238,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, diff --git a/src/pl/plpgsql/src/sql/plpgsql_domain.sql b/src/pl/plpgsql/src/sql/plpgsql_domain.sql index 8f99aae5a9f..4c5dd7dc707 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_domain.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_domain.sql @@ -277,3 +277,13 @@ $$ LANGUAGE plpgsql; SELECT * FROM test_assign_ordered_named_pairs(1,2,3); SELECT * FROM test_assign_ordered_named_pairs(2,1,3); SELECT * FROM test_assign_ordered_named_pairs(1,2,0); -- should fail someday + +CREATE FUNCTION test_null_ordered_named_pair() + RETURNS ordered_named_pair AS $$ +declare v ordered_named_pair; +begin +return v; +end +$$ LANGUAGE plpgsql; + +SELECT * FROM test_null_ordered_named_pair(); [parent: ebc53ca7b2ff]