mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
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
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user