Include column name in build_attrmap_by_position's error reports.

Formerly we only provided the column number, but it's frequently
more useful to mention the column name.  The input tupdesc often
doesn't have useful column names, but the output tupdesc usually
contains user-supplied names, so report that one.

Author: Marcos Pegoraro <marcos@f10.com.br>
Co-authored-by: jian he <jian.universality@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Co-authored-by: Erik Wienhold <ewie@ewie.name>
Reviewed-by: Vladlen Popolitov <v.popolitov@postgrespro.ru>
Discussion: https://postgr.es/m/CAB-JLwanky28gjAMdnMh1CjyO1b2zLdr6UOA1-oY9G7PVL9KKQ@mail.gmail.com
This commit is contained in:
Tom Lane
2025-03-07 13:24:09 -05:00
parent b48832cddb
commit 34c3c5ce1c
4 changed files with 41 additions and 23 deletions

View File

@ -96,33 +96,31 @@ build_attrmap_by_position(TupleDesc indesc,
same = true;
for (i = 0; i < n; i++)
{
Form_pg_attribute att = TupleDescAttr(outdesc, i);
Oid atttypid;
int32 atttypmod;
Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
if (att->attisdropped)
if (outatt->attisdropped)
continue; /* attrMap->attnums[i] is already 0 */
noutcols++;
atttypid = att->atttypid;
atttypmod = att->atttypmod;
for (; j < indesc->natts; j++)
{
att = TupleDescAttr(indesc, j);
if (att->attisdropped)
Form_pg_attribute inatt = TupleDescAttr(indesc, j);
if (inatt->attisdropped)
continue;
nincols++;
/* Found matching column, now check type */
if (atttypid != att->atttypid ||
(atttypmod != att->atttypmod && atttypmod >= 0))
if (outatt->atttypid != inatt->atttypid ||
(outatt->atttypmod != inatt->atttypmod && outatt->atttypmod >= 0))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg_internal("%s", _(msg)),
errdetail("Returned type %s does not match expected type %s in column %d.",
format_type_with_typemod(att->atttypid,
att->atttypmod),
format_type_with_typemod(atttypid,
atttypmod),
errdetail("Returned type %s does not match expected type %s in column \"%s\" (position %d).",
format_type_with_typemod(inatt->atttypid,
inatt->atttypmod),
format_type_with_typemod(outatt->atttypid,
outatt->atttypmod),
NameStr(outatt->attname),
noutcols)));
attrMap->attnums[i] = (AttrNumber) (j + 1);
j++;

View File

@ -28,7 +28,7 @@ create or replace function retc(int) returns two_int8s language plpgsql as
$$ begin return row($1,1); end $$;
select retc(42);
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 1.
DETAIL: Returned type integer does not match expected type bigint in column "q1" (position 1).
CONTEXT: PL/pgSQL function retc(integer) while casting return value to function's return type
-- nor extra columns
create or replace function retc(int) returns two_int8s language plpgsql as
@ -50,7 +50,7 @@ create or replace function retc(int) returns two_int8s language plpgsql as
$$ declare r record; begin r := row($1,1); return r; end $$;
select retc(42);
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 1.
DETAIL: Returned type integer does not match expected type bigint in column "q1" (position 1).
CONTEXT: PL/pgSQL function retc(integer) while casting return value to function's return type
create or replace function retc(int) returns two_int8s language plpgsql as
$$ declare r record; begin r := row($1::int8, 1::int8, 42); return r; end $$;
@ -386,7 +386,7 @@ DETAIL: Number of returned columns (2) does not match expected column count (3)
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
select * from returnsrecord(42) as r(x int, y bigint); -- fail
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 2.
DETAIL: Returned type integer does not match expected type bigint in column "y" (position 2).
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
-- same with an intermediate record variable
create or replace function returnsrecord(int) returns record language plpgsql as
@ -409,7 +409,7 @@ DETAIL: Number of returned columns (2) does not match expected column count (3)
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
select * from returnsrecord(42) as r(x int, y bigint); -- fail
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 2.
DETAIL: Returned type integer does not match expected type bigint in column "y" (position 2).
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
-- should work the same with a missing column in the actual result value
create table has_hole(f1 int, f2 int, f3 int);
@ -434,7 +434,7 @@ DETAIL: Number of returned columns (2) does not match expected column count (3)
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
select * from returnsrecord(42) as r(x int, y bigint); -- fail
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 2.
DETAIL: Returned type integer does not match expected type bigint in column "y" (position 2).
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
-- same with an intermediate record variable
create or replace function returnsrecord(int) returns record language plpgsql as
@ -457,7 +457,7 @@ DETAIL: Number of returned columns (2) does not match expected column count (3)
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
select * from returnsrecord(42) as r(x int, y bigint); -- fail
ERROR: returned record type does not match expected record type
DETAIL: Returned type integer does not match expected type bigint in column 2.
DETAIL: Returned type integer does not match expected type bigint in column "y" (position 2).
CONTEXT: PL/pgSQL function returnsrecord(integer) while casting return value to function's return type
-- check access to a field of an argument declared "record"
create function getf1(x record) returns int language plpgsql as
@ -545,6 +545,7 @@ begin
return next h;
return next row(5,6);
return next row(7,8)::has_hole;
return query select 9, 10;
end$$;
select returnssetofholes();
returnssetofholes
@ -554,7 +555,8 @@ select returnssetofholes();
(3,4)
(5,6)
(7,8)
(5 rows)
(9,10)
(6 rows)
create or replace function returnssetofholes() returns setof has_hole language plpgsql as
$$
@ -575,6 +577,16 @@ select returnssetofholes();
ERROR: returned record type does not match expected record type
DETAIL: Number of returned columns (3) does not match expected column count (2).
CONTEXT: PL/pgSQL function returnssetofholes() line 3 at RETURN NEXT
create or replace function returnssetofholes() returns setof has_hole language plpgsql as
$$
begin
return query select 1, 2.0; -- fails
end$$;
select returnssetofholes();
ERROR: structure of query does not match function result type
DETAIL: Returned type numeric does not match expected type integer in column "f3" (position 2).
CONTEXT: SQL statement "select 1, 2.0"
PL/pgSQL function returnssetofholes() line 3 at RETURN QUERY
-- check behavior with changes of a named rowtype
create table mutable(f1 int, f2 text);
create function sillyaddone(int) returns int language plpgsql as

View File

@ -338,6 +338,7 @@ begin
return next h;
return next row(5,6);
return next row(7,8)::has_hole;
return query select 9, 10;
end$$;
select returnssetofholes();
@ -356,6 +357,13 @@ begin
end$$;
select returnssetofholes();
create or replace function returnssetofholes() returns setof has_hole language plpgsql as
$$
begin
return query select 1, 2.0; -- fails
end$$;
select returnssetofholes();
-- check behavior with changes of a named rowtype
create table mutable(f1 int, f2 text);

View File

@ -3779,7 +3779,7 @@ end;
$$ language plpgsql;
select compos();
ERROR: returned record type does not match expected record type
DETAIL: Returned type unknown does not match expected type character varying in column 2.
DETAIL: Returned type unknown does not match expected type character varying in column "y" (position 2).
CONTEXT: PL/pgSQL function compos() while casting return value to function's return type
-- ... but this does
create or replace function compos() returns compostype as $$