diff options
author | Tom Lane | 2017-09-30 17:40:56 +0000 |
---|---|---|
committer | Tom Lane | 2017-09-30 17:40:56 +0000 |
commit | c12d570fa147d0ec273df53de3a2802925d551ba (patch) | |
tree | 781667b2e5ee4fe98ec4d1c9042cff5bfa2bc829 /src/include | |
parent | 248e33756b425335d94a32ffc8e9aace04f82c31 (diff) |
Support arrays over domains.
Allowing arrays with a domain type as their element type was left un-done
in the original domain patch, but not for any very good reason. This
omission leads to such surprising results as array_agg() not working on
a domain column, because the parser can't identify a suitable output type
for the polymorphic aggregate.
In order to fix this, first clean up the APIs of coerce_to_domain() and
some internal functions in parse_coerce.c so that we consistently pass
around a CoercionContext along with CoercionForm. Previously, we sometimes
passed an "isExplicit" boolean flag instead, which is strictly less
information; and coerce_to_domain() didn't even get that, but instead had
to reverse-engineer isExplicit from CoercionForm. That's contrary to the
documentation in primnodes.h that says that CoercionForm only affects
display and not semantics. I don't think this change fixes any live bugs,
but it makes things more consistent. The main reason for doing it though
is that now build_coercion_expression() receives ccontext, which it needs
in order to be able to recursively invoke coerce_to_target_type().
Next, reimplement ArrayCoerceExpr so that the node does not directly know
any details of what has to be done to the individual array elements while
performing the array coercion. Instead, the per-element processing is
represented by a sub-expression whose input is a source array element and
whose output is a target array element. This simplifies life in
parse_coerce.c, because it can build that sub-expression by a recursive
invocation of coerce_to_target_type(). The executor now handles the
per-element processing as a compiled expression instead of hard-wired code.
The main advantage of this is that we can use a single ArrayCoerceExpr to
handle as many as three successive steps per element: base type conversion,
typmod coercion, and domain constraint checking. The old code used two
stacked ArrayCoerceExprs to handle type + typmod coercion, which was pretty
inefficient, and adding yet another array deconstruction to do domain
constraint checking seemed very unappetizing.
In the case where we just need a single, very simple coercion function,
doing this straightforwardly leads to a noticeable increase in the
per-array-element runtime cost. Hence, add an additional shortcut evalfunc
in execExprInterp.c that skips unnecessary overhead for that specific form
of expression. The runtime speed of simple cases is within 1% or so of
where it was before, while cases that previously required two levels of
array processing are significantly faster.
Finally, create an implicit array type for every domain type, as we do for
base types, enums, etc. Everything except the array-coercion case seems
to just work without further effort.
Tom Lane, reviewed by Andrew Dunstan
Discussion: https://postgr.es/m/9852.1499791473@sss.pgh.pa.us
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/executor/execExpr.h | 7 | ||||
-rw-r--r-- | src/include/nodes/primnodes.h | 14 | ||||
-rw-r--r-- | src/include/parser/parse_coerce.h | 5 | ||||
-rw-r--r-- | src/include/utils/array.h | 9 |
5 files changed, 20 insertions, 17 deletions
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 5d57a95d8bb..2c382a73cfb 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201709191 +#define CATALOG_VERSION_NO 201709301 #endif diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 8ee0496e010..78d22478166 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -385,10 +385,8 @@ typedef struct ExprEvalStep /* for EEOP_ARRAYCOERCE */ struct { - ArrayCoerceExpr *coerceexpr; + ExprState *elemexprstate; /* null if no per-element work */ Oid resultelemtype; /* element type of result array */ - FmgrInfo *elemfunc; /* lookup info for element coercion - * function */ struct ArrayMapState *amstate; /* workspace for array_map */ } arraycoerce; @@ -621,7 +619,8 @@ extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op, extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op); -extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op); +extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); extern void ExecEvalRow(ExprState *state, ExprEvalStep *op); extern void ExecEvalMinMax(ExprState *state, ExprEvalStep *op); extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 8c536a8d38d..ccb5123e2ec 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -820,11 +820,12 @@ typedef struct CoerceViaIO * ArrayCoerceExpr * * ArrayCoerceExpr represents a type coercion from one array type to another, - * which is implemented by applying the indicated element-type coercion - * function to each element of the source array. If elemfuncid is InvalidOid - * then the element types are binary-compatible, but the coercion still - * requires some effort (we have to fix the element type ID stored in the - * array header). + * which is implemented by applying the per-element coercion expression + * "elemexpr" to each element of the source array. Within elemexpr, the + * source element is represented by a CaseTestExpr node. Note that even if + * elemexpr is a no-op (that is, just CaseTestExpr + RelabelType), the + * coercion still requires some effort: we have to fix the element type OID + * stored in the array header. * ---------------- */ @@ -832,11 +833,10 @@ typedef struct ArrayCoerceExpr { Expr xpr; Expr *arg; /* input expression (yields an array) */ - Oid elemfuncid; /* OID of element coercion function, or 0 */ + Expr *elemexpr; /* expression representing per-element work */ Oid resulttype; /* output type of coercion (an array type) */ int32 resulttypmod; /* output typmod (also element typmod) */ Oid resultcollid; /* OID of collation, or InvalidOid if none */ - bool isExplicit; /* conversion semantics flag to pass to func */ CoercionForm coerceformat; /* how to display this node */ int location; /* token location, or -1 if unknown */ } ArrayCoerceExpr; diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index 06f65293cb3..e560f0c96e4 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -48,9 +48,8 @@ extern Node *coerce_type(ParseState *pstate, Node *node, CoercionContext ccontext, CoercionForm cformat, int location); extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, - CoercionForm cformat, int location, - bool hideInputCoercion, - bool lengthCoercionDone); + CoercionContext ccontext, CoercionForm cformat, int location, + bool hideInputCoercion); extern Node *coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName); diff --git a/src/include/utils/array.h b/src/include/utils/array.h index d6d3c582b6a..cc19879a9a7 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -64,6 +64,10 @@ #include "fmgr.h" #include "utils/expandeddatum.h" +/* avoid including execnodes.h here */ +struct ExprState; +struct ExprContext; + /* * Arrays are varlena objects, so must meet the varlena convention that @@ -360,8 +364,9 @@ extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign); -extern Datum array_map(FunctionCallInfo fcinfo, Oid retType, - ArrayMapState *amstate); +extern Datum array_map(Datum arrayd, + struct ExprState *exprstate, struct ExprContext *econtext, + Oid retType, ArrayMapState *amstate); extern void array_bitmap_copy(bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, |