mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-09-06 21:48:58 +00:00
* fix(query): keep INSERT timestamp conversion out of the source query Interpreting an INSERT's string timestamps used to work by pushing the conversion down into the source query, which changed what that query means. Two consequences: - Pushing through a UNION's DISTINCT moved the dedup key from the raw strings to parsed instants, so rows spelling the same instant differently collapsed into one. On an append-only table that is a silently dropped row. - A UNION branch that needed no conversion (a NULL, or an explicit cast) made the whole column give up, leaving sibling branches on UTC while the rest of the row used the session timezone. Convert at the assignment instead, by routing its cast through a timezone-carrying timestamp type and back. Arrow applies the timezone when a cast target carries one, and stripping it afterwards preserves the value. The source query is no longer touched, so both cases go away and the tree-walking rewrite (roughly 160 lines) is deleted. The rewrite reads source types, so it now runs TypeCoercion first: a UNION still carries its loose per-branch schema before coercion, and retargeting a cast whose input later becomes a timestamp would shift the value rather than reinterpret it. Signed-off-by: Dennis Zhuang <killme2008@gmail.com> * fix(query): address review on INSERT assignment rewrite - Clone the input `Arc` instead of the whole subtree, and only rebuild it when a `Values` row actually changes. - Defer cloning the cast source until the literal-folding path has been ruled out. - Move the UTC check onto `Timezone::is_utc`, replacing a bare string compare. - Cover a prepared `INSERT ... VALUES (?)`: an untyped placeholder types as `Null`, so the assignment cast is left for parameter substitution. Signed-off-by: Dennis Zhuang <killme2008@gmail.com> --------- Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
96 lines
2.8 KiB
SQL
96 lines
2.8 KiB
SQL
--- insert timestamp with default values aware of session timezone test ---
|
|
|
|
CREATE TABLE test1 (i INTEGER, j TIMESTAMP default '2024-01-30 00:01:01' TIME INDEX, PRIMARY KEY(i));
|
|
|
|
INSERT INTO test1 VALUES (1, DEFAULT), (2, DEFAULT), (3, '2024-01-31 00:01:01'), (4, '2025-02-01 00:01:01');
|
|
|
|
SELECT * FROM test1 ORDER BY j;
|
|
|
|
SET time_zone = 'Asia/Shanghai';
|
|
|
|
CREATE TABLE test2 (i INTEGER, j TIMESTAMP default '2024-01-30 00:01:01' TIME INDEX, PRIMARY KEY(i));
|
|
|
|
INSERT INTO test2 VALUES (1, DEFAULT), (2, DEFAULT), (3, '2024-01-31 00:01:01'), (4, '2025-02-01 00:01:01');
|
|
|
|
SELECT * FROM test2 ORDER BY j;
|
|
|
|
SELECT * FROM test1 ORDER BY j;
|
|
|
|
CREATE TABLE test3 (ts TIMESTAMP TIME INDEX, st TIMESTAMP, ts_ns TIMESTAMP(9));
|
|
|
|
INSERT INTO test3 (ts) VALUES ('2026-08-01 12:00:00.001');
|
|
|
|
INSERT INTO test3 (ts, st) VALUES ('2026-08-02 12:00:00.001', now());
|
|
|
|
INSERT INTO test3 (ts, st) SELECT '2026-08-03 12:00:00.001', now();
|
|
|
|
INSERT INTO test3 (ts, st) SELECT '2026-08-04 12:00:00.001', now() LIMIT 1;
|
|
|
|
INSERT INTO test3 (ts, st)
|
|
SELECT '2026-08-06 12:00:00.001', now()
|
|
UNION ALL
|
|
SELECT '2026-08-07 12:00:00.001', now();
|
|
|
|
INSERT INTO test3 (ts, st) VALUES (
|
|
CAST('2026-08-08 12:00:00.001' AS TIMESTAMP),
|
|
now()
|
|
);
|
|
|
|
INSERT INTO test3 (ts, st)
|
|
SELECT '2026-08-10 12:00:00.001', now()
|
|
UNION ALL
|
|
SELECT CAST('2026-08-11 12:00:00.001' AS TIMESTAMP), now();
|
|
|
|
INSERT INTO test3 (ts, st)
|
|
SELECT '2026-08-16 12:00:00.001', now()
|
|
UNION
|
|
SELECT '2026-08-17 12:00:00.001', now();
|
|
|
|
INSERT INTO test3 (ts, ts_ns) SELECT a, b FROM (
|
|
SELECT c AS a, c AS b FROM (SELECT '2026-08-12 12:00:00.123456789' AS c) AS t1
|
|
) AS t2;
|
|
|
|
INSERT INTO test3 (ts, st, ts_ns) VALUES (
|
|
'2026-08-09 12:00:00.001',
|
|
now(),
|
|
'2026-08-09 12:00:00.123456789'
|
|
);
|
|
|
|
-- a NULL branch must not cancel the conversion for the whole column
|
|
INSERT INTO test3 (ts, ts_ns)
|
|
SELECT '2026-08-13 12:00:00.001' AS a, '2026-08-13 12:00:00.123456789' AS b
|
|
UNION ALL
|
|
SELECT '2026-08-14 12:00:00.001', NULL;
|
|
|
|
-- NULL in the first branch: the union's schema starts out as Null
|
|
INSERT INTO test3 (ts, ts_ns)
|
|
SELECT '2026-08-15 12:00:00.001' AS a, NULL AS b
|
|
UNION ALL
|
|
SELECT '2026-08-19 12:00:00.001', '2026-08-19 12:00:00.123456789';
|
|
|
|
-- the assignment cast also lands on non-literal VALUES expressions
|
|
INSERT INTO test3 (ts, st) VALUES (concat('2026-08-20 ', '12:00:00.001'), now());
|
|
|
|
SELECT ts, ts_ns FROM test3 ORDER BY ts;
|
|
|
|
-- UNION dedup keys must stay on the source strings: these two spell the same
|
|
-- instant differently, so the source query yields two rows and both are kept.
|
|
CREATE TABLE test4 (ts TIMESTAMP TIME INDEX) WITH ('append_mode'='true');
|
|
|
|
INSERT INTO test4 (ts)
|
|
SELECT '2026-08-06 04:00:00' UNION SELECT '2026-08-06 04:00:00.000';
|
|
|
|
SELECT count(*) FROM test4;
|
|
|
|
SELECT ts FROM test4 ORDER BY ts;
|
|
|
|
SET time_zone = 'UTC';
|
|
|
|
DROP TABLE test1;
|
|
|
|
DROP TABLE test2;
|
|
|
|
DROP TABLE test3;
|
|
|
|
DROP TABLE test4;
|