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_target.c | |
parent | 08f1e1f0a47b4b0e87b07b9794698747b279c711 (diff) | |
download | postgresql-37a795a60b4f4b1def11c615525ec5e0e9449e05.tar.gz postgresql-37a795a60b4f4b1def11c615525ec5e0e9449e05.zip |
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_target.c')
-rw-r--r-- | src/backend/parser/parse_target.c | 49 |
1 files changed, 29 insertions, 20 deletions
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 25475240259..01fd726a3d8 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -725,6 +725,8 @@ transformAssignmentIndirection(ParseState *pstate, else { FieldStore *fstore; + Oid baseTypeId; + int32 baseTypeMod; Oid typrelid; AttrNumber attnum; Oid fieldTypeId; @@ -752,7 +754,14 @@ transformAssignmentIndirection(ParseState *pstate, /* No subscripts, so can process field selection here */ - typrelid = typeidTypeRelid(targetTypeId); + /* + * Look up the composite type, accounting for possibility that + * what we are given is a domain over composite. + */ + baseTypeMod = targetTypMod; + baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod); + + typrelid = typeidTypeRelid(baseTypeId); if (!typrelid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -796,7 +805,17 @@ transformAssignmentIndirection(ParseState *pstate, fstore->arg = (Expr *) basenode; fstore->newvals = list_make1(rhs); fstore->fieldnums = list_make1_int(attnum); - fstore->resulttype = targetTypeId; + fstore->resulttype = baseTypeId; + + /* If target is a domain, apply constraints */ + if (baseTypeId != targetTypeId) + return coerce_to_domain((Node *) fstore, + baseTypeId, baseTypeMod, + targetTypeId, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + location, + false); return (Node *) fstore; } @@ -1164,7 +1183,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref, Node *node; node = pstate->p_post_columnref_hook(pstate, cref, - (Node *) rte); + (Node *) rte); if (node != NULL) { if (rte != NULL) @@ -1387,22 +1406,18 @@ ExpandRowReference(ParseState *pstate, Node *expr, * (This can be pretty inefficient if the expression involves nontrivial * computation :-(.) * - * Verify it's a composite type, and get the tupdesc. We use - * get_expr_result_type() because that can handle references to functions - * returning anonymous record types. If that fails, use - * lookup_rowtype_tupdesc(), which will almost certainly fail as well, but - * it will give an appropriate error message. + * Verify it's a composite type, and get the tupdesc. + * get_expr_result_tupdesc() handles this conveniently. * * If it's a Var of type RECORD, we have to work even harder: we have to - * find what the Var refers to, and pass that to get_expr_result_type. + * find what the Var refers to, and pass that to get_expr_result_tupdesc. * That task is handled by expandRecordVariable(). */ if (IsA(expr, Var) && ((Var *) expr)->vartype == RECORDOID) tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0); - else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) - tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr), - exprTypmod(expr)); + else + tupleDesc = get_expr_result_tupdesc(expr, false); Assert(tupleDesc); /* Generate a list of references to the individual fields */ @@ -1610,15 +1625,9 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup) /* * We now have an expression we can't expand any more, so see if - * get_expr_result_type() can do anything with it. If not, pass to - * lookup_rowtype_tupdesc() which will probably fail, but will give an - * appropriate error message while failing. + * get_expr_result_tupdesc() can do anything with it. */ - if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) - tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr), - exprTypmod(expr)); - - return tupleDesc; + return get_expr_result_tupdesc(expr, false); } |