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++;
$$ 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
$$ 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 $$;
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
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);
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
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
return next h;
return next row(5,6);
return next row(7,8)::has_hole;
+ return query select 9, 10;
end$$;
select returnssetofholes();
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
$$
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