Skip to content

Commit d4ac9e2

Browse files
feat: support INSERT INTO FUNCTION
1 parent fe36020 commit d4ac9e2

File tree

8 files changed

+125
-45
lines changed

8 files changed

+125
-45
lines changed

src/ast/dml.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use super::{
3636
FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat, HiveRowFormat, Ident,
3737
InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OneOrManyWithParens,
3838
OrderByExpr, Query, RowAccessPolicy, SelectItem, SqlOption, SqliteOnConflict, TableEngine,
39-
TableWithJoins, Tag, WrappedCollection,
39+
TableObject, TableWithJoins, Tag, WrappedCollection,
4040
};
4141

4242
/// CREATE INDEX statement.
@@ -470,8 +470,7 @@ pub struct Insert {
470470
/// INTO - optional keyword
471471
pub into: bool,
472472
/// TABLE
473-
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
474-
pub table_name: ObjectName,
473+
pub table_object: TableObject,
475474
/// table_name as foo (for PostgreSQL)
476475
pub table_alias: Option<Ident>,
477476
/// COLUMNS
@@ -500,9 +499,9 @@ pub struct Insert {
500499
impl Display for Insert {
501500
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502501
let table_name = if let Some(alias) = &self.table_alias {
503-
format!("{0} AS {alias}", self.table_name)
502+
format!("{0} AS {alias}", self.table_object)
504503
} else {
505-
self.table_name.to_string()
504+
self.table_object.to_string()
506505
};
507506

508507
if let Some(on_conflict) = self.or {

src/ast/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -7672,6 +7672,26 @@ impl Display for JsonNullClause {
76727672
}
76737673
}
76747674

7675+
/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
7676+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
7677+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7678+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
7679+
pub enum TableObject {
7680+
TableName(#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))] ObjectName),
7681+
7682+
// Clickhouse: [Table functions](https://clickhouse.com/docs/en/sql-reference/table-functions)
7683+
TableFunction(Function),
7684+
}
7685+
7686+
impl fmt::Display for TableObject {
7687+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7688+
match self {
7689+
Self::TableName(table_name) => write!(f, "{}", display_separated(&table_name.0, ".")),
7690+
Self::TableFunction(func) => write!(f, "FUNCTION {}", func),
7691+
}
7692+
}
7693+
}
7694+
76757695
#[cfg(test)]
76767696
mod tests {
76777697
use super::*;

src/ast/spans.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ use super::{
3232
OrderBy, OrderByExpr, Partition, PivotValueSource, ProjectionSelect, Query, ReferentialAction,
3333
RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
3434
SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef,
35-
TableConstraint, TableFactor, TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use,
36-
Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill,
35+
TableConstraint, TableFactor, TableObject, TableOptionsClustered, TableWithJoins,
36+
UpdateTableFromKind, Use, Value, Values, ViewColumnDef, WildcardAdditionalOptions, With,
37+
WithFill,
3738
};
3839

3940
/// Given an iterator of spans, return the [Span::union] of all spans.
@@ -1138,7 +1139,7 @@ impl Spanned for Insert {
11381139
or: _, // enum, sqlite specific
11391140
ignore: _, // bool
11401141
into: _, // bool
1141-
table_name,
1142+
table_object,
11421143
table_alias,
11431144
columns,
11441145
overwrite: _, // bool
@@ -1154,7 +1155,7 @@ impl Spanned for Insert {
11541155
} = self;
11551156

11561157
union_spans(
1157-
core::iter::once(table_name.span())
1158+
core::iter::once(table_object.span())
11581159
.chain(table_alias.as_ref().map(|i| i.span))
11591160
.chain(columns.iter().map(|i| i.span))
11601161
.chain(source.as_ref().map(|q| q.span()))
@@ -2116,6 +2117,17 @@ impl Spanned for UpdateTableFromKind {
21162117
}
21172118
}
21182119

2120+
impl Spanned for TableObject {
2121+
fn span(&self) -> Span {
2122+
match self {
2123+
TableObject::TableName(ObjectName(segments)) => {
2124+
union_spans(segments.iter().map(|i| i.span))
2125+
}
2126+
TableObject::TableFunction(func) => func.span(),
2127+
}
2128+
}
2129+
}
2130+
21192131
#[cfg(test)]
21202132
pub mod tests {
21212133
use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};

src/parser/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -8839,6 +8839,23 @@ impl<'a> Parser<'a> {
88398839
}
88408840
}
88418841

8842+
pub fn parse_table_object(
8843+
&mut self,
8844+
in_table_clause: bool,
8845+
) -> Result<TableObject, ParserError> {
8846+
if dialect_of!(self is ClickHouseDialect) && self.parse_keyword(Keyword::FUNCTION) {
8847+
self.parse_table_function().map(TableObject::TableFunction)
8848+
} else {
8849+
self.parse_object_name(in_table_clause)
8850+
.map(TableObject::TableName)
8851+
}
8852+
}
8853+
8854+
pub fn parse_table_function(&mut self) -> Result<Function, ParserError> {
8855+
let fn_name = self.parse_object_name(false)?;
8856+
self.parse_function_call(fn_name)
8857+
}
8858+
88428859
/// Parse a possibly qualified, possibly quoted identifier, e.g.
88438860
/// `foo` or `myschema."table"
88448861
///
@@ -11813,7 +11830,7 @@ impl<'a> Parser<'a> {
1181311830
} else {
1181411831
// Hive lets you put table here regardless
1181511832
let table = self.parse_keyword(Keyword::TABLE);
11816-
let table_name = self.parse_object_name(false)?;
11833+
let table_object = self.parse_table_object(false)?;
1181711834

1181811835
let table_alias =
1181911836
if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::AS) {
@@ -11916,7 +11933,7 @@ impl<'a> Parser<'a> {
1191611933

1191711934
Ok(Statement::Insert(Insert {
1191811935
or,
11919-
table_name,
11936+
table_object,
1192011937
table_alias,
1192111938
ignore,
1192211939
into,

tests/sqlparser_clickhouse.rs

+5
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ fn parse_create_table() {
222222
);
223223
}
224224

225+
#[test]
226+
fn parse_insert_into_function() {
227+
clickhouse().verified_stmt(r#"INSERT INTO TABLE FUNCTION remote('localhost', default.simple_table) VALUES (100, 'inserted via remote()')"#);
228+
}
229+
225230
#[test]
226231
fn parse_alter_table_attach_and_detach_partition() {
227232
for operation in &["ATTACH", "DETACH"] {

tests/sqlparser_common.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn parse_insert_values() {
9595
) {
9696
match verified_stmt(sql) {
9797
Statement::Insert(Insert {
98-
table_name,
98+
table_object: table_name,
9999
columns,
100100
source: Some(source),
101101
..
@@ -142,7 +142,7 @@ fn parse_insert_default_values() {
142142
partitioned,
143143
returning,
144144
source,
145-
table_name,
145+
table_object: table_name,
146146
..
147147
}) => {
148148
assert_eq!(columns, vec![]);
@@ -151,7 +151,10 @@ fn parse_insert_default_values() {
151151
assert_eq!(partitioned, None);
152152
assert_eq!(returning, None);
153153
assert_eq!(source, None);
154-
assert_eq!(table_name, ObjectName(vec!["test_table".into()]));
154+
assert_eq!(
155+
table_name,
156+
TableObject::TableName(ObjectName(vec!["test_table".into()]))
157+
);
155158
}
156159
_ => unreachable!(),
157160
}
@@ -167,7 +170,7 @@ fn parse_insert_default_values() {
167170
partitioned,
168171
returning,
169172
source,
170-
table_name,
173+
table_object: table_name,
171174
..
172175
}) => {
173176
assert_eq!(after_columns, vec![]);
@@ -176,7 +179,10 @@ fn parse_insert_default_values() {
176179
assert_eq!(partitioned, None);
177180
assert!(returning.is_some());
178181
assert_eq!(source, None);
179-
assert_eq!(table_name, ObjectName(vec!["test_table".into()]));
182+
assert_eq!(
183+
table_name,
184+
TableObject::TableName(ObjectName(vec!["test_table".into()]))
185+
);
180186
}
181187
_ => unreachable!(),
182188
}
@@ -192,7 +198,7 @@ fn parse_insert_default_values() {
192198
partitioned,
193199
returning,
194200
source,
195-
table_name,
201+
table_object: table_name,
196202
..
197203
}) => {
198204
assert_eq!(after_columns, vec![]);
@@ -201,7 +207,10 @@ fn parse_insert_default_values() {
201207
assert_eq!(partitioned, None);
202208
assert_eq!(returning, None);
203209
assert_eq!(source, None);
204-
assert_eq!(table_name, ObjectName(vec!["test_table".into()]));
210+
assert_eq!(
211+
table_name,
212+
TableObject::TableName(ObjectName(vec!["test_table".into()]))
213+
);
205214
}
206215
_ => unreachable!(),
207216
}

0 commit comments

Comments
 (0)