|
30 | 30 | #include "catalog/pg_type.h"
|
31 | 31 | #include "libpq/pqformat.h"
|
32 | 32 | #include "miscadmin.h"
|
| 33 | +#include "nodes/nodeFuncs.h" |
| 34 | +#include "parser/parse_clause.h" |
33 | 35 | #include "utils/array.h"
|
34 | 36 | #include "utils/builtins.h"
|
35 | 37 | #include "utils/int8.h"
|
@@ -712,6 +714,52 @@ numeric_send(PG_FUNCTION_ARGS)
|
712 | 714 | }
|
713 | 715 |
|
714 | 716 |
|
| 717 | +/* |
| 718 | + * numeric_transform() - |
| 719 | + * |
| 720 | + * Flatten calls to our length coercion function that solely represent |
| 721 | + * increases in allowable precision. Scale changes mutate every datum, so |
| 722 | + * they are unoptimizable. Some values, e.g. 1E-1001, can only fit into an |
| 723 | + * unconstrained numeric, so a change from an unconstrained numeric to any |
| 724 | + * constrained numeric is also unoptimizable. |
| 725 | + */ |
| 726 | +Datum |
| 727 | +numeric_transform(PG_FUNCTION_ARGS) |
| 728 | +{ |
| 729 | + FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0); |
| 730 | + Node *typmod; |
| 731 | + Node *ret = NULL; |
| 732 | + |
| 733 | + if (!IsA(expr, FuncExpr)) |
| 734 | + PG_RETURN_POINTER(ret); |
| 735 | + |
| 736 | + Assert(list_length(expr->args) == 2); |
| 737 | + typmod = lsecond(expr->args); |
| 738 | + |
| 739 | + if (IsA(typmod, Const)) |
| 740 | + { |
| 741 | + Node *source = linitial(expr->args); |
| 742 | + int32 old_typmod = exprTypmod(source); |
| 743 | + int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); |
| 744 | + int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff; |
| 745 | + int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff; |
| 746 | + int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff; |
| 747 | + int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff; |
| 748 | + |
| 749 | + /* |
| 750 | + * If new_typmod < VARHDRSZ, the destination is unconstrained; that's |
| 751 | + * always OK. If old_typmod >= VARHDRSZ, the source is constained. |
| 752 | + * and we're OK if the scale is unchanged and the precison is not |
| 753 | + * decreasing. See further nodes in function header comment. |
| 754 | + */ |
| 755 | + if (new_typmod < VARHDRSZ || (old_typmod >= VARHDRSZ && |
| 756 | + new_scale == old_scale && new_precision >= old_precision)) |
| 757 | + ret = relabel_to_typmod(source, new_typmod); |
| 758 | + } |
| 759 | + |
| 760 | + PG_RETURN_POINTER(ret); |
| 761 | +} |
| 762 | + |
715 | 763 | /*
|
716 | 764 | * numeric() -
|
717 | 765 | *
|
|
0 commit comments