mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-22 05:32:29 +00:00
Support SQLite CREATE VIRTUAL TABLE
(#209)
`CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)` https://www.sqlite.org/lang_createvtab.html
This commit is contained in:
parent
0c83e5d9e8
commit
a53f1d26ef
5 changed files with 73 additions and 4 deletions
|
@ -12,6 +12,7 @@ Check https://github.com/andygrove/sqlparser-rs/commits/master for undocumented
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Support SQLite's `CREATE TABLE (...) WITHOUT ROWID` (#208) - thanks @mashuai!
|
- Support SQLite's `CREATE TABLE (...) WITHOUT ROWID` (#208) - thanks @mashuai!
|
||||||
|
- Support SQLite's `CREATE VIRTUAL TABLE` (#209) - thanks @mashuai!
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -484,6 +484,13 @@ pub enum Statement {
|
||||||
query: Option<Box<Query>>,
|
query: Option<Box<Query>>,
|
||||||
without_rowid: bool,
|
without_rowid: bool,
|
||||||
},
|
},
|
||||||
|
/// SQLite's `CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`
|
||||||
|
CreateVirtualTable {
|
||||||
|
name: ObjectName,
|
||||||
|
if_not_exists: bool,
|
||||||
|
module_name: Ident,
|
||||||
|
module_args: Vec<Ident>,
|
||||||
|
},
|
||||||
/// CREATE INDEX
|
/// CREATE INDEX
|
||||||
CreateIndex {
|
CreateIndex {
|
||||||
/// index name
|
/// index name
|
||||||
|
@ -695,6 +702,24 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Statement::CreateVirtualTable {
|
||||||
|
name,
|
||||||
|
if_not_exists,
|
||||||
|
module_name,
|
||||||
|
module_args,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"CREATE VIRTUAL TABLE {if_not_exists}{name} USING {module_name}",
|
||||||
|
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
|
||||||
|
name = name,
|
||||||
|
module_name = module_name
|
||||||
|
)?;
|
||||||
|
if !module_args.is_empty() {
|
||||||
|
write!(f, " ({})", display_comma_separated(module_args))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Statement::CreateIndex {
|
Statement::CreateIndex {
|
||||||
name,
|
name,
|
||||||
table_name,
|
table_name,
|
||||||
|
|
|
@ -438,6 +438,7 @@ define_keywords!(
|
||||||
VAR_SAMP,
|
VAR_SAMP,
|
||||||
VERSIONING,
|
VERSIONING,
|
||||||
VIEW,
|
VIEW,
|
||||||
|
VIRTUAL,
|
||||||
WHEN,
|
WHEN,
|
||||||
WHENEVER,
|
WHENEVER,
|
||||||
WHERE,
|
WHERE,
|
||||||
|
|
|
@ -55,6 +55,7 @@ pub enum IsLateral {
|
||||||
Lateral,
|
Lateral,
|
||||||
NotLateral,
|
NotLateral,
|
||||||
}
|
}
|
||||||
|
use crate::ast::Statement::CreateVirtualTable;
|
||||||
use IsLateral::*;
|
use IsLateral::*;
|
||||||
|
|
||||||
impl From<TokenizerError> for ParserError {
|
impl From<TokenizerError> for ParserError {
|
||||||
|
@ -986,16 +987,35 @@ impl Parser {
|
||||||
self.parse_create_view()
|
self.parse_create_view()
|
||||||
} else if self.parse_keyword(Keyword::EXTERNAL) {
|
} else if self.parse_keyword(Keyword::EXTERNAL) {
|
||||||
self.parse_create_external_table()
|
self.parse_create_external_table()
|
||||||
|
} else if self.parse_keyword(Keyword::VIRTUAL) {
|
||||||
|
self.parse_create_virtual_table()
|
||||||
} else if self.parse_keyword(Keyword::SCHEMA) {
|
} else if self.parse_keyword(Keyword::SCHEMA) {
|
||||||
self.parse_create_schema()
|
self.parse_create_schema()
|
||||||
} else {
|
} else {
|
||||||
self.expected(
|
self.expected("an object type after CREATE", self.peek_token())
|
||||||
"TABLE, VIEW, INDEX or SCHEMA after CREATE",
|
|
||||||
self.peek_token(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SQLite-specific `CREATE VIRTUAL TABLE`
|
||||||
|
pub fn parse_create_virtual_table(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
self.expect_keyword(Keyword::TABLE)?;
|
||||||
|
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
|
||||||
|
let table_name = self.parse_object_name()?;
|
||||||
|
self.expect_keyword(Keyword::USING)?;
|
||||||
|
let module_name = self.parse_identifier()?;
|
||||||
|
// SQLite docs note that module "arguments syntax is sufficiently
|
||||||
|
// general that the arguments can be made to appear as column
|
||||||
|
// definitions in a traditional CREATE TABLE statement", but
|
||||||
|
// we don't implement that.
|
||||||
|
let module_args = self.parse_parenthesized_column_list(Optional)?;
|
||||||
|
Ok(CreateVirtualTable {
|
||||||
|
name: table_name,
|
||||||
|
if_not_exists,
|
||||||
|
module_name,
|
||||||
|
module_args,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_create_schema(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_create_schema(&mut self) -> Result<Statement, ParserError> {
|
||||||
let schema_name = self.parse_object_name()?;
|
let schema_name = self.parse_object_name()?;
|
||||||
Ok(Statement::CreateSchema { schema_name })
|
Ok(Statement::CreateSchema { schema_name })
|
||||||
|
|
|
@ -33,6 +33,28 @@ fn parse_create_table_without_rowid() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_virtual_table() {
|
||||||
|
let sql = "CREATE VIRTUAL TABLE IF NOT EXISTS t USING module_name (arg1, arg2)";
|
||||||
|
match sqlite_and_generic().verified_stmt(sql) {
|
||||||
|
Statement::CreateVirtualTable {
|
||||||
|
name,
|
||||||
|
if_not_exists: true,
|
||||||
|
module_name,
|
||||||
|
module_args,
|
||||||
|
} => {
|
||||||
|
let args = vec![Ident::new("arg1"), Ident::new("arg2")];
|
||||||
|
assert_eq!("t", name.to_string());
|
||||||
|
assert_eq!("module_name", module_name.to_string());
|
||||||
|
assert_eq!(args, module_args);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
let sql = "CREATE VIRTUAL TABLE t USING module_name";
|
||||||
|
sqlite_and_generic().verified_stmt(sql);
|
||||||
|
}
|
||||||
|
|
||||||
fn sqlite_and_generic() -> TestedDialects {
|
fn sqlite_and_generic() -> TestedDialects {
|
||||||
TestedDialects {
|
TestedDialects {
|
||||||
// we don't have a separate SQLite dialect, so test only the generic dialect for now
|
// we don't have a separate SQLite dialect, so test only the generic dialect for now
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue