From 6a208aa40438652e2f3129a63af5d08ae53d9398 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 1 Jan 2011 22:44:32 +0200 Subject: [PATCH] Allow casting a table's row type to the table's supertype if it's a typed table This is analogous to the existing facility that allows casting a row type to a supertable's row type. --- src/backend/parser/parse_coerce.c | 39 +++++++++++++++++++++-- src/test/regress/expected/typed_table.out | 15 +++++++++ src/test/regress/sql/typed_table.sql | 12 +++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 33a60a1edb..5b0dc1420d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -15,6 +15,7 @@ #include "postgres.h" #include "catalog/pg_cast.h" +#include "catalog/pg_class.h" #include "catalog/pg_inherits_fn.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" @@ -48,6 +49,7 @@ static Node *coerce_record_to_complex(ParseState *pstate, Node *node, CoercionForm cformat, int location); static bool is_complex_array(Oid typid); +static bool typeIsOfTypedTable(Oid reltypeId, Oid reloftypeId); /* @@ -371,7 +373,8 @@ coerce_type(ParseState *pstate, Node *node, /* NB: we do NOT want a RelabelType here */ return node; } - if (typeInheritsFrom(inputTypeId, targetTypeId)) + if (typeInheritsFrom(inputTypeId, targetTypeId) + || typeIsOfTypedTable(inputTypeId, targetTypeId)) { /* * Input class type is a subclass of target, so generate an @@ -482,7 +485,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, /* * If input is a class type that inherits from target, accept */ - if (typeInheritsFrom(inputTypeId, targetTypeId)) + if (typeInheritsFrom(inputTypeId, targetTypeId) + || typeIsOfTypedTable(inputTypeId, targetTypeId)) continue; /* @@ -2046,3 +2050,34 @@ is_complex_array(Oid typid) return (OidIsValid(elemtype) && ISCOMPLEX(elemtype)); } + + +/* + * Check whether reltypeId is the row type of a typed table of type + * reloftypeId. (This is conceptually similar to the subtype + * relationship checked by typeInheritsFrom().) + */ +static bool +typeIsOfTypedTable(Oid reltypeId, Oid reloftypeId) +{ + Oid relid = typeidTypeRelid(reltypeId); + bool result = false; + + if (relid) + { + HeapTuple tp; + Form_pg_class reltup; + + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for relation %u", relid); + + reltup = (Form_pg_class) GETSTRUCT(tp); + if (reltup->reloftype == reloftypeId) + result = true; + + ReleaseSysCache(tp); + } + + return result; +} diff --git a/src/test/regress/expected/typed_table.out b/src/test/regress/expected/typed_table.out index 6db8d4c803..0874a64d55 100644 --- a/src/test/regress/expected/typed_table.out +++ b/src/test/regress/expected/typed_table.out @@ -92,3 +92,18 @@ drop cascades to function get_all_persons() drop cascades to table persons2 drop cascades to table persons3 DROP TABLE stuff; +-- implicit casting +CREATE TYPE person_type AS (id int, name text); +CREATE TABLE persons OF person_type; +INSERT INTO persons VALUES (1, 'test'); +CREATE FUNCTION namelen(person_type) RETURNS int LANGUAGE SQL AS $$ SELECT length($1.name) $$; +SELECT id, namelen(persons) FROM persons; + id | namelen +----+--------- + 1 | 4 +(1 row) + +DROP TYPE person_type CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table persons +drop cascades to function namelen(person_type) diff --git a/src/test/regress/sql/typed_table.sql b/src/test/regress/sql/typed_table.sql index 1afede14b1..b0d452c387 100644 --- a/src/test/regress/sql/typed_table.sql +++ b/src/test/regress/sql/typed_table.sql @@ -47,3 +47,15 @@ DROP TYPE person_type RESTRICT; DROP TYPE person_type CASCADE; DROP TABLE stuff; + + +-- implicit casting + +CREATE TYPE person_type AS (id int, name text); +CREATE TABLE persons OF person_type; +INSERT INTO persons VALUES (1, 'test'); + +CREATE FUNCTION namelen(person_type) RETURNS int LANGUAGE SQL AS $$ SELECT length($1.name) $$; +SELECT id, namelen(persons) FROM persons; + +DROP TYPE person_type CASCADE; -- 2.40.0