Skip to content

Commit b6cc285

Browse files
authored
feat(sql): support expressions in AT (SNAPSHOT => ...) (#19762)
feat(sql): support expressions and scalar queries in AT (SNAPSHOT => ...) clause Previously, the AT (SNAPSHOT => ...) time travel clause only accepted string literals. This change allows arbitrary scalar expressions including subqueries, consistent with how TIMESTAMP and OFFSET already work. Closes #19761
1 parent 6612ad0 commit b6cc285

9 files changed

Lines changed: 349 additions & 49 deletions

File tree

src/query/ast/src/ast/query.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ impl Display for Indirection {
566566
/// Time Travel specification
567567
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
568568
pub enum TimeTravelPoint {
569-
Snapshot(String),
569+
Snapshot(Box<Expr>),
570570
Timestamp(Box<Expr>),
571571
Offset(Box<Expr>),
572572
Stream {
@@ -580,8 +580,8 @@ pub enum TimeTravelPoint {
580580
impl Display for TimeTravelPoint {
581581
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
582582
match self {
583-
TimeTravelPoint::Snapshot(sid) => {
584-
write!(f, "(SNAPSHOT => '{sid}')")?;
583+
TimeTravelPoint::Snapshot(expr) => {
584+
write!(f, "(SNAPSHOT => {expr})")?;
585585
}
586586
TimeTravelPoint::Timestamp(ts) => {
587587
write!(f, "(TIMESTAMP => {ts})")?;

src/query/ast/src/parser/query.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,8 @@ pub fn travel_point(i: Input) -> IResult<TimeTravelPoint> {
573573

574574
pub fn at_snapshot_or_ts(i: Input) -> IResult<TimeTravelPoint> {
575575
let at_snapshot = map(
576-
rule! { "(" ~ SNAPSHOT ~ "=>" ~ #literal_string ~ ")" },
577-
|(_, _, _, s, _)| TimeTravelPoint::Snapshot(s),
576+
rule! { "(" ~ SNAPSHOT ~ "=>" ~ #expr ~ ")" },
577+
|(_, _, _, e, _)| TimeTravelPoint::Snapshot(Box::new(e)),
578578
);
579579
let at_timestamp = map(
580580
rule! { "(" ~ TIMESTAMP ~ "=>" ~ #expr ~ ")" },

src/query/ast/src/visit/table_reference.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,9 @@ impl Walk for TimeTravelPoint {
261261
visitor: &mut V,
262262
) -> Result<VisitControl<V::Break>, V::Error> {
263263
match self {
264-
TimeTravelPoint::Snapshot(_) => {}
265-
TimeTravelPoint::Timestamp(expr) | TimeTravelPoint::Offset(expr) => {
264+
TimeTravelPoint::Snapshot(expr)
265+
| TimeTravelPoint::Timestamp(expr)
266+
| TimeTravelPoint::Offset(expr) => {
266267
try_walk!(expr.walk(visitor));
267268
}
268269
TimeTravelPoint::Stream {
@@ -293,8 +294,9 @@ impl WalkMut for TimeTravelPoint {
293294
visitor: &mut V,
294295
) -> Result<VisitControl<V::Break>, V::Error> {
295296
match self {
296-
TimeTravelPoint::Snapshot(_) => {}
297-
TimeTravelPoint::Timestamp(expr) | TimeTravelPoint::Offset(expr) => {
297+
TimeTravelPoint::Snapshot(expr)
298+
| TimeTravelPoint::Timestamp(expr)
299+
| TimeTravelPoint::Offset(expr) => {
298300
try_walk!(expr.walk_mut(visitor));
299301
}
300302
TimeTravelPoint::Stream {

src/query/ast/tests/it/parser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,7 @@ fn test_query() {
14061406
r#"select * from customer with consume as s"#,
14071407
r#"select * from t12_0004 at (TIMESTAMP => 'xxxx') as t"#,
14081408
r#"select count(t.c) from t12_0004 at (snapshot => 'xxxx') as t"#,
1409+
r#"select * from t at (snapshot => (select snapshot_id from fuse_snapshot('db', 't') limit 1))"#,
14091410
r#"select * from customer inner join orders"#,
14101411
r#"select * from customer cross join orders"#,
14111412
r#"select * from customer inner join orders on (a = b)"#,

src/query/ast/tests/it/testdata/query.txt

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,190 @@ Query {
10701070
temporal: Some(
10711071
TimeTravel(
10721072
Snapshot(
1073-
"xxxx",
1073+
Literal {
1074+
span: Some(
1075+
48..54,
1076+
),
1077+
value: String(
1078+
"xxxx",
1079+
),
1080+
},
1081+
),
1082+
),
1083+
),
1084+
with_options: None,
1085+
pivot: None,
1086+
unpivot: None,
1087+
sample: None,
1088+
},
1089+
],
1090+
selection: None,
1091+
group_by: None,
1092+
having: None,
1093+
window_list: None,
1094+
qualify: None,
1095+
},
1096+
),
1097+
order_by: [],
1098+
limit: [],
1099+
offset: None,
1100+
ignore_result: false,
1101+
}
1102+
1103+
1104+
---------- Input ----------
1105+
select * from t at (snapshot => (select snapshot_id from fuse_snapshot('db', 't') limit 1))
1106+
---------- Output ---------
1107+
SELECT * FROM t AT (SNAPSHOT => (SELECT snapshot_id FROM fuse_snapshot('db', 't') LIMIT 1))
1108+
---------- AST ------------
1109+
Query {
1110+
span: Some(
1111+
0..91,
1112+
),
1113+
with: None,
1114+
body: Select(
1115+
SelectStmt {
1116+
span: Some(
1117+
0..91,
1118+
),
1119+
hints: None,
1120+
distinct: false,
1121+
top_n: None,
1122+
select_list: [
1123+
StarColumns {
1124+
qualified: [
1125+
Star(
1126+
Some(
1127+
7..8,
1128+
),
1129+
),
1130+
],
1131+
column_filter: None,
1132+
},
1133+
],
1134+
from: [
1135+
Table {
1136+
span: Some(
1137+
14..91,
1138+
),
1139+
table: TableRef {
1140+
catalog: None,
1141+
database: None,
1142+
table: Identifier {
1143+
span: Some(
1144+
14..15,
1145+
),
1146+
name: "t",
1147+
quote: None,
1148+
ident_type: None,
1149+
},
1150+
branch: None,
1151+
},
1152+
alias: None,
1153+
temporal: Some(
1154+
TimeTravel(
1155+
Snapshot(
1156+
Subquery {
1157+
span: Some(
1158+
32..90,
1159+
),
1160+
modifier: None,
1161+
subquery: Query {
1162+
span: Some(
1163+
33..81,
1164+
),
1165+
with: None,
1166+
body: Select(
1167+
SelectStmt {
1168+
span: Some(
1169+
33..81,
1170+
),
1171+
hints: None,
1172+
distinct: false,
1173+
top_n: None,
1174+
select_list: [
1175+
AliasedExpr {
1176+
expr: ColumnRef {
1177+
span: Some(
1178+
40..51,
1179+
),
1180+
column: ColumnRef {
1181+
database: None,
1182+
table: None,
1183+
column: Name(
1184+
Identifier {
1185+
span: Some(
1186+
40..51,
1187+
),
1188+
name: "snapshot_id",
1189+
quote: None,
1190+
ident_type: None,
1191+
},
1192+
),
1193+
},
1194+
},
1195+
alias: None,
1196+
},
1197+
],
1198+
from: [
1199+
TableFunction {
1200+
span: Some(
1201+
57..81,
1202+
),
1203+
lateral: false,
1204+
name: Identifier {
1205+
span: Some(
1206+
57..70,
1207+
),
1208+
name: "fuse_snapshot",
1209+
quote: None,
1210+
ident_type: None,
1211+
},
1212+
params: [
1213+
Literal {
1214+
span: Some(
1215+
71..75,
1216+
),
1217+
value: String(
1218+
"db",
1219+
),
1220+
},
1221+
Literal {
1222+
span: Some(
1223+
77..80,
1224+
),
1225+
value: String(
1226+
"t",
1227+
),
1228+
},
1229+
],
1230+
named_params: [],
1231+
alias: None,
1232+
sample: None,
1233+
},
1234+
],
1235+
selection: None,
1236+
group_by: None,
1237+
having: None,
1238+
window_list: None,
1239+
qualify: None,
1240+
},
1241+
),
1242+
order_by: [],
1243+
limit: [
1244+
Literal {
1245+
span: Some(
1246+
88..89,
1247+
),
1248+
value: UInt64(
1249+
1,
1250+
),
1251+
},
1252+
],
1253+
offset: None,
1254+
ignore_result: false,
1255+
},
1256+
},
10741257
),
10751258
),
10761259
),

src/query/ast/tests/it/testdata/stmt.txt

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6858,7 +6858,14 @@ CreateStream(
68586858
},
68596859
travel_point: Some(
68606860
Snapshot(
6861-
"9828b23f74664ff3806f44bbc1925ea5",
6861+
Literal {
6862+
span: Some(
6863+
69..103,
6864+
),
6865+
value: String(
6866+
"9828b23f74664ff3806f44bbc1925ea5",
6867+
),
6868+
},
68626869
),
68636870
),
68646871
append_only: true,
@@ -16528,7 +16535,14 @@ OptimizeTable(
1652816535
action: Purge {
1652916536
before: Some(
1653016537
Snapshot(
16531-
"9828b23f74664ff3806f44bbc1925ea5",
16538+
Literal {
16539+
span: Some(
16540+
43..77,
16541+
),
16542+
value: String(
16543+
"9828b23f74664ff3806f44bbc1925ea5",
16544+
),
16545+
},
1653216546
),
1653316547
),
1653416548
},
@@ -18622,7 +18636,14 @@ AlterTable(
1862218636
},
1862318637
action: FlashbackTo {
1862418638
point: Snapshot(
18625-
"9828b23f74664ff3806f44bbc1925ea5",
18639+
Literal {
18640+
span: Some(
18641+
40..74,
18642+
),
18643+
value: String(
18644+
"9828b23f74664ff3806f44bbc1925ea5",
18645+
),
18646+
},
1862618647
),
1862718648
},
1862818649
},
@@ -18673,7 +18694,14 @@ AlterTable(
1867318694
},
1867418695
travel_point: Some(
1867518696
Snapshot(
18676-
"9828b23f74664ff3806f44bbc1925ea5",
18697+
Literal {
18698+
span: Some(
18699+
47..81,
18700+
),
18701+
value: String(
18702+
"9828b23f74664ff3806f44bbc1925ea5",
18703+
),
18704+
},
1867718705
),
1867818706
),
1867918707
retain: Some(

0 commit comments

Comments
 (0)