aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/date.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-09-28 12:05:03 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-09-28 12:05:03 -0400
commit0a87ddff5c83589e90de236bd55e6a19b017fe9a (patch)
tree6c35e1a6d9fcd89e7ede77e30b9f184f30dbaab3 /src/backend/utils/adt/date.c
parente21cbb4b893b85b5f1cf203b9a77ca0d9ee671d1 (diff)
downloadpostgresql-0a87ddff5c83589e90de236bd55e6a19b017fe9a.tar.gz
postgresql-0a87ddff5c83589e90de236bd55e6a19b017fe9a.zip
Cache the result of converting now() to a struct pg_tm.
SQL operations such as CURRENT_DATE, CURRENT_TIME, LOCALTIME, and conversion of "now" in a datetime input string have to obtain the transaction start timestamp ("now()") as a broken-down struct pg_tm. This is a remarkably expensive conversion, and since now() does not change intra-transaction, it doesn't really need to be done more than once per transaction. Introducing a simple cache provides visible speedups in queries that compute these values many times, for example insertion of many rows that use a default value of CURRENT_DATE. Peter Smith, with a bit of kibitzing by me Discussion: https://postgr.es/m/CAHut+Pu89TWjq530V2gY5O6SWi=OEJMQ_VHMt8bdZB_9JFna5A@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/date.c')
-rw-r--r--src/backend/utils/adt/date.c49
1 files changed, 24 insertions, 25 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index eaaffa7137d..057051fa855 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -299,20 +299,31 @@ EncodeSpecialDate(DateADT dt, char *str)
DateADT
GetSQLCurrentDate(void)
{
- TimestampTz ts;
- struct pg_tm tt,
- *tm = &tt;
- fsec_t fsec;
- int tz;
+ struct pg_tm tm;
- ts = GetCurrentTransactionStartTimestamp();
+ static int cache_year = 0;
+ static int cache_mon = 0;
+ static int cache_mday = 0;
+ static DateADT cache_date;
- if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("timestamp out of range")));
+ GetCurrentDateTime(&tm);
- return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+ /*
+ * date2j involves several integer divisions; moreover, unless our session
+ * lives across local midnight, we don't really have to do it more than
+ * once. So it seems worth having a separate cache here.
+ */
+ if (tm.tm_year != cache_year ||
+ tm.tm_mon != cache_mon ||
+ tm.tm_mday != cache_mday)
+ {
+ cache_date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
+ cache_year = tm.tm_year;
+ cache_mon = tm.tm_mon;
+ cache_mday = tm.tm_mday;
+ }
+
+ return cache_date;
}
/*
@@ -322,18 +333,12 @@ TimeTzADT *
GetSQLCurrentTime(int32 typmod)
{
TimeTzADT *result;
- TimestampTz ts;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
- ts = GetCurrentTransactionStartTimestamp();
-
- if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("timestamp out of range")));
+ GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
@@ -348,18 +353,12 @@ TimeADT
GetSQLLocalTime(int32 typmod)
{
TimeADT result;
- TimestampTz ts;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
- ts = GetCurrentTransactionStartTimestamp();
-
- if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
- errmsg("timestamp out of range")));
+ GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);