mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
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.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user