Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 16acbed

Browse files
tglsfdcCommitfest Bot
authored and
Commitfest Bot
committed
Break out xxx2yyy_opt_overflow APIs for more datetime conversions.
Previous commits invented timestamp2timestamptz_opt_overflow, date2timestamp_opt_overflow, and date2timestamptz_opt_overflow functions to perform non-error-throwing conversions between datetime types. This patch completes the set by adding timestamp2date_opt_overflow, timestamptz2date_opt_overflow, and timestamptz2timestamp_opt_overflow. In addition, adjust timestamp2timestamptz_opt_overflow so that it doesn't throw error if timestamp2tm fails, but treats that as an overflow case. The situation probably can't arise except with an invalid timestamp value, and I can't think of a way that that would happen except data corruption. However, it's pretty silly to have a function whose entire reason for existence is to not throw errors for out-of-range inputs nonetheless throw an error for out-of-range input. The new APIs are not used in this patch, but will be needed by btree_gin. Discussion: https://postgr.es/m/262624.1738460652@sss.pgh.pa.us
1 parent 44ce4e1 commit 16acbed

File tree

4 files changed

+156
-16
lines changed

4 files changed

+156
-16
lines changed

src/backend/utils/adt/date.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,25 +1363,66 @@ timestamp_date(PG_FUNCTION_ARGS)
13631363
{
13641364
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
13651365
DateADT result;
1366+
1367+
result = timestamp2date_opt_overflow(timestamp, NULL);
1368+
PG_RETURN_DATEADT(result);
1369+
}
1370+
1371+
/*
1372+
* Convert timestamp to date.
1373+
*
1374+
* On successful conversion, *overflow is set to zero if it's not NULL.
1375+
*
1376+
* If the timestamp is finite but out of the valid range for date, then:
1377+
* if overflow is NULL, we throw an out-of-range error.
1378+
* if overflow is not NULL, we store +1 or -1 there to indicate the sign
1379+
* of the overflow, and return the appropriate date infinity.
1380+
*
1381+
* Note: given the ranges of the types, overflow is only possible at
1382+
* the minimum end of the range, but we don't assume that in this code.
1383+
*/
1384+
DateADT
1385+
timestamp2date_opt_overflow(Timestamp timestamp, int *overflow)
1386+
{
1387+
DateADT result;
13661388
struct pg_tm tt,
13671389
*tm = &tt;
13681390
fsec_t fsec;
13691391

1392+
if (overflow)
1393+
*overflow = 0;
1394+
13701395
if (TIMESTAMP_IS_NOBEGIN(timestamp))
13711396
DATE_NOBEGIN(result);
13721397
else if (TIMESTAMP_IS_NOEND(timestamp))
13731398
DATE_NOEND(result);
13741399
else
13751400
{
13761401
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1402+
{
1403+
if (overflow)
1404+
{
1405+
if (timestamp < 0)
1406+
{
1407+
*overflow = -1;
1408+
DATE_NOBEGIN(result);
1409+
}
1410+
else
1411+
{
1412+
*overflow = 1; /* not actually reachable */
1413+
DATE_NOEND(result);
1414+
}
1415+
return result;
1416+
}
13771417
ereport(ERROR,
13781418
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
13791419
errmsg("timestamp out of range")));
1420+
}
13801421

13811422
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
13821423
}
13831424

1384-
PG_RETURN_DATEADT(result);
1425+
return result;
13851426
}
13861427

13871428

@@ -1408,26 +1449,67 @@ timestamptz_date(PG_FUNCTION_ARGS)
14081449
{
14091450
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
14101451
DateADT result;
1452+
1453+
result = timestamptz2date_opt_overflow(timestamp, NULL);
1454+
PG_RETURN_DATEADT(result);
1455+
}
1456+
1457+
/*
1458+
* Convert timestamptz to date.
1459+
*
1460+
* On successful conversion, *overflow is set to zero if it's not NULL.
1461+
*
1462+
* If the timestamptz is finite but out of the valid range for date, then:
1463+
* if overflow is NULL, we throw an out-of-range error.
1464+
* if overflow is not NULL, we store +1 or -1 there to indicate the sign
1465+
* of the overflow, and return the appropriate date infinity.
1466+
*
1467+
* Note: given the ranges of the types, overflow is only possible at
1468+
* the minimum end of the range, but we don't assume that in this code.
1469+
*/
1470+
DateADT
1471+
timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow)
1472+
{
1473+
DateADT result;
14111474
struct pg_tm tt,
14121475
*tm = &tt;
14131476
fsec_t fsec;
14141477
int tz;
14151478

1479+
if (overflow)
1480+
*overflow = 0;
1481+
14161482
if (TIMESTAMP_IS_NOBEGIN(timestamp))
14171483
DATE_NOBEGIN(result);
14181484
else if (TIMESTAMP_IS_NOEND(timestamp))
14191485
DATE_NOEND(result);
14201486
else
14211487
{
14221488
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1489+
{
1490+
if (overflow)
1491+
{
1492+
if (timestamp < 0)
1493+
{
1494+
*overflow = -1;
1495+
DATE_NOBEGIN(result);
1496+
}
1497+
else
1498+
{
1499+
*overflow = 1; /* not actually reachable */
1500+
DATE_NOEND(result);
1501+
}
1502+
return result;
1503+
}
14231504
ereport(ERROR,
14241505
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
14251506
errmsg("timestamp out of range")));
1507+
}
14261508

14271509
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
14281510
}
14291511

1430-
PG_RETURN_DATEADT(result);
1512+
return result;
14311513
}
14321514

14331515

src/backend/utils/adt/timestamp.c

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6477,31 +6477,30 @@ timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
64776477
if (TIMESTAMP_NOT_FINITE(timestamp))
64786478
return timestamp;
64796479

6480-
/* We don't expect this to fail, but check it pro forma */
6480+
/* timestamp2tm should not fail on valid timestamps, but cope */
64816481
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
64826482
{
64836483
tz = DetermineTimeZoneOffset(tm, session_timezone);
64846484

64856485
result = dt2local(timestamp, -tz);
64866486

64876487
if (IS_VALID_TIMESTAMP(result))
6488-
{
64896488
return result;
6489+
}
6490+
6491+
if (overflow)
6492+
{
6493+
if (timestamp < 0)
6494+
{
6495+
*overflow = -1;
6496+
TIMESTAMP_NOBEGIN(result);
64906497
}
6491-
else if (overflow)
6498+
else
64926499
{
6493-
if (result < MIN_TIMESTAMP)
6494-
{
6495-
*overflow = -1;
6496-
TIMESTAMP_NOBEGIN(result);
6497-
}
6498-
else
6499-
{
6500-
*overflow = 1;
6501-
TIMESTAMP_NOEND(result);
6502-
}
6503-
return result;
6500+
*overflow = 1;
6501+
TIMESTAMP_NOEND(result);
65046502
}
6503+
return result;
65056504
}
65066505

65076506
ereport(ERROR,
@@ -6531,27 +6530,81 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
65316530
PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
65326531
}
65336532

6533+
/*
6534+
* Convert timestamptz to timestamp, throwing error for overflow.
6535+
*/
65346536
static Timestamp
65356537
timestamptz2timestamp(TimestampTz timestamp)
6538+
{
6539+
return timestamptz2timestamp_opt_overflow(timestamp, NULL);
6540+
}
6541+
6542+
/*
6543+
* Convert timestamp with time zone to timestamp.
6544+
*
6545+
* On successful conversion, *overflow is set to zero if it's not NULL.
6546+
*
6547+
* If the timestamptz is finite but out of the valid range for timestamp, then:
6548+
* if overflow is NULL, we throw an out-of-range error.
6549+
* if overflow is not NULL, we store +1 or -1 there to indicate the sign
6550+
* of the overflow, and return the appropriate timestamp infinity.
6551+
*/
6552+
Timestamp
6553+
timestamptz2timestamp_opt_overflow(TimestampTz timestamp, int *overflow)
65366554
{
65376555
Timestamp result;
65386556
struct pg_tm tt,
65396557
*tm = &tt;
65406558
fsec_t fsec;
65416559
int tz;
65426560

6561+
if (overflow)
6562+
*overflow = 0;
6563+
65436564
if (TIMESTAMP_NOT_FINITE(timestamp))
65446565
result = timestamp;
65456566
else
65466567
{
65476568
if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
6569+
{
6570+
if (overflow)
6571+
{
6572+
if (timestamp < 0)
6573+
{
6574+
*overflow = -1;
6575+
TIMESTAMP_NOBEGIN(result);
6576+
}
6577+
else
6578+
{
6579+
*overflow = 1;
6580+
TIMESTAMP_NOEND(result);
6581+
}
6582+
return result;
6583+
}
65486584
ereport(ERROR,
65496585
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
65506586
errmsg("timestamp out of range")));
6587+
}
65516588
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
6589+
{
6590+
if (overflow)
6591+
{
6592+
if (timestamp < 0)
6593+
{
6594+
*overflow = -1;
6595+
TIMESTAMP_NOBEGIN(result);
6596+
}
6597+
else
6598+
{
6599+
*overflow = 1;
6600+
TIMESTAMP_NOEND(result);
6601+
}
6602+
return result;
6603+
}
65526604
ereport(ERROR,
65536605
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
65546606
errmsg("timestamp out of range")));
6607+
}
65556608
}
65566609
return result;
65576610
}

src/include/utils/date.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ extern int32 anytime_typmod_check(bool istz, int32 typmod);
100100
extern double date2timestamp_no_overflow(DateADT dateVal);
101101
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
102102
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
103+
extern DateADT timestamp2date_opt_overflow(Timestamp timestamp, int *overflow);
104+
extern DateADT timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow);
103105
extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
104106
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
105107

src/include/utils/timestamp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2);
144144

145145
extern TimestampTz timestamp2timestamptz_opt_overflow(Timestamp timestamp,
146146
int *overflow);
147+
extern Timestamp timestamptz2timestamp_opt_overflow(TimestampTz timestamp,
148+
int *overflow);
149+
147150
extern int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal,
148151
TimestampTz dt2);
149152

0 commit comments

Comments
 (0)