Is it possible to extend an existing datatype in PostgreSQL? Essentially, I want the equivalent of this TypeScript but in SQL:
interface Meeting {
id: number;
start: Date;
end: Date;
description: string;
}
interface ServiceHour extends Meeting {
total: number;
hours: number;
}
Because I have a function that returns all the columns from a meetings table and then the additional two total and hours columns that are computed at query time. Here's what that function looks like:
create or replace function user_hours(org_id text, user_id text)
returns table (like meeting_instances)
as $$
select (sum(hours) over (order by _.instance_time)) total, * from (
select
extract(epoch from ((meeting_instances.time).to - (meeting_instances.time).from)) / 60 / 60 as hours,
meeting_instances.*
from meeting_instances inner join relation_people on relation_people.meeting = meeting_instances.id
where relation_people.user = user_id
and meeting_instances.org = org_id
and meeting_instances.instance_time <= current_date
) as _;
$$
language sql stable;
And right now, I'm getting a type mismatch error because table (like meeting_instances) isn't the same as a table with the meeting_instances columns and the two new hours and total columns. What I want to be able to do is something like this (obviously the syntax below doesn't actually exist... but I'm not sure if there's another way to do this with a similar shorthand syntax):
returns table (total float, hours float, meeting_instances.*)
returns table (total float, hours float) intersect (like meeting_instances)
returns table (total float, hours float) extends (like meeting_instances)
My current workaround is to create a view and then have that function simply query that view and return the view's type.
To your core question:
No, not possible. Not in the
RETURNSclause ofCREATE FUNCTION, not anywhere else in PostgreSQL up to version 14.You can return a field of composite type, plus additional fields of any type. But that's subtly different:
Calling that function with:
Returns a nested composite type as one of the return columns, like:
To decompose the composite type, you could call with:
But I wouldn't go there.
Then just use the view. Don't create an additional function on top of it. Case closed.
If you actually meant to say:
Then we are back to your question.
CREATE VIEWto (implicitly) register the extended row type is a valid option - especially sinceSELECT *is a convenient syntax shorthand for the case at had. But for starters,... isn't documented syntax for
CREATE FUNCTION. Nobody should use it. Might be removed without notice in one of the next versions.The canonical, equivalent, documented syntax is:
(LIKE some_table)is documented syntax forCREATE TABLE. TheRETURNSclause ofCREATE FUNCTIONcurrently supports the same, but it's not documented, so don't use it.Back to your workaround with creating a
VIEW. If you have no use for theVIEW, other than registering that extended row type, considerCREATE TYPEinstead. Unfortunately,CREATE TYPEdoes not allowLIKE other_typesyntax, either. You have to spell out all columns (attributes) of the composite type. Like:Then you can use:
Just like you wanted.
But for just the one function, I would use
RETURNS TABLE()instead and spell out the return type:Oh, and I wouldn't use "start" and "end" as identifiers in Postgres. Both are reserved words in standard SQL. "end" is absolutely reserved in Postgres and must always be double-quoted.