aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2011-01-01 22:44:32 +0200
committerPeter Eisentraut <peter_e@gmx.net>2011-01-01 23:04:14 +0200
commit6a208aa40438652e2f3129a63af5d08ae53d9398 (patch)
tree9946b11e74e4c6ebaefbaf5ab55519a15c84a6ac /src
parent92a73d219052ab4d393ebe7b5362aa7d414156e7 (diff)
downloadpostgresql-6a208aa40438652e2f3129a63af5d08ae53d9398.tar.gz
postgresql-6a208aa40438652e2f3129a63af5d08ae53d9398.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_coerce.c39
-rw-r--r--src/test/regress/expected/typed_table.out15
-rw-r--r--src/test/regress/sql/typed_table.sql12
3 files changed, 64 insertions, 2 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 33a60a1edb4..5b0dc1420d0 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 6db8d4c8031..0874a64d554 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 1afede14b10..b0d452c387e 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;