mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-22 15:04:04 +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
|
||||
/// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type
|
||||
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 {
|
||||
|
@ -379,6 +383,7 @@ impl fmt::Display for DataType {
|
|||
write!(f, "STRUCT")
|
||||
}
|
||||
}
|
||||
DataType::Unspecified => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -586,7 +586,11 @@ pub struct ColumnDef {
|
|||
|
||||
impl fmt::Display for ColumnDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.data_type == DataType::Unspecified {
|
||||
write!(f, "{}", self.name)?;
|
||||
} else {
|
||||
write!(f, "{} {}", self.name, self.data_type)?;
|
||||
}
|
||||
if let Some(collation) = &self.collation {
|
||||
write!(f, " COLLATE {collation}")?;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,9 @@ macro_rules! dialect_of {
|
|||
/// encapsulates the parsing differences between dialects.
|
||||
///
|
||||
/// [`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
|
||||
/// Most users create a [`Dialect`] directly, as shown on the [module
|
||||
|
|
|
@ -16,6 +16,11 @@ use crate::keywords::Keyword;
|
|||
use crate::parser::{Parser, ParserError};
|
||||
|
||||
/// 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)]
|
||||
pub struct SQLiteDialect {}
|
||||
|
||||
|
|
|
@ -4272,7 +4272,11 @@ impl<'a> Parser<'a> {
|
|||
|
||||
pub fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
|
||||
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) {
|
||||
Some(self.parse_object_name()?)
|
||||
} 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> {
|
||||
if self.parse_keywords(&[Keyword::CHARACTER, Keyword::SET]) {
|
||||
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)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table_untyped() {
|
||||
sqlite().verified_stmt("CREATE TABLE t1 (a, b AS (a * 2), c NOT NULL)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placeholder() {
|
||||
// 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