mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 23:14:07 +00:00
Support SQLite column definitions with no type (#1075)
This commit is contained in:
parent
a75778c8c7
commit
a430d1a5a7
6 changed files with 51 additions and 3 deletions
|
@ -219,6 +219,10 @@ pub enum DataType {
|
||||||
/// [hive]: https://docs.cloudera.com/cdw-runtime/cloud/impala-sql-reference/topics/impala-struct.html
|
/// [hive]: https://docs.cloudera.com/cdw-runtime/cloud/impala-sql-reference/topics/impala-struct.html
|
||||||
/// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
|
/// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
|
||||||
Struct(Vec<StructField>),
|
Struct(Vec<StructField>),
|
||||||
|
/// No type specified - only used with
|
||||||
|
/// [`SQLiteDialect`](crate::dialect::SQLiteDialect), from statements such
|
||||||
|
/// as `CREATE TABLE t1 (a)`.
|
||||||
|
Unspecified,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DataType {
|
impl fmt::Display for DataType {
|
||||||
|
@ -379,6 +383,7 @@ impl fmt::Display for DataType {
|
||||||
write!(f, "STRUCT")
|
write!(f, "STRUCT")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DataType::Unspecified => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -586,7 +586,11 @@ pub struct ColumnDef {
|
||||||
|
|
||||||
impl fmt::Display for ColumnDef {
|
impl fmt::Display for ColumnDef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {}", self.name, self.data_type)?;
|
if self.data_type == DataType::Unspecified {
|
||||||
|
write!(f, "{}", self.name)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{} {}", self.name, self.data_type)?;
|
||||||
|
}
|
||||||
if let Some(collation) = &self.collation {
|
if let Some(collation) = &self.collation {
|
||||||
write!(f, " COLLATE {collation}")?;
|
write!(f, " COLLATE {collation}")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,9 @@ macro_rules! dialect_of {
|
||||||
/// encapsulates the parsing differences between dialects.
|
/// encapsulates the parsing differences between dialects.
|
||||||
///
|
///
|
||||||
/// [`GenericDialect`] is the most permissive dialect, and parses the union of
|
/// [`GenericDialect`] is the most permissive dialect, and parses the union of
|
||||||
/// all the other dialects, when there is no ambiguity.
|
/// all the other dialects, when there is no ambiguity. However, it does not
|
||||||
|
/// currently allow `CREATE TABLE` statements without types specified for all
|
||||||
|
/// columns; use [`SQLiteDialect`] if you require that.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// Most users create a [`Dialect`] directly, as shown on the [module
|
/// Most users create a [`Dialect`] directly, as shown on the [module
|
||||||
|
|
|
@ -16,6 +16,11 @@ use crate::keywords::Keyword;
|
||||||
use crate::parser::{Parser, ParserError};
|
use crate::parser::{Parser, ParserError};
|
||||||
|
|
||||||
/// A [`Dialect`] for [SQLite](https://www.sqlite.org)
|
/// A [`Dialect`] for [SQLite](https://www.sqlite.org)
|
||||||
|
///
|
||||||
|
/// This dialect allows columns in a
|
||||||
|
/// [`CREATE TABLE`](https://sqlite.org/lang_createtable.html) statement with no
|
||||||
|
/// type specified, as in `CREATE TABLE t1 (a)`. In the AST, these columns will
|
||||||
|
/// have the data type [`Unspecified`](crate::ast::DataType::Unspecified).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SQLiteDialect {}
|
pub struct SQLiteDialect {}
|
||||||
|
|
||||||
|
|
|
@ -4272,7 +4272,11 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
pub fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
|
pub fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
|
||||||
let name = self.parse_identifier()?;
|
let name = self.parse_identifier()?;
|
||||||
let data_type = self.parse_data_type()?;
|
let data_type = if self.is_column_type_sqlite_unspecified() {
|
||||||
|
DataType::Unspecified
|
||||||
|
} else {
|
||||||
|
self.parse_data_type()?
|
||||||
|
};
|
||||||
let mut collation = if self.parse_keyword(Keyword::COLLATE) {
|
let mut collation = if self.parse_keyword(Keyword::COLLATE) {
|
||||||
Some(self.parse_object_name()?)
|
Some(self.parse_object_name()?)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4308,6 +4312,29 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_column_type_sqlite_unspecified(&mut self) -> bool {
|
||||||
|
if dialect_of!(self is SQLiteDialect) {
|
||||||
|
match self.peek_token().token {
|
||||||
|
Token::Word(word) => matches!(
|
||||||
|
word.keyword,
|
||||||
|
Keyword::CONSTRAINT
|
||||||
|
| Keyword::PRIMARY
|
||||||
|
| Keyword::NOT
|
||||||
|
| Keyword::UNIQUE
|
||||||
|
| Keyword::CHECK
|
||||||
|
| Keyword::DEFAULT
|
||||||
|
| Keyword::COLLATE
|
||||||
|
| Keyword::REFERENCES
|
||||||
|
| Keyword::GENERATED
|
||||||
|
| Keyword::AS
|
||||||
|
),
|
||||||
|
_ => true, // e.g. comma immediately after column name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_optional_column_option(&mut self) -> Result<Option<ColumnOption>, ParserError> {
|
pub fn parse_optional_column_option(&mut self) -> Result<Option<ColumnOption>, ParserError> {
|
||||||
if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) {
|
if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) {
|
||||||
Ok(Some(ColumnOption::CharacterSet(self.parse_object_name()?)))
|
Ok(Some(ColumnOption::CharacterSet(self.parse_object_name()?)))
|
||||||
|
|
|
@ -221,6 +221,11 @@ fn parse_create_table_gencol() {
|
||||||
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
|
sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 2) STORED)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_create_table_untyped() {
|
||||||
|
sqlite().verified_stmt("CREATE TABLE t1 (a, b AS (a * 2), c NOT NULL)");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_placeholder() {
|
fn test_placeholder() {
|
||||||
// In postgres, this would be the absolute value operator '@' applied to the column 'xxx'
|
// In postgres, this would be the absolute value operator '@' applied to the column 'xxx'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue