Building on commit 8f9fe6edce358f7904e0db119416b4d1080a83aa, this adds protransform functions to the length coercions for numeric, varbit, timestamp, timestamptz, time, timetz and interval. This mostly serves to make more ALTER TABLE ALTER TYPE operations avoid a rewrite, including numeric(10,2) -> numeric(12,2), varbit(4) -> varbit(8) and timestamptz(2) -> timestamptz(4). The rules for varbit are exactly the same as for varchar. Numeric is slightly more complex:
* Flatten calls to our 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. time{,stamp}{,tz} are similar to varchar for these purposes, except that, for example, plain "timestamptz" is equivalent to "timestamptz(6)". interval has a vastly different typmod format, but the principles applicable to length coercion remain the same. Under --disable-integer-datetimes, I'm not positive that timestamp_scale() is always a no-op when one would logically expect as much. Does there exist a timestamp such that v::timestamp(2) differs from v:timestamp(2)::timestamp(4) due to floating point rounding? Even if so, I'm fairly comfortable calling it a feature rather than a bug to avoid perturbing values that way. After these patches, the only core length coercion casts not having protransform functions are those for "bpchar" and "bit". For those, we could only optimize trivial cases of no length change. I'm not planning to do so. Thanks, nm
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 3fa8117..e5a03b9 100644 *** a/src/backend/utils/adt/varbit.c --- b/src/backend/utils/adt/varbit.c *************** *** 18,23 **** --- 18,25 ---- #include "access/htup.h" #include "libpq/pqformat.h" + #include "nodes/nodeFuncs.h" + #include "parser/parse_clause.h" #include "utils/array.h" #include "utils/varbit.h" *************** *** 646,651 **** varbit_send(PG_FUNCTION_ARGS) --- 648,686 ---- } /* + * varbit_transform() + * Flatten calls to our length coercion function that leave the new maximum + * length >= the previous maximum length. We ignore the isExplicit argument, + * which only affects truncation. + */ + Datum + varbit_transform(PG_FUNCTION_ARGS) + { + FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0); + Node *typmod; + Node *ret = NULL; + + if (!IsA(expr, FuncExpr)) + PG_RETURN_POINTER(ret); + + Assert(list_length(expr->args) == 3); + typmod = lsecond(expr->args); + + if (IsA(typmod, Const)) + { + Node *source = linitial(expr->args); + int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); + int32 old_max = exprTypmod(source); + int32 new_max = new_typmod; + + if (new_max <= 0 || (old_max >= 0 && old_max <= new_max)) + ret = relabel_to_typmod(source, new_typmod); + } + + PG_RETURN_POINTER(ret); + } + + /* * varbit() * Converts a varbit() type to a specific internal length. * len is the maximum bitlength specified in the column definition. diff --git a/src/include/catalog/pg_pindex c893c3a..2a71f82 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2005,2011 **** DESCR("convert bitstring to int4"); DATA(insert OID = 1685 ( bit PGNSP PGUID 12 1 0 0 0 f f f t f i 3 0 1560 "1560 23 16" _null_ _null_ _null_ _null_ bit _null_ _null_ _null_ )); DESCR("adjust bit() to typmod length"); ! DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 1 0 0 0 f f f t f i 3 0 1562 "1562 23 16" _null_ _null_ _null_ _null_ varbit _null_ _null_ _null_ )); DESCR("adjust varbit() to typmod length"); DATA(insert OID = 1698 ( position PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ )); --- 2005,2013 ---- DATA(insert OID = 1685 ( bit PGNSP PGUID 12 1 0 0 0 f f f t f i 3 0 1560 "1560 23 16" _null_ _null_ _null_ _null_ bit _null_ _null_ _null_ )); DESCR("adjust bit() to typmod length"); ! DATA(insert OID = 3145 ( varbit_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ varbit_transform _null_ _null_ _null_ )); ! DESCR("transform a varbit length coercion"); ! DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 1 0 0 3145 f f f t f i 3 0 1562 "1562 23 16" _null_ _null_ _null_ _null_ varbit _null_ _null_ _null_ )); DESCR("adjust varbit() to typmod length"); DATA(insert OID = 1698 ( position PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ )); diff --git a/src/include/utils/varbiindex e329d52..5f2d8dd 100644 *** a/src/include/utils/varbit.h --- b/src/include/utils/varbit.h *************** *** 72,77 **** extern Datum varbit_send(PG_FUNCTION_ARGS); --- 72,78 ---- extern Datum varbittypmodin(PG_FUNCTION_ARGS); extern Datum varbittypmodout(PG_FUNCTION_ARGS); extern Datum bit(PG_FUNCTION_ARGS); + extern Datum varbit_transform(PG_FUNCTION_ARGS); extern Datum varbit(PG_FUNCTION_ARGS); extern Datum biteq(PG_FUNCTION_ARGS); extern Datum bitne(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expindex 301cc4b..ca83664 100644
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 6b60a5c..e70230e 100644 *** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c *************** *** 30,35 **** --- 30,37 ---- #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "miscadmin.h" + #include "nodes/nodeFuncs.h" + #include "parser/parse_clause.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/int8.h" *************** *** 713,718 **** numeric_send(PG_FUNCTION_ARGS) --- 715,762 ---- /* + * numeric_transform() - + * + * Flatten calls to our 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. + */ + Datum + numeric_transform(PG_FUNCTION_ARGS) + { + FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0); + Node *typmod; + Node *ret = NULL; + + if (!IsA(expr, FuncExpr)) + PG_RETURN_POINTER(ret); + + Assert(list_length(expr->args) == 2); + typmod = lsecond(expr->args); + + if (IsA(typmod, Const)) + { + Node *source = 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_precis = (old_typmod - VARHDRSZ) >> 16 & 0xffff; + int32 new_precis = (new_typmod - VARHDRSZ) >> 16 & 0xffff; + + if (new_typmod < VARHDRSZ /* unconstrained destination */ || + (old_typmod >= VARHDRSZ /* constrained source */ && + new_scale == old_scale && + new_precis >= old_precis)) + ret = relabel_to_typmod(source, new_typmod); + } + + PG_RETURN_POINTER(ret); + } + + /* * numeric() - * * This is a special function called by the Postgres database system diff --git a/src/include/catalog/pg_prindex c893c3a..d0d25b8 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2135,2142 **** DATA(insert OID = 2917 ( numerictypmodin PGNSP PGUID 12 1 0 0 0 f f f t f i 1 DESCR("I/O typmod"); DATA(insert OID = 2918 ( numerictypmodout PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_ numerictypmodout _null_ _null_ _null_ )); DESCR("I/O typmod"); ! DATA(insert OID = 1703 ( numeric PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ numeric _null_ _null_ _null_ )); DESCR("adjust numeric to typmod precision/scale"); DATA(insert OID = 1704 ( numeric_abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ )); DATA(insert OID = 1705 ( abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ )); DESCR("absolute value"); --- 2135,2144 ---- DESCR("I/O typmod"); DATA(insert OID = 2918 ( numerictypmodout PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_ numerictypmodout _null_ _null_ _null_ )); DESCR("I/O typmod"); ! DATA(insert OID = 1703 ( numeric PGNSP PGUID 12 1 0 0 3144 f f f t f i 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ numeric _null_ _null_ _null_ )); DESCR("adjust numeric to typmod precision/scale"); + DATA(insert OID = 3144 ( numeric_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ numeric_transform _null_ _null_ _null_ )); + DESCR("transform a numeric length coercion"); DATA(insert OID = 1704 ( numeric_abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ )); DATA(insert OID = 1705 ( abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ )); DESCR("absolute value"); diff --git a/src/include/utils/builtindex aa36db6..63e2844 100644 *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** *** 910,915 **** extern Datum numeric_recv(PG_FUNCTION_ARGS); --- 910,916 ---- extern Datum numeric_send(PG_FUNCTION_ARGS); extern Datum numerictypmodin(PG_FUNCTION_ARGS); extern Datum numerictypmodout(PG_FUNCTION_ARGS); + extern Datum numeric_transform(PG_FUNCTION_ARGS); extern Datum numeric (PG_FUNCTION_ARGS); extern Datum numeric_abs(PG_FUNCTION_ARGS); extern Datum numeric_uminus(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expecindex 301cc4b..be669b6 100644
diff --git a/configure b/configure index bfc7a1f..7e1b74f 100755 *** a/configure --- b/configure *************** *** 20773,20779 **** LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` ! for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 --- 20773,20780 ---- ! ! for ac_func in crypt fls getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/conindex 54ca820..b684512 100644 *** a/configure.in --- b/configure.in *************** *** 1319,1325 **** fi pgac_save_LIBS="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` ! AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul]) case $host_os in --- 1319,1325 ---- pgac_save_LIBS="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` ! AC_REPLACE_FUNCS([crypt fls getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul]) case $host_os in diff --git a/src/baindex ff4e304..1c84e87 100644 *** a/src/backend/utils/adt/date.c --- b/src/backend/utils/adt/date.c *************** *** 1210,1215 **** timetypmodout(PG_FUNCTION_ARGS) --- 1210,1226 ---- } + /* time_transform() + * Flatten calls to time_scale() and timetz_scale() that solely represent + * increases in allowed precision. + */ + Datum + time_transform(PG_FUNCTION_ARGS) + { + PG_RETURN_POINTER(TemporalTransform(MAX_TIME_PRECISION, + (Node *) PG_GETARG_POINTER(0))); + } + /* time_scale() * Adjust time type for specified scale factor. * Used by PostgreSQL type system to stuff columns. diff --git a/src/backend/utils/adt/index dad41fc..fd118c4 100644 *** a/src/backend/utils/adt/datetime.c --- b/src/backend/utils/adt/datetime.c *************** *** 23,28 **** --- 23,30 ---- #include "catalog/pg_type.h" #include "funcapi.h" #include "miscadmin.h" + #include "nodes/nodeFuncs.h" + #include "parser/parse_clause.h" #include "utils/builtins.h" #include "utils/date.h" #include "utils/datetime.h" *************** *** 4142,4147 **** CheckDateTokenTables(void) --- 4144,4182 ---- } /* + * Helper for temporal protransform functions. Types time, timetz, timestamp + * and timestamptz each have a range of allowed precisions. An unspecified + * precision is rigorously equivalent to the highest specifiable precision. + */ + Node * + TemporalTransform(int32 max_precis, Node *node) + { + FuncExpr *expr = (FuncExpr *) node; + Node *typmod; + Node *ret = NULL; + + if (!IsA(expr, FuncExpr)) + return ret; + + Assert(list_length(expr->args) == 2); + typmod = lsecond(expr->args); + + if (IsA(typmod, Const)) + { + Node *source = linitial(expr->args); + int32 old_precis = exprTypmod(source); + int32 new_precis = DatumGetInt32(((Const *) typmod)->constvalue); + + if (new_precis == -1 || + new_precis == max_precis || + (old_precis != -1 && new_precis >= old_precis)) + ret = relabel_to_typmod(source, new_precis); + } + + return ret; + } + + /* * This function gets called during timezone config file load or reload * to create the final array of timezone tokens. The argument array * is already sorted in name order. The data is converted to datetkn diff --git a/src/backend/utils/adt/timeindex 450dcd4..c7bd1e3 100644 *** a/src/backend/utils/adt/timestamp.c --- b/src/backend/utils/adt/timestamp.c *************** *** 27,32 **** --- 27,34 ---- #include "funcapi.h" #include "libpq/pqformat.h" #include "miscadmin.h" + #include "nodes/nodeFuncs.h" + #include "parser/parse_clause.h" #include "parser/scansup.h" #include "utils/array.h" #include "utils/builtins.h" *************** *** 308,313 **** timestamptypmodout(PG_FUNCTION_ARGS) --- 310,330 ---- } + /* timestamp_transform() + * Flatten calls to timestamp_scale() and timestamptz_scale() that solely + * represent increases in allowed precision. + */ + Datum + timestamp_transform(PG_FUNCTION_ARGS) + { + /* + * timestamp_scale throws an error when the typmod is out of range, but we + * can't get there from a cast: our typmodin will have caught it already. + */ + PG_RETURN_POINTER(TemporalTransform(MAX_TIMESTAMP_PRECISION, + (Node *) PG_GETARG_POINTER(0))); + } + /* timestamp_scale() * Adjust time type for specified scale factor. * Used by PostgreSQL type system to stuff columns. *************** *** 745,750 **** interval_send(PG_FUNCTION_ARGS) --- 762,779 ---- PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } + /* + * The interval typmod stores a "range" in its high 16 bits and a "precision" + * in its low 16 bits. Both contribute to defining the resolution of the + * type. Range addresses resolution granules larger than one second, and + * precision specifies resolution below one second. This representation can + * express all SQL standard resolutions, but we implement them all in terms of + * truncating rightward from some position. Range is a bitmap of permitted + * fields, but only the temporally-smallest such field is significant to our + * calculations. Precision is a count of sub-second decimal places to retain. + * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation + * semantics as choosing MAX_INTERVAL_PRECISION. + */ Datum intervaltypmodin(PG_FUNCTION_ARGS) { *************** *** 901,906 **** intervaltypmodout(PG_FUNCTION_ARGS) --- 930,993 ---- } + /* interval_transform() + + * Flatten superfluous calls to interval_scale(). The interval typmod is + * complex to permit accepting and regurgitating all SQL standard variations. + * For truncation purposes, it boils down to a single, simple granularity. + */ + Datum + interval_transform(PG_FUNCTION_ARGS) + { + FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0); + Node *typmod; + Node *ret = NULL; + + if (!IsA(expr, FuncExpr)) + PG_RETURN_POINTER(ret); + + Assert(list_length(expr->args) == 2); + typmod = lsecond(expr->args); + + if (IsA(typmod, Const)) + { + Node *source = linitial(expr->args); + int32 old_typmod = exprTypmod(source); + int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); + int old_range; + int old_precis; + int new_range = INTERVAL_RANGE(new_typmod); + int new_precis = INTERVAL_PRECISION(new_typmod); + int new_range_fls; + + if (old_typmod == -1) + { + old_range = INTERVAL_FULL_RANGE; + old_precis = INTERVAL_FULL_PRECISION; + } + else + { + old_range = INTERVAL_RANGE(old_typmod); + old_precis = INTERVAL_PRECISION(old_typmod); + } + + /* + * Temporally-smaller fields occupy higher positions in the range + * bitmap. Since only the temporally-smallest bit matters for length + * coercion purposes, we compare the last-set bits in the ranges. + */ + new_range_fls = fls(new_range); + if (new_typmod == -1 || + ((new_range_fls >= SECOND || + new_range_fls >= fls(old_range)) && + (new_precis >= MAX_INTERVAL_PRECISION || + new_precis >= old_precis))) + ret = relabel_to_typmod(source, new_typmod); + } + + PG_RETURN_POINTER(ret); + } + /* interval_scale() * Adjust interval type for specified fields. * Used by PostgreSQL type system to stuff columns. diff --git a/src/include/catalog/pg_procindex c893c3a..49cde6b 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 1253,1259 **** DESCR("date difference preserving months and years"); /* OIDS 1200 - 1299 */ ! DATA(insert OID = 1200 ( interval PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1186 "1186 23" _null_ _null_ _null_ _null_ interval_scale _null_ _null_ _null_ )); DESCR("adjust interval precision"); DATA(insert OID = 1215 ( obj_description PGNSP PGUID 14 100 0 0 0 f f f t f s 2 0 25 "26 19" _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0" _null_ _null_ _null_ )); --- 1253,1261 ---- /* OIDS 1200 - 1299 */ ! DATA(insert OID = 3148 ( interval_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ interval_transform _null_ _null_ _null_ )); ! DESCR("transform an interval length coercion"); ! DATA(insert OID = 1200 ( interval PGNSP PGUID 12 1 0 0 3148 f f f t f i 2 0 1186 "1186 23" _null_ _null_ _null_ _null_ interval_scale _null_ _null_ _null_ )); DESCR("adjust interval precision"); DATA(insert OID = 1215 ( obj_description PGNSP PGUID 14 100 0 0 0 f f f t f s 2 0 25 "26 19" _null_ _null_ _null_ _null_ "select description from pg_catalog.pg_description where objoid = $1 and classoid = (select oid from pg_catalog.pg_class where relname = $2 and relnamespace = PGNSP) and objsubid = 0" _null_ _null_ _null_ )); *************** *** 2712,2718 **** DATA(insert OID = 1953 ( byteane PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 DATA(insert OID = 1954 ( byteacmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "17 17" _null_ _null_ _null_ _null_ byteacmp _null_ _null_ _null_ )); DESCR("less-equal-greater"); ! DATA(insert OID = 1961 ( timestamp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1114 "1114 23" _null_ _null_ _null_ _null_ timestamp_scale _null_ _null_ _null_ )); DESCR("adjust timestamp precision"); DATA(insert OID = 1965 ( oidlarger PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 26 "26 26" _null_ _null_ _null_ _null_ oidlarger _null_ _null_ _null_ )); --- 2714,2722 ---- DATA(insert OID = 1954 ( byteacmp PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "17 17" _null_ _null_ _null_ _null_ byteacmp _null_ _null_ _null_ )); DESCR("less-equal-greater"); ! DATA(insert OID = 3147 ( timestamp_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ timestamp_transform _null_ _null_ _null_ )); ! DESCR("transform a timestamp length coercion"); ! DATA(insert OID = 1961 ( timestamp PGNSP PGUID 12 1 0 0 3147 f f f t f i 2 0 1114 "1114 23" _null_ _null_ _null_ _null_ timestamp_scale _null_ _null_ _null_ )); DESCR("adjust timestamp precision"); DATA(insert OID = 1965 ( oidlarger PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 26 "26 26" _null_ _null_ _null_ _null_ oidlarger _null_ _null_ _null_ )); *************** *** 2720,2730 **** DESCR("larger of two"); DATA(insert OID = 1966 ( oidsmaller PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 26 "26 26" _null_ _null_ _null_ _null_ oidsmaller _null_ _null_ _null_ )); DESCR("smaller of two"); ! DATA(insert OID = 1967 ( timestamptz PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1184 "1184 23" _null_ _null_ _null_ _null_ timestamptz_scale _null_ _null_ _null_ )); DESCR("adjust timestamptz precision"); ! DATA(insert OID = 1968 ( time PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1083 "1083 23" _null_ _null_ _null_ _null_ time_scale _null_ _null_ _null_ )); DESCR("adjust time precision"); ! DATA(insert OID = 1969 ( timetz PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1266 "1266 23" _null_ _null_ _null_ _null_ timetz_scale _null_ _null_ _null_ )); DESCR("adjust time with time zone precision"); DATA(insert OID = 2003 ( textanycat PGNSP PGUID 14 1 0 0 0 f f f t f v 2 0 25 "25 2776" _null_ _null_ _null_ _null_ "select $1 || $2::pg_catalog.text" _null_ _null_ _null_ )); --- 2724,2736 ---- DATA(insert OID = 1966 ( oidsmaller PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 26 "26 26" _null_ _null_ _null_ _null_ oidsmaller _null_ _null_ _null_ )); DESCR("smaller of two"); ! DATA(insert OID = 1967 ( timestamptz PGNSP PGUID 12 1 0 0 3147 f f f t f i 2 0 1184 "1184 23" _null_ _null_ _null_ _null_ timestamptz_scale _null_ _null_ _null_ )); DESCR("adjust timestamptz precision"); ! DATA(insert OID = 3146 ( time_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ time_transform _null_ _null_ _null_ )); ! DESCR("transform a time length coercion"); ! DATA(insert OID = 1968 ( time PGNSP PGUID 12 1 0 0 3146 f f f t f i 2 0 1083 "1083 23" _null_ _null_ _null_ _null_ time_scale _null_ _null_ _null_ )); DESCR("adjust time precision"); ! DATA(insert OID = 1969 ( timetz PGNSP PGUID 12 1 0 0 3146 f f f t f i 2 0 1266 "1266 23" _null_ _null_ _null_ _null_ timetz_scale _null_ _null_ _null_ )); DESCR("adjust time with time zone precision"); DATA(insert OID = 2003 ( textanycat PGNSP PGUID 14 1 0 0 0 f f f t f v 2 0 25 "25 2776" _null_ _null_ _null_ _null_ "select $1 || $2::pg_catalog.text" _null_ _null_ _null_ )); diff --git a/src/include/pg_config.hindex ef467b7..0411716 100644 *** a/src/include/pg_config.h.in --- b/src/include/pg_config.h.in *************** *** 158,163 **** --- 158,166 ---- /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC + /* Define to 1 if you have the `fls' function. */ + #undef HAVE_FLS + /* Define to 1 if you have the `fpclass' function. */ #undef HAVE_FPCLASS diff --git a/src/include/port.h bindex eceb4bf..edcc41f 100644 *** a/src/include/port.h --- b/src/include/port.h *************** *** 396,401 **** extern double pg_erand48(unsigned short xseed[3]); --- 396,405 ---- extern long pg_lrand48(void); extern void pg_srand48(long seed); + #ifndef HAVE_FLS + extern int fls(int mask); + #endif + #ifndef HAVE_FSEEKO #define fseeko(a, b, c) fseek(a, b, c) #define ftello(a) ftell(a) diff --git a/src/include/index 13e0db4..cc6f381 100644 *** a/src/include/utils/date.h --- b/src/include/utils/date.h *************** *** 154,159 **** extern Datum time_recv(PG_FUNCTION_ARGS); --- 154,160 ---- extern Datum time_send(PG_FUNCTION_ARGS); extern Datum timetypmodin(PG_FUNCTION_ARGS); extern Datum timetypmodout(PG_FUNCTION_ARGS); + extern Datum time_transform(PG_FUNCTION_ARGS); extern Datum time_scale(PG_FUNCTION_ARGS); extern Datum time_eq(PG_FUNCTION_ARGS); extern Datum time_ne(PG_FUNCTION_ARGS); diff --git a/src/include/utils/index cd9edda..a3d90fe 100644 *** a/src/include/utils/datetime.h --- b/src/include/utils/datetime.h *************** *** 16,21 **** --- 16,22 ---- #ifndef DATETIME_H #define DATETIME_H + #include "nodes/nodes.h" #include "utils/timestamp.h" /* this struct is declared in utils/tzparser.h: */ *************** *** 298,303 **** extern int DecodeUnits(int field, char *lowtoken, int *val); --- 299,306 ---- extern int j2day(int jd); + extern Node *TemporalTransform(int32 max_precis, Node *node); + extern bool CheckDateTokenTables(void); extern void ConvertTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl, diff --git a/src/include/utils/timeindex 7661744..4006504 100644 *** a/src/include/utils/timestamp.h --- b/src/include/utils/timestamp.h *************** *** 100,105 **** extern Datum timestamp_recv(PG_FUNCTION_ARGS); --- 100,106 ---- extern Datum timestamp_send(PG_FUNCTION_ARGS); extern Datum timestamptypmodin(PG_FUNCTION_ARGS); extern Datum timestamptypmodout(PG_FUNCTION_ARGS); + extern Datum timestamp_transform(PG_FUNCTION_ARGS); extern Datum timestamp_scale(PG_FUNCTION_ARGS); extern Datum timestamp_eq(PG_FUNCTION_ARGS); extern Datum timestamp_ne(PG_FUNCTION_ARGS); *************** *** 136,141 **** extern Datum interval_recv(PG_FUNCTION_ARGS); --- 137,143 ---- extern Datum interval_send(PG_FUNCTION_ARGS); extern Datum intervaltypmodin(PG_FUNCTION_ARGS); extern Datum intervaltypmodout(PG_FUNCTION_ARGS); + extern Datum interval_transform(PG_FUNCTION_ARGS); extern Datum interval_scale(PG_FUNCTION_ARGS); extern Datum interval_eq(PG_FUNCTION_ARGS); extern Datum interval_ne(PG_FUNCTION_ARGS); diff --git a/src/port/fls.c b/src/ponew file mode 100644 index 0000000..53b2b15 *** /dev/null --- b/src/port/fls.c *************** *** 0 **** --- 1,51 ---- + /* + * src/port/fls.c + * + * $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/lib/libc/string/fls.c,v 1.3 2007/01/09 00:28:12 imp Exp $ + */ + + /*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + #include "c.h" + + /* + * Find Last Set bit + */ + int + fls(int mask) + { + int bit; + + if (mask == 0) + return (0); + for (bit = 1; mask != 1; bit++) + mask = (unsigned int)mask >> 1; + return (bit); + } diff --git a/src/testindex 301cc4b..323db24 100644
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers