summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c32
-rw-r--r--src/backend/utils/adt/timestamp.c17
-rw-r--r--src/include/utils/timestamp.h2
-rw-r--r--src/test/regress/expected/event_trigger.out11
-rw-r--r--src/test/regress/sql/event_trigger.sql10
5 files changed, 65 insertions, 7 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 93f13a4778..59341e2a40 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -96,6 +96,7 @@
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
+#include "utils/timestamp.h"
#include "utils/typcache.h"
@@ -9678,11 +9679,15 @@ ATPrepAlterColumnType(List **wqueue,
* When the data type of a column is changed, a rewrite might not be required
* if the new type is sufficiently identical to the old one, and the USING
* clause isn't trying to insert some other value. It's safe to skip the
- * rewrite if the old type is binary coercible to the new type, or if the
- * new type is an unconstrained domain over the old type. In the case of a
- * constrained domain, we could get by with scanning the table and checking
- * the constraint rather than actually rewriting it, but we don't currently
- * try to do that.
+ * rewrite in these cases:
+ *
+ * - the old type is binary coercible to the new type
+ * - the new type is an unconstrained domain over the old type
+ * - {NEW,OLD} or {OLD,NEW} is {timestamptz,timestamp} and the timezone is UTC
+ *
+ * In the case of a constrained domain, we could get by with scanning the
+ * table and checking the constraint rather than actually rewriting it, but we
+ * don't currently try to do that.
*/
static bool
ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
@@ -9704,6 +9709,23 @@ ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno)
return true;
expr = (Node *) d->arg;
}
+ else if (IsA(expr, FuncExpr))
+ {
+ FuncExpr *f = (FuncExpr *) expr;
+
+ switch (f->funcid)
+ {
+ case F_TIMESTAMPTZ_TIMESTAMP:
+ case F_TIMESTAMP_TIMESTAMPTZ:
+ if (TimestampTimestampTzRequiresRewrite())
+ return true;
+ else
+ expr = linitial(f->args);
+ break;
+ default:
+ return true;
+ }
+ }
else
return true;
}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index e0ef2f7861..1b0effa924 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -5168,6 +5168,23 @@ timestamp_izone(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMPTZ(result);
} /* timestamp_izone() */
+/* TimestampTimestampTzRequiresRewrite()
+ *
+ * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
+ * timestamptz_timestamp to be no-ops, where the return value has the same
+ * bits as the argument. Since project convention is to assume a GUC changes
+ * no more often than STABLE functions change, the answer is valid that long.
+ */
+bool
+TimestampTimestampTzRequiresRewrite(void)
+{
+ long offset;
+
+ if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
+ PG_RETURN_BOOL(false);
+ PG_RETURN_BOOL(true);
+}
+
/* timestamp_timestamptz()
* Convert local timestamp to timestamp at GMT
*/
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index aeb89dc0ce..cb6bb4b242 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -104,4 +104,6 @@ extern int date2isoweek(int year, int mon, int mday);
extern int date2isoyear(int year, int mon, int mday);
extern int date2isoyearday(int year, int mon, int mday);
+extern bool TimestampTimestampTzRequiresRewrite(void);
+
#endif /* TIMESTAMP_H */
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 0e32d5c427..d0c9f9a67f 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -435,7 +435,7 @@ END;
$$;
create event trigger no_rewrite_allowed on table_rewrite
execute procedure test_evtrig_no_rewrite();
-create table rewriteme (id serial primary key, foo float);
+create table rewriteme (id serial primary key, foo float, bar timestamptz);
insert into rewriteme
select x * 1.001 from generate_series(1, 500) as t(x);
alter table rewriteme alter column foo type numeric;
@@ -458,6 +458,15 @@ alter table rewriteme
NOTICE: Table 'rewriteme' is being rewritten (reason = 4)
-- shouldn't trigger a table_rewrite event
alter table rewriteme alter column foo type numeric(12,4);
+begin;
+set timezone to 'UTC';
+alter table rewriteme alter column bar type timestamp;
+set timezone to '0';
+alter table rewriteme alter column bar type timestamptz;
+set timezone to 'Europe/London';
+alter table rewriteme alter column bar type timestamp; -- does rewrite
+NOTICE: Table 'rewriteme' is being rewritten (reason = 4)
+rollback;
-- typed tables are rewritten when their type changes. Don't emit table
-- name, because firing order is not stable.
CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index f022cfaed0..346168673d 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -329,7 +329,7 @@ $$;
create event trigger no_rewrite_allowed on table_rewrite
execute procedure test_evtrig_no_rewrite();
-create table rewriteme (id serial primary key, foo float);
+create table rewriteme (id serial primary key, foo float, bar timestamptz);
insert into rewriteme
select x * 1.001 from generate_series(1, 500) as t(x);
alter table rewriteme alter column foo type numeric;
@@ -352,6 +352,14 @@ alter table rewriteme
-- shouldn't trigger a table_rewrite event
alter table rewriteme alter column foo type numeric(12,4);
+begin;
+set timezone to 'UTC';
+alter table rewriteme alter column bar type timestamp;
+set timezone to '0';
+alter table rewriteme alter column bar type timestamptz;
+set timezone to 'Europe/London';
+alter table rewriteme alter column bar type timestamp; -- does rewrite
+rollback;
-- typed tables are rewritten when their type changes. Don't emit table
-- name, because firing order is not stable.