|  | 
| 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 | +		int32		old_typmod = exprTypmod(source); | 
|  | 955 | +		int32		new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); | 
|  | 956 | +		int			old_range; | 
|  | 957 | +		int			old_precis; | 
|  | 958 | +		int			new_range = INTERVAL_RANGE(new_typmod); | 
|  | 959 | +		int			new_precis = INTERVAL_PRECISION(new_typmod); | 
|  | 960 | +		int			new_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. | 
|  | 
0 commit comments