aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/timestamp.c123
-rw-r--r--src/test/regress/expected/timestamptz.out19
-rw-r--r--src/test/regress/sql/timestamptz.sql9
3 files changed, 38 insertions, 113 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index a87f9828b00..f2784da3605 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -5202,84 +5202,15 @@ interval_part(PG_FUNCTION_ARGS)
/* timestamp_zone_transform()
- * If the zone argument of a timestamp_zone() or timestamptz_zone() call is a
- * plan-time constant denoting a zone equivalent to UTC, the call will always
- * return its second argument unchanged. Simplify the expression tree
- * accordingly. Civil time zones almost never qualify, because jurisdictions
- * that follow UTC today have not done so continuously.
+ * The original optimization here caused problems by relabeling Vars that
+ * could be matched to index entries. It might be possible to resurrect it
+ * at some point by teaching the planner to be less cavalier with RelabelType
+ * nodes, but that will take careful analysis.
*/
Datum
timestamp_zone_transform(PG_FUNCTION_ARGS)
{
- Node *func_node = (Node *) PG_GETARG_POINTER(0);
- FuncExpr *expr = (FuncExpr *) func_node;
- Node *ret = NULL;
- Node *zone_node;
-
- Assert(IsA(expr, FuncExpr));
- Assert(list_length(expr->args) == 2);
-
- zone_node = (Node *) linitial(expr->args);
-
- if (IsA(zone_node, Const) &&!((Const *) zone_node)->constisnull)
- {
- text *zone = DatumGetTextPP(((Const *) zone_node)->constvalue);
- char tzname[TZ_STRLEN_MAX + 1];
- char *lowzone;
- int type,
- abbrev_offset;
- pg_tz *tzp;
- bool noop = false;
-
- /*
- * If the timezone is forever UTC+0, the FuncExpr function call is a
- * no-op for all possible timestamps. This passage mirrors code in
- * timestamp_zone().
- */
- text_to_cstring_buffer(zone, tzname, sizeof(tzname));
- lowzone = downcase_truncate_identifier(tzname,
- strlen(tzname),
- false);
- type = DecodeTimezoneAbbrev(0, lowzone, &abbrev_offset, &tzp);
- if (type == TZ || type == DTZ)
- noop = (abbrev_offset == 0);
- else if (type == DYNTZ)
- {
- /*
- * An abbreviation of a single-offset timezone ought not to be
- * configured as a DYNTZ, so don't bother checking.
- */
- }
- else
- {
- long tzname_offset;
-
- tzp = pg_tzset(tzname);
- if (tzp && pg_get_timezone_offset(tzp, &tzname_offset))
- noop = (tzname_offset == 0);
- }
-
- if (noop)
- {
- Node *timestamp = (Node *) lsecond(expr->args);
-
- /* Strip any existing RelabelType node(s) */
- while (timestamp && IsA(timestamp, RelabelType))
- timestamp = (Node *) ((RelabelType *) timestamp)->arg;
-
- /*
- * Replace the FuncExpr with its timestamp argument, relabeled as
- * though the function call had computed it.
- */
- ret = (Node *) makeRelabelType((Expr *) timestamp,
- exprType(func_node),
- exprTypmod(func_node),
- exprCollation(func_node),
- COERCE_EXPLICIT_CAST);
- }
- }
-
- PG_RETURN_POINTER(ret);
+ PG_RETURN_POINTER(NULL);
}
/* timestamp_zone()
@@ -5376,49 +5307,15 @@ timestamp_zone(PG_FUNCTION_ARGS)
}
/* timestamp_izone_transform()
- * If we deduce at plan time that a particular timestamp_izone() or
- * timestamptz_izone() call can only compute tz=0, the call will always return
- * its second argument unchanged. Simplify the expression tree accordingly.
+ * The original optimization here caused problems by relabeling Vars that
+ * could be matched to index entries. It might be possible to resurrect it
+ * at some point by teaching the planner to be less cavalier with RelabelType
+ * nodes, but that will take careful analysis.
*/
Datum
timestamp_izone_transform(PG_FUNCTION_ARGS)
{
- Node *func_node = (Node *) PG_GETARG_POINTER(0);
- FuncExpr *expr = (FuncExpr *) func_node;
- Node *ret = NULL;
- Node *zone_node;
-
- Assert(IsA(expr, FuncExpr));
- Assert(list_length(expr->args) == 2);
-
- zone_node = (Node *) linitial(expr->args);
-
- if (IsA(zone_node, Const) &&!((Const *) zone_node)->constisnull)
- {
- Interval *zone;
-
- zone = DatumGetIntervalP(((Const *) zone_node)->constvalue);
- if (zone->month == 0 && zone->day == 0 && zone->time == 0)
- {
- Node *timestamp = (Node *) lsecond(expr->args);
-
- /* Strip any existing RelabelType node(s) */
- while (timestamp && IsA(timestamp, RelabelType))
- timestamp = (Node *) ((RelabelType *) timestamp)->arg;
-
- /*
- * Replace the FuncExpr with its timestamp argument, relabeled as
- * though the function call had computed it.
- */
- ret = (Node *) makeRelabelType((Expr *) timestamp,
- exprType(func_node),
- exprTypmod(func_node),
- exprCollation(func_node),
- COERCE_EXPLICIT_CAST);
- }
- }
-
- PG_RETURN_POINTER(ret);
+ PG_RETURN_POINTER(NULL);
}
/* timestamp_izone()
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index 9fa93a43eaf..51d4d211573 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -2638,3 +2638,22 @@ select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
t
(1 row)
+--
+-- Test that AT TIME ZONE isn't misoptimized when using an index (bug #14504)
+--
+create temp table tmptz (f1 timestamptz primary key);
+insert into tmptz values ('2017-01-18 00:00+00');
+explain (costs off)
+select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00';
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------
+ Seq Scan on tmptz
+ Filter: (timezone('utc'::text, f1) = 'Wed Jan 18 00:00:00 2017'::timestamp without time zone)
+(2 rows)
+
+select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00';
+ f1
+------------------------------
+ Tue Jan 17 16:00:00 2017 PST
+(1 row)
+
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index 5573e0ed779..ab86622a88a 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -484,3 +484,12 @@ set timezone_abbreviations = 'Australia';
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
set timezone_abbreviations = 'India';
select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs;
+
+--
+-- Test that AT TIME ZONE isn't misoptimized when using an index (bug #14504)
+--
+create temp table tmptz (f1 timestamptz primary key);
+insert into tmptz values ('2017-01-18 00:00+00');
+explain (costs off)
+select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00';
+select * from tmptz where f1 at time zone 'utc' = '2017-01-18 00:00';