Support VALUES clauses in FROM

VALUES clauses are not just valid in INSERT statements. They're also
valid (basically) anywhere table expressions are accepted, like in FROM
clauses.
This commit is contained in:
Nikhil Benesch 2019-05-28 19:28:43 -04:00
parent a3aaa49a7e
commit 9420070a0d
No known key found for this signature in database
GPG key ID: F7386C5DEADABA7F
4 changed files with 83 additions and 39 deletions

View file

@ -20,10 +20,12 @@ mod sql_operator;
mod sqltype;
mod value;
use std::ops::Deref;
pub use self::ddl::{AlterTableOperation, TableConstraint};
pub use self::query::{
Cte, Fetch, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect,
SQLSelectItem, SQLSetExpr, SQLSetOperator, TableFactor,
SQLSelectItem, SQLSetExpr, SQLSetOperator, SQLValues, TableFactor,
};
pub use self::sqltype::SQLType;
pub use self::value::Value;
@ -31,9 +33,14 @@ pub use self::value::Value;
pub use self::sql_operator::SQLOperator;
/// Like `vec.join(", ")`, but for any types implementing ToString.
fn comma_separated_string<T: ToString>(vec: &[T]) -> String {
vec.iter()
.map(T::to_string)
fn comma_separated_string<I>(iter: I) -> String
where
I: IntoIterator,
I::Item: Deref,
<I::Item as Deref>::Target: ToString,
{
iter.into_iter()
.map(|t| t.deref().to_string())
.collect::<Vec<String>>()
.join(", ")
}
@ -336,7 +343,7 @@ pub enum SQLStatement {
/// COLUMNS
columns: Vec<SQLIdent>,
/// VALUES (vector of rows to insert)
values: Vec<Vec<ASTNode>>,
values: SQLValues,
},
SQLCopy {
/// TABLE
@ -408,16 +415,7 @@ impl ToString for SQLStatement {
if !columns.is_empty() {
s += &format!(" ({})", columns.join(", "));
}
if !values.is_empty() {
s += &format!(
" VALUES({})",
values
.iter()
.map(|row| comma_separated_string(row))
.collect::<Vec<String>>()
.join(", ")
);
}
s += &format!(" {}", values.to_string());
s
}
SQLStatement::SQLCopy {
@ -519,7 +517,7 @@ impl ToString for SQLStatement {
"DROP {}{} {}{}",
object_type.to_string(),
if *if_exists { " IF EXISTS" } else { "" },
comma_separated_string(&names),
comma_separated_string(names),
if *cascade { " CASCADE" } else { "" },
),
}

View file

@ -58,7 +58,8 @@ pub enum SQLSetExpr {
left: Box<SQLSetExpr>,
right: Box<SQLSetExpr>,
},
// TODO: ANSI SQL supports `TABLE` and `VALUES` here.
Values(SQLValues),
// TODO: ANSI SQL supports `TABLE` here.
}
impl ToString for SQLSetExpr {
@ -66,6 +67,7 @@ impl ToString for SQLSetExpr {
match self {
SQLSetExpr::Select(s) => s.to_string(),
SQLSetExpr::Query(q) => format!("({})", q.to_string()),
SQLSetExpr::Values(v) => v.to_string(),
SQLSetExpr::SetOperation {
left,
right,
@ -364,3 +366,16 @@ impl ToString for Fetch {
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQLValues(pub Vec<Vec<ASTNode>>);
impl ToString for SQLValues {
fn to_string(&self) -> String {
let rows = self
.0
.iter()
.map(|row| format!("({})", comma_separated_string(row)));
format!("VALUES {}", comma_separated_string(rows))
}
}

View file

@ -1352,6 +1352,8 @@ impl Parser {
let subquery = self.parse_query()?;
self.expect_token(&Token::RParen)?;
SQLSetExpr::Query(Box::new(subquery))
} else if self.parse_keyword("VALUES") {
SQLSetExpr::Values(self.parse_values()?)
} else {
return self.expected("SELECT or a subquery in the query body", self.peek_token());
};
@ -1564,13 +1566,11 @@ impl Parser {
let table_name = self.parse_object_name()?;
let columns = self.parse_parenthesized_column_list(Optional)?;
self.expect_keyword("VALUES")?;
self.expect_token(&Token::LParen)?;
let values = self.parse_expr_list()?;
self.expect_token(&Token::RParen)?;
let values = self.parse_values()?;
Ok(SQLStatement::SQLInsert {
table_name,
columns,
values: vec![values],
values,
})
}
@ -1688,6 +1688,20 @@ impl Parser {
quantity,
})
}
pub fn parse_values(&mut self) -> Result<SQLValues, ParserError> {
let mut values = vec![];
loop {
self.expect_token(&Token::LParen)?;
values.push(self.parse_expr_list()?);
self.expect_token(&Token::RParen)?;
match self.peek_token() {
Some(Token::Comma) => self.next_token(),
_ => break,
};
}
Ok(SQLValues(values))
}
}
impl SQLWord {

View file

@ -14,23 +14,40 @@ use sqlparser::test_utils::{all_dialects, expr_from_projection, only};
#[test]
fn parse_insert_values() {
let sql = "INSERT INTO customer VALUES(1, 2, 3)";
check_one(sql, "customer", vec![]);
let row = vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3)),
];
let rows1 = vec![row.clone()];
let rows2 = vec![row.clone(), row];
let sql = "INSERT INTO public.customer VALUES(1, 2, 3)";
check_one(sql, "public.customer", vec![]);
let sql = "INSERT INTO customer VALUES (1, 2, 3)";
check_one(sql, "customer", &[], &rows1);
let sql = "INSERT INTO db.public.customer VALUES(1, 2, 3)";
check_one(sql, "db.public.customer", vec![]);
let sql = "INSERT INTO customer VALUES (1, 2, 3), (1, 2, 3)";
check_one(sql, "customer", &[], &rows2);
let sql = "INSERT INTO public.customer (id, name, active) VALUES(1, 2, 3)";
let sql = "INSERT INTO public.customer VALUES (1, 2, 3)";
check_one(sql, "public.customer", &[], &rows1);
let sql = "INSERT INTO db.public.customer VALUES (1, 2, 3)";
check_one(sql, "db.public.customer", &[], &rows1);
let sql = "INSERT INTO public.customer (id, name, active) VALUES (1, 2, 3)";
check_one(
sql,
"public.customer",
vec!["id".to_string(), "name".to_string(), "active".to_string()],
&["id".to_string(), "name".to_string(), "active".to_string()],
&rows1,
);
fn check_one(sql: &str, expected_table_name: &str, expected_columns: Vec<String>) {
fn check_one(
sql: &str,
expected_table_name: &str,
expected_columns: &[String],
expected_rows: &[Vec<ASTNode>],
) {
match verified_stmt(sql) {
SQLStatement::SQLInsert {
table_name,
@ -40,14 +57,7 @@ fn parse_insert_values() {
} => {
assert_eq!(table_name.to_string(), expected_table_name);
assert_eq!(columns, expected_columns);
assert_eq!(
vec![vec![
ASTNode::SQLValue(Value::Long(1)),
ASTNode::SQLValue(Value::Long(2)),
ASTNode::SQLValue(Value::Long(3))
]],
values
);
assert_eq!(values.0.as_slice(), expected_rows);
}
_ => unreachable!(),
}
@ -1383,6 +1393,13 @@ fn parse_union() {
verified_stmt("SELECT foo FROM tab UNION SELECT bar FROM TAB");
}
#[test]
fn parse_values() {
verified_stmt("SELECT * FROM (VALUES (1), (2), (3))");
verified_stmt("SELECT * FROM (VALUES (1), (2), (3)), (VALUES (1, 2, 3))");
verified_stmt("SELECT * FROM (VALUES (1)) UNION VALUES (1)");
}
#[test]
fn parse_multiple_statements() {
fn test_with(sql1: &str, sql2_kw: &str, sql2_rest: &str) {
@ -1416,7 +1433,7 @@ fn parse_multiple_statements() {
" cte AS (SELECT 1 AS s) SELECT bar",
);
test_with("DELETE FROM foo", "SELECT", " bar");
test_with("INSERT INTO foo VALUES(1)", "SELECT", " bar");
test_with("INSERT INTO foo VALUES (1)", "SELECT", " bar");
test_with("CREATE TABLE foo (baz int)", "SELECT", " bar");
// Make sure that empty statements do not cause an error:
let res = parse_sql_statements(";;");