diff options
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r-- | src/backend/utils/adt/numeric.c | 69 |
1 files changed, 39 insertions, 30 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 45cd1a0664f..1c9deebc1dd 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -34,6 +34,7 @@ #include "libpq/pqformat.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "nodes/supportnodes.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/float.h" @@ -890,45 +891,53 @@ numeric_send(PG_FUNCTION_ARGS) /* - * numeric_transform() - + * numeric_support() * - * Flatten calls to numeric's length coercion function that solely represent - * increases in allowable precision. Scale changes mutate every datum, so - * they are unoptimizable. Some values, e.g. 1E-1001, can only fit into an - * unconstrained numeric, so a change from an unconstrained numeric to any - * constrained numeric is also unoptimizable. + * Planner support function for the numeric() length coercion function. + * + * Flatten calls that solely represent increases in allowable precision. + * Scale changes mutate every datum, so they are unoptimizable. Some values, + * e.g. 1E-1001, can only fit into an unconstrained numeric, so a change from + * an unconstrained numeric to any constrained numeric is also unoptimizable. */ Datum -numeric_transform(PG_FUNCTION_ARGS) +numeric_support(PG_FUNCTION_ARGS) { - FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0)); + Node *rawreq = (Node *) PG_GETARG_POINTER(0); Node *ret = NULL; - Node *typmod; - Assert(list_length(expr->args) >= 2); + if (IsA(rawreq, SupportRequestSimplify)) + { + SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq; + FuncExpr *expr = req->fcall; + Node *typmod; - typmod = (Node *) lsecond(expr->args); + Assert(list_length(expr->args) >= 2); - if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull) - { - Node *source = (Node *) linitial(expr->args); - int32 old_typmod = exprTypmod(source); - int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); - int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff; - int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff; - int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff; - int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff; + typmod = (Node *) lsecond(expr->args); - /* - * If new_typmod < VARHDRSZ, the destination is unconstrained; that's - * always OK. If old_typmod >= VARHDRSZ, the source is constrained, - * and we're OK if the scale is unchanged and the precision is not - * decreasing. See further notes in function header comment. - */ - if (new_typmod < (int32) VARHDRSZ || - (old_typmod >= (int32) VARHDRSZ && - new_scale == old_scale && new_precision >= old_precision)) - ret = relabel_to_typmod(source, new_typmod); + if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull) + { + Node *source = (Node *) linitial(expr->args); + int32 old_typmod = exprTypmod(source); + int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); + int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff; + int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff; + int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff; + int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff; + + /* + * If new_typmod < VARHDRSZ, the destination is unconstrained; + * that's always OK. If old_typmod >= VARHDRSZ, the source is + * constrained, and we're OK if the scale is unchanged and the + * precision is not decreasing. See further notes in function + * header comment. + */ + if (new_typmod < (int32) VARHDRSZ || + (old_typmod >= (int32) VARHDRSZ && + new_scale == old_scale && new_precision >= old_precision)) + ret = relabel_to_typmod(source, new_typmod); + } } PG_RETURN_POINTER(ret); |