diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2017-10-26 13:47:45 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2017-10-26 13:47:45 -0400 |
commit | 37a795a60b4f4b1def11c615525ec5e0e9449e05 (patch) | |
tree | a5aa9d7e51ef4fd0e353223bd691f7e85018a032 /src/backend/parser/parse_coerce.c | |
parent | 08f1e1f0a47b4b0e87b07b9794698747b279c711 (diff) |
Support domains over composite types.
This is the last major omission in our domains feature: you can now
make a domain over anything that's not a pseudotype.
The major complication from an implementation standpoint is that places
that might be creating tuples of a domain type now need to be prepared
to apply domain_check(). It seems better that unprepared code fail
with an error like "<type> is not composite" than that it silently fail
to apply domain constraints. Therefore, relevant infrastructure like
get_func_result_type() and lookup_rowtype_tupdesc() has been adjusted
to treat domain-over-composite as a distinct case that unprepared code
won't recognize, rather than just transparently treating it the same
as plain composite. This isn't a 100% solution to the possibility of
overlooked domain checks, but it catches most places.
In passing, improve typcache.c's support for domains (it can now cache
the identity of a domain's base type), and rewrite the argument handling
logic in jsonfuncs.c's populate_record[set]_worker to reduce duplicative
per-call lookups.
I believe this is code-complete so far as the core and contrib code go.
The PLs need varying amounts of work, which will be tackled in followup
patches.
Discussion: https://postgr.es/m/4206.1499798337@sss.pgh.pa.us
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 53457dc2c8d..def41b36b68 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -499,9 +499,26 @@ coerce_type(ParseState *pstate, Node *node, * Input class type is a subclass of target, so generate an * appropriate runtime conversion (removing unneeded columns and * possibly rearranging the ones that are wanted). + * + * We will also get here when the input is a domain over a subclass of + * the target type. To keep life simple for the executor, we define + * ConvertRowtypeExpr as only working between regular composite types; + * therefore, in such cases insert a RelabelType to smash the input + * expression down to its base type. */ + Oid baseTypeId = getBaseType(inputTypeId); ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr); + if (baseTypeId != inputTypeId) + { + RelabelType *rt = makeRelabelType((Expr *) node, + baseTypeId, -1, + InvalidOid, + COERCE_IMPLICIT_CAST); + + rt->location = location; + node = (Node *) rt; + } r->arg = (Expr *) node; r->resulttype = targetTypeId; r->convertformat = cformat; @@ -966,6 +983,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node, int location) { RowExpr *rowexpr; + Oid baseTypeId; + int32 baseTypeMod = -1; TupleDesc tupdesc; List *args = NIL; List *newargs; @@ -1001,7 +1020,14 @@ coerce_record_to_complex(ParseState *pstate, Node *node, format_type_be(targetTypeId)), parser_coercion_errposition(pstate, location, node))); - tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1); + /* + * Look up the composite type, accounting for possibility that what we are + * given is a domain over composite. + */ + baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod); + tupdesc = lookup_rowtype_tupdesc(baseTypeId, baseTypeMod); + + /* Process the fields */ newargs = NIL; ucolno = 1; arg = list_head(args); @@ -1070,10 +1096,22 @@ coerce_record_to_complex(ParseState *pstate, Node *node, rowexpr = makeNode(RowExpr); rowexpr->args = newargs; - rowexpr->row_typeid = targetTypeId; + rowexpr->row_typeid = baseTypeId; rowexpr->row_format = cformat; rowexpr->colnames = NIL; /* not needed for named target type */ rowexpr->location = location; + + /* If target is a domain, apply constraints */ + if (baseTypeId != targetTypeId) + { + rowexpr->row_format = COERCE_IMPLICIT_CAST; + return coerce_to_domain((Node *) rowexpr, + baseTypeId, baseTypeMod, + targetTypeId, + ccontext, cformat, location, + false); + } + return (Node *) rowexpr; } @@ -2401,13 +2439,13 @@ is_complex_array(Oid typid) /* * 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().) + * reloftypeId, or is a domain over such a row type. (This is conceptually + * similar to the subtype relationship checked by typeInheritsFrom().) */ static bool typeIsOfTypedTable(Oid reltypeId, Oid reloftypeId) { - Oid relid = typeidTypeRelid(reltypeId); + Oid relid = typeOrDomainTypeRelid(reltypeId); bool result = false; if (relid) |