As we know, there is a simple way to cast any record to the corresponding composite type in PostgreSQL, like this:
CREATE TYPE test.t_test AS (
mytext text,
myint integer
);
SELECT ('text', 10)::test.t_test; -- will succeed
But one inconvenience with this is that – if the target type is modified (e.g. a field is added) – the cast will then break :(
ALTER TYPE test.t_test ADD ATTRIBUTE mychar char(1);
SELECT ('text', 10)::test.t_test; -- will fail
CREATE CAST
for this case may help but I cannot pass a pseudo-type like RECORD
as an argument to a casting function. And neither type-inheritance nor composite type defaults (like table) work either. Is there any other way to achieve compatibility here?
Of course it's possible to use explicit cast-functions like CREATE FUNCTION test.to_t_test(t text, i integer, c char DEFAULT '') RETURNS test.t_test
and then do
SELECT test.to_t_test('text', 10) -- OK
SELECT test.to_t_test('text', 10, '1') -- OK
then use default parameter values. But this way is neither clear nor comfortable.
Constructing Composite Values. To write a composite value as a literal constant, enclose the field values within parentheses and separate them by commas. You can put double quotes around any field value, and must do so if it contains commas or parentheses.
CREATE TABLE groups ( id int PRIMARY KEY, name varchar(30) ); CREATE TABLE emp ( id int PRIMARY KEY, name varchar(50), group_id int REFERENCES groups ); INSERT INTO groups(id,name) VALUES (1, 'Managers'), (2, 'Teachers'), (3, 'Cleaners'), (4, 'Drivers'); INSERT INTO emp(id,name,group_id) VALUES (1,'john',1), (2,'Smith' ...
PostgreSQL uses record type variables which simply act as placeholders for rows of a result set, similar to a row type variable. However, unlike row type variables, they do not have a predefined structure. Their structure is only determined after assigning a row to them.
My recommendation is that if you need to do this then take one of the following approaches:
Dynamic discovery of structure (using the pg_attribute
catalog table). This is not guaranteed to be future safe but probably is. It also has a bunch of gotchas (don't use attributes with an attnum
of less than 0 for example). This is usually the approach I take and have written libraries in Perl for doing such discovery on the client-end.
Create a use type and a storage type and have a cast between them. Thus you can do a SELECT ('text', 10)::test.used_test::test.stored_test
and that will work fine. But there is a reason you cannot cast record to a composite type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With