Fix precision handling for some COERCE_SQL_SYNTAX functions
authorMichael Paquier <[email protected]>
Fri, 30 Dec 2022 11:47:57 +0000 (20:47 +0900)
committerMichael Paquier <[email protected]>
Fri, 30 Dec 2022 11:47:57 +0000 (20:47 +0900)
f193883 has been incorrectly setting up the precision used in the
timestamp compilations returned by the following functions:
- LOCALTIME
- LOCALTIMESTAMP
- CURRENT_TIME
- CURRENT_TIMESTAMP

Specifying an out-of-range precision for CURRENT_TIMESTAMP and
LOCALTIMESTAMP was raising a WARNING without adjusting the precision,
leading to a subsequent error.  LOCALTIME and CURRENT_TIME raised a
WARNING without an error, still the precision given to the internal
routines was not correct, so let's be clean.

Ian has reported the problems in timestamp.c, while I have noticed the
ones in date.c.  Regression tests are added for all of them with
precisions high enough to provide coverage for the warnings, something
that went missing up to this commit.

Author: Ian Lawrence Barwick, Michael Paquier
Discussion: https://postgr.es/m/CAB8KJ=jQEnn9sYG+N752spt68wMrhmT-ocHCh4oeNmHF82QMWA@mail.gmail.com

src/backend/utils/adt/date.c
src/backend/utils/adt/timestamp.c
src/test/regress/expected/expressions.out
src/test/regress/sql/expressions.sql

index 1cf7c7652d7d31054f015e0b764ddf0a48827ecf..e70cf4bdcff46afd357d10708eff23aabd8a9c1f 100644 (file)
@@ -347,10 +347,7 @@ current_time(PG_FUNCTION_ARGS)
        int32           typmod = -1;
 
        if (!PG_ARGISNULL(0))
-       {
-               typmod = PG_GETARG_INT32(0);
-               anytime_typmod_check(true, typmod);
-       }
+               typmod = anytime_typmod_check(true, PG_GETARG_INT32(0));
 
        GetCurrentTimeUsec(tm, &fsec, &tz);
 
@@ -375,10 +372,7 @@ sql_localtime(PG_FUNCTION_ARGS)
        int32           typmod = -1;
 
        if (!PG_ARGISNULL(0))
-       {
-               typmod = PG_GETARG_INT32(0);
-               anytime_typmod_check(false, typmod);
-       }
+               typmod = anytime_typmod_check(false, PG_GETARG_INT32(0));
 
        GetCurrentTimeUsec(tm, &fsec, &tz);
 
index 3f2508c0c4a2c92aab667147d4ad7554dbb57258..b23cce113621d0f8bd58604f7d33346b3af02dfe 100644 (file)
@@ -1606,10 +1606,7 @@ current_timestamp(PG_FUNCTION_ARGS)
        int32           typmod = -1;
 
        if (!PG_ARGISNULL(0))
-       {
-               typmod = PG_GETARG_INT32(0);
-               anytimestamp_typmod_check(true, typmod);
-       }
+               typmod = anytimestamp_typmod_check(true, PG_GETARG_INT32(0));
 
        ts = GetCurrentTransactionStartTimestamp();
        if (typmod >= 0)
@@ -1627,10 +1624,7 @@ sql_localtimestamp(PG_FUNCTION_ARGS)
        int32           typmod = -1;
 
        if (!PG_ARGISNULL(0))
-       {
-               typmod = PG_GETARG_INT32(0);
-               anytimestamp_typmod_check(false, typmod);
-       }
+               typmod = anytimestamp_typmod_check(false, PG_GETARG_INT32(0));
 
        ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
        if (typmod >= 0)
index 28a20900f194c637d18fff380b0fb5b126ddc066..df432d4c92713ac39c74d630f03163288d89f3f4 100644 (file)
@@ -36,7 +36,7 @@ SELECT now()::time(3)::text = localtime(3)::text;
  t
 (1 row)
 
--- current_timestamp / localtimestamp (always matches because of transactional behaviour)
+-- current_time[stamp]/ localtime[stamp] (always matches because of transactional behaviour)
 SELECT current_timestamp = NOW();
  ?column? 
 ----------
@@ -57,6 +57,35 @@ SELECT now()::timestamp::text = localtimestamp::text;
  t
 (1 row)
 
+-- precision overflow
+SELECT current_time = current_time(7);
+WARNING:  TIME(7) WITH TIME ZONE precision reduced to maximum allowed, 6
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT current_timestamp = current_timestamp(7);
+WARNING:  TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT localtime = localtime(7);
+WARNING:  TIME(7) precision reduced to maximum allowed, 6
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT localtimestamp = localtimestamp(7);
+WARNING:  TIMESTAMP(7) precision reduced to maximum allowed, 6
+ ?column? 
+----------
+ t
+(1 row)
+
 -- current_role/user/user is tested in rolnames.sql
 -- current database / catalog
 SELECT current_catalog = current_database();
index f9a0299d17bccfd5872c6824a54fc58046620000..fea5358d2526ae2aa44b374365320d5ec5ce5d06 100644 (file)
@@ -17,12 +17,17 @@ SELECT now()::timetz(4)::text = current_time(4)::text;
 SELECT now()::time::text = localtime::text;
 SELECT now()::time(3)::text = localtime(3)::text;
 
--- current_timestamp / localtimestamp (always matches because of transactional behaviour)
+-- current_time[stamp]/ localtime[stamp] (always matches because of transactional behaviour)
 SELECT current_timestamp = NOW();
 -- precision
 SELECT length(current_timestamp::text) >= length(current_timestamp(0)::text);
 -- localtimestamp
 SELECT now()::timestamp::text = localtimestamp::text;
+-- precision overflow
+SELECT current_time = current_time(7);
+SELECT current_timestamp = current_timestamp(7);
+SELECT localtime = localtime(7);
+SELECT localtimestamp = localtimestamp(7);
 
 -- current_role/user/user is tested in rolnames.sql