Skip to content

Commit ba34f62

Browse files
authored
[chore] add passthrough query as a tablefactor (#32)
We want to have the capability to specify subquery of a SQL string that we don't necessarily need to parse. This passthrough query will be only created at runtime and serialized as it is. The main purpose here is performance and to avoid any potential parsing bugs with already known valid SQL.
2 parents 761c86e + fce3ce8 commit ba34f62

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

src/ast/query.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,12 @@ pub enum TableFactor {
11351135
subquery: Box<Query>,
11361136
alias: Option<TableAlias>,
11371137
},
1138+
/// A pass-through query string that is not parsed.
1139+
/// This is useful while building/rewriting queries with a known valid SQL string and to avoid parsing it.
1140+
PassThroughQuery {
1141+
query: String,
1142+
alias: Option<TableAlias>,
1143+
},
11381144
/// `TABLE(<expr>)[ AS <alias> ]`
11391145
TableFunction {
11401146
expr: Expr,
@@ -1767,6 +1773,13 @@ impl fmt::Display for TableFactor {
17671773
}
17681774
Ok(())
17691775
}
1776+
TableFactor::PassThroughQuery { query, alias } => {
1777+
write!(f, "({query})")?;
1778+
if let Some(alias) = alias {
1779+
write!(f, " AS {alias}")?;
1780+
}
1781+
Ok(())
1782+
}
17701783
TableFactor::Function {
17711784
lateral,
17721785
name,

src/ast/spans.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,8 @@ impl Spanned for TableFactor {
18761876
} => subquery
18771877
.span()
18781878
.union_opt(&alias.as_ref().map(|alias| alias.span())),
1879+
// This is usually created at runtime, so we don't have a span for it
1880+
TableFactor::PassThroughQuery { query: _, alias: _ } => Span::empty(),
18791881
TableFactor::TableFunction { expr, alias } => expr
18801882
.span()
18811883
.union_opt(&alias.as_ref().map(|alias| alias.span())),

src/parser/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11971,7 +11971,8 @@ impl<'a> Parser<'a> {
1197111971
| TableFactor::Pivot { alias, .. }
1197211972
| TableFactor::Unpivot { alias, .. }
1197311973
| TableFactor::MatchRecognize { alias, .. }
11974-
| TableFactor::NestedJoin { alias, .. } => {
11974+
| TableFactor::NestedJoin { alias, .. }
11975+
| TableFactor::PassThroughQuery { alias, .. } => {
1197511976
// but not `FROM (mytable AS alias1) AS alias2`.
1197611977
if let Some(inner_alias) = alias {
1197711978
return Err(ParserError::ParserError(format!(

tests/sqlparser_common.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14124,6 +14124,29 @@ fn parse_select_without_projection() {
1412414124
dialects.verified_stmt("SELECT FROM users");
1412514125
}
1412614126

14127+
#[test]
14128+
fn ast_with_pass_through_query() {
14129+
let sql = "SELECT * FROM t1 AS t2";
14130+
let mut ast = all_dialects().verified_stmt(sql);
14131+
let Statement::Query(ref mut query) = ast else {
14132+
panic!("Expected Query");
14133+
};
14134+
let SetExpr::Select(ref mut select) = *query.body else {
14135+
panic!("Expected SetExpr::Select");
14136+
};
14137+
let from = select.from.get_mut(0).unwrap();
14138+
from.relation = TableFactor::PassThroughQuery {
14139+
query: "SELECT * FROM tx".to_string(),
14140+
alias: Some(TableAlias {
14141+
name: Ident::new("ty"),
14142+
columns: vec![],
14143+
}),
14144+
};
14145+
14146+
// After modifying the AST, the SQL representation should be different
14147+
assert_eq!(ast.to_string(), "SELECT * FROM (SELECT * FROM tx) AS ty");
14148+
}
14149+
1412714150
#[test]
1412814151
fn parse_update_from_before_select() {
1412914152
verified_stmt("UPDATE t1 FROM (SELECT name, id FROM t1 GROUP BY id) AS t2 SET name = t2.name WHERE t1.id = t2.id");

0 commit comments

Comments
 (0)