|
27 | 27 | #include"funcapi.h"
|
28 | 28 | #include"libpq/pqformat.h"
|
29 | 29 | #include"miscadmin.h"
|
| 30 | +#include"nodes/nodeFuncs.h" |
| 31 | +#include"parser/parse_clause.h" |
30 | 32 | #include"parser/scansup.h"
|
31 | 33 | #include"utils/array.h"
|
32 | 34 | #include"utils/builtins.h"
|
@@ -308,6 +310,21 @@ timestamptypmodout(PG_FUNCTION_ARGS)
|
308 | 310 | }
|
309 | 311 |
|
310 | 312 |
|
| 313 | +/* timestamp_transform() |
| 314 | + * Flatten calls to timestamp_scale() and timestamptz_scale() that solely |
| 315 | + * represent increases in allowed precision. |
| 316 | + */ |
| 317 | +Datum |
| 318 | +timestamp_transform(PG_FUNCTION_ARGS) |
| 319 | +{ |
| 320 | +/* |
| 321 | + * timestamp_scale throws an error when the typmod is out of range, but we |
| 322 | + * can't get there from a cast: our typmodin will have caught it already. |
| 323 | + */ |
| 324 | +PG_RETURN_POINTER(TemporalTransform(MAX_TIMESTAMP_PRECISION, |
| 325 | +(Node*)PG_GETARG_POINTER(0))); |
| 326 | +} |
| 327 | + |
311 | 328 | /* timestamp_scale()
|
312 | 329 | * Adjust time type for specified scale factor.
|
313 | 330 | * Used by PostgreSQL type system to stuff columns.
|
@@ -745,6 +762,18 @@ interval_send(PG_FUNCTION_ARGS)
|
745 | 762 | PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
746 | 763 | }
|
747 | 764 |
|
| 765 | +/* |
| 766 | + * The interval typmod stores a "range" in its high 16 bits and a "precision" |
| 767 | + * in its low 16 bits. Both contribute to defining the resolution of the |
| 768 | + * type. Range addresses resolution granules larger than one second, and |
| 769 | + * precision specifies resolution below one second. This representation can |
| 770 | + * express all SQL standard resolutions, but we implement them all in terms of |
| 771 | + * truncating rightward from some position. Range is a bitmap of permitted |
| 772 | + * fields, but only the temporally-smallest such field is significant to our |
| 773 | + * calculations. Precision is a count of sub-second decimal places to retain. |
| 774 | + * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation |
| 775 | + * semantics as choosing MAX_INTERVAL_PRECISION. |
| 776 | + */ |
748 | 777 | Datum
|
749 | 778 | intervaltypmodin(PG_FUNCTION_ARGS)
|
750 | 779 | {
|
@@ -901,6 +930,63 @@ intervaltypmodout(PG_FUNCTION_ARGS)
|
901 | 930 | }
|
902 | 931 |
|
903 | 932 |
|
| 933 | +/* interval_transform() |
| 934 | + * Flatten superfluous calls to interval_scale(). The interval typmod is |
| 935 | + * complex to permit accepting and regurgitating all SQL standard variations. |
| 936 | + * For truncation purposes, it boils down to a single, simple granularity. |
| 937 | + */ |
| 938 | +Datum |
| 939 | +interval_transform(PG_FUNCTION_ARGS) |
| 940 | +{ |
| 941 | +FuncExpr*expr= (FuncExpr*)PG_GETARG_POINTER(0); |
| 942 | +Node*typmod; |
| 943 | +Node*ret=NULL; |
| 944 | + |
| 945 | +if (!IsA(expr,FuncExpr)) |
| 946 | +PG_RETURN_POINTER(ret); |
| 947 | + |
| 948 | +Assert(list_length(expr->args)==2); |
| 949 | +typmod=lsecond(expr->args); |
| 950 | + |
| 951 | +if (IsA(typmod,Const)) |
| 952 | +{ |
| 953 | +Node*source=linitial(expr->args); |
| 954 | +int32old_typmod=exprTypmod(source); |
| 955 | +int32new_typmod=DatumGetInt32(((Const*)typmod)->constvalue); |
| 956 | +intold_range; |
| 957 | +intold_precis; |
| 958 | +intnew_range=INTERVAL_RANGE(new_typmod); |
| 959 | +intnew_precis=INTERVAL_PRECISION(new_typmod); |
| 960 | +intnew_range_fls; |
| 961 | + |
| 962 | +if (old_typmod==-1) |
| 963 | +{ |
| 964 | +old_range=INTERVAL_FULL_RANGE; |
| 965 | +old_precis=INTERVAL_FULL_PRECISION; |
| 966 | +} |
| 967 | +else |
| 968 | +{ |
| 969 | +old_range=INTERVAL_RANGE(old_typmod); |
| 970 | +old_precis=INTERVAL_PRECISION(old_typmod); |
| 971 | +} |
| 972 | + |
| 973 | +/* |
| 974 | + * Temporally-smaller fields occupy higher positions in the range |
| 975 | + * bitmap. Since only the temporally-smallest bit matters for length |
| 976 | + * coercion purposes, we compare the last-set bits in the ranges. |
| 977 | + */ |
| 978 | +new_range_fls=fls(new_range); |
| 979 | +if (new_typmod==-1|| |
| 980 | +((new_range_fls >=SECOND|| |
| 981 | +new_range_fls >=fls(old_range))&& |
| 982 | + (new_precis >=MAX_INTERVAL_PRECISION|| |
| 983 | +new_precis >=old_precis))) |
| 984 | +ret=relabel_to_typmod(source,new_typmod); |
| 985 | +} |
| 986 | + |
| 987 | +PG_RETURN_POINTER(ret); |
| 988 | +} |
| 989 | + |
904 | 990 | /* interval_scale()
|
905 | 991 | * Adjust interval type for specified fields.
|
906 | 992 | * Used by PostgreSQL type system to stuff columns.
|
|