mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-07 15:58:02 +00:00
Make a PostgreSQLDialect
Add is_primary and is_unique in the column definition Initial code for testing alter table
This commit is contained in:
parent
74b34faaf1
commit
da153bf848
4 changed files with 135 additions and 23 deletions
105
src/dialect.rs
105
src/dialect.rs
|
@ -433,16 +433,101 @@ impl Dialect for GenericSqlDialect {
|
||||||
"DATE",
|
"DATE",
|
||||||
"TIME",
|
"TIME",
|
||||||
"TIMESTAMP",
|
"TIMESTAMP",
|
||||||
"VALUES",
|
];
|
||||||
"DEFAULT",
|
}
|
||||||
"ZONE",
|
|
||||||
"REGCLASS",
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
"TEXT",
|
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '@'
|
||||||
"BYTEA",
|
}
|
||||||
"TRUE",
|
|
||||||
"FALSE",
|
fn is_identifier_part(&self, ch: char) -> bool {
|
||||||
"COPY",
|
(ch >= 'a' && ch <= 'z')
|
||||||
"STDIN",
|
|| (ch >= 'A' && ch <= 'Z')
|
||||||
|
|| (ch >= '0' && ch <= '9')
|
||||||
|
|| ch == '@'
|
||||||
|
|| ch == '_'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PostgreSqlDialect {}
|
||||||
|
|
||||||
|
impl Dialect for PostgreSqlDialect {
|
||||||
|
fn keywords(&self) -> Vec<&'static str> {
|
||||||
|
return vec![
|
||||||
|
"SELECT",
|
||||||
|
"FROM",
|
||||||
|
"WHERE",
|
||||||
|
"LIMIT",
|
||||||
|
"ORDER",
|
||||||
|
"GROUP",
|
||||||
|
"BY",
|
||||||
|
"HAVING",
|
||||||
|
"UNION",
|
||||||
|
"ALL",
|
||||||
|
"INSERT",
|
||||||
|
"INTO",
|
||||||
|
"UPDATE",
|
||||||
|
"DELETE",
|
||||||
|
"IN",
|
||||||
|
"IS",
|
||||||
|
"NULL",
|
||||||
|
"SET",
|
||||||
|
"CREATE",
|
||||||
|
"EXTERNAL",
|
||||||
|
"TABLE",
|
||||||
|
"ASC",
|
||||||
|
"DESC",
|
||||||
|
"AND",
|
||||||
|
"OR",
|
||||||
|
"NOT",
|
||||||
|
"AS",
|
||||||
|
"STORED",
|
||||||
|
"CSV",
|
||||||
|
"PARQUET",
|
||||||
|
"LOCATION",
|
||||||
|
"WITH",
|
||||||
|
"WITHOUT",
|
||||||
|
"HEADER",
|
||||||
|
"ROW",
|
||||||
|
// SQL types
|
||||||
|
"CHAR",
|
||||||
|
"CHARACTER",
|
||||||
|
"VARYING",
|
||||||
|
"LARGE",
|
||||||
|
"OBJECT",
|
||||||
|
"VARCHAR",
|
||||||
|
"CLOB",
|
||||||
|
"BINARY",
|
||||||
|
"VARBINARY",
|
||||||
|
"BLOB",
|
||||||
|
"FLOAT",
|
||||||
|
"REAL",
|
||||||
|
"DOUBLE",
|
||||||
|
"PRECISION",
|
||||||
|
"INT",
|
||||||
|
"INTEGER",
|
||||||
|
"SMALLINT",
|
||||||
|
"BIGINT",
|
||||||
|
"NUMERIC",
|
||||||
|
"DECIMAL",
|
||||||
|
"DEC",
|
||||||
|
"BOOLEAN",
|
||||||
|
"DATE",
|
||||||
|
"TIME",
|
||||||
|
"TIMESTAMP",
|
||||||
|
"VALUES",
|
||||||
|
"DEFAULT",
|
||||||
|
"ZONE",
|
||||||
|
"REGCLASS",
|
||||||
|
"TEXT",
|
||||||
|
"BYTEA",
|
||||||
|
"TRUE",
|
||||||
|
"FALSE",
|
||||||
|
"COPY",
|
||||||
|
"STDIN",
|
||||||
|
"PRIMARY",
|
||||||
|
"KEY",
|
||||||
|
"UNIQUE",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,8 @@ pub struct SQLColumnDef {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data_type: SQLType,
|
pub data_type: SQLType,
|
||||||
pub allow_null: bool,
|
pub allow_null: bool,
|
||||||
|
pub is_primary: bool,
|
||||||
|
pub is_unique: bool,
|
||||||
pub default: Option<Box<ASTNode>>,
|
pub default: Option<Box<ASTNode>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -478,6 +478,8 @@ impl Parser {
|
||||||
loop {
|
loop {
|
||||||
if let Some(Token::Identifier(column_name)) = self.next_token() {
|
if let Some(Token::Identifier(column_name)) = self.next_token() {
|
||||||
if let Ok(data_type) = self.parse_data_type() {
|
if let Ok(data_type) = self.parse_data_type() {
|
||||||
|
let is_primary = self.parse_keywords(vec!["PRIMARY", "KEY"]);
|
||||||
|
let is_unique = self.parse_keyword("UNIQUE");
|
||||||
let default = if self.parse_keyword("DEFAULT"){
|
let default = if self.parse_keyword("DEFAULT"){
|
||||||
let expr = self.parse_expr(0)?;
|
let expr = self.parse_expr(0)?;
|
||||||
Some(Box::new(expr))
|
Some(Box::new(expr))
|
||||||
|
@ -500,6 +502,8 @@ impl Parser {
|
||||||
name: column_name,
|
name: column_name,
|
||||||
data_type: data_type,
|
data_type: data_type,
|
||||||
allow_null,
|
allow_null,
|
||||||
|
is_primary,
|
||||||
|
is_unique,
|
||||||
default,
|
default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -509,6 +513,8 @@ impl Parser {
|
||||||
name: column_name,
|
name: column_name,
|
||||||
data_type: data_type,
|
data_type: data_type,
|
||||||
allow_null,
|
allow_null,
|
||||||
|
is_primary,
|
||||||
|
is_unique,
|
||||||
default,
|
default,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -538,6 +544,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Parse a copy statement
|
/// Parse a copy statement
|
||||||
pub fn parse_copy(&mut self) -> Result<ASTNode, ParserError> {
|
pub fn parse_copy(&mut self) -> Result<ASTNode, ParserError> {
|
||||||
let table_name = self.parse_tablename()?;
|
let table_name = self.parse_tablename()?;
|
||||||
|
@ -1090,13 +1097,13 @@ impl Parser {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::super::dialect::GenericSqlDialect;
|
use super::super::dialect::PostgreSqlDialect;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prev_index(){
|
fn test_prev_index(){
|
||||||
let sql: &str = "SELECT version()";
|
let sql: &str = "SELECT version()";
|
||||||
let mut tokenizer = Tokenizer::new(&GenericSqlDialect{}, &sql);
|
let mut tokenizer = Tokenizer::new(&PostgreSqlDialect{}, &sql);
|
||||||
let tokens = tokenizer.tokenize().expect("error tokenizing");
|
let tokens = tokenizer.tokenize().expect("error tokenizing");
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
assert_eq!(parser.prev_token(), None);
|
assert_eq!(parser.prev_token(), None);
|
||||||
|
@ -1542,9 +1549,9 @@ mod tests {
|
||||||
fn parse_create_table_with_inherit() {
|
fn parse_create_table_with_inherit() {
|
||||||
let sql = String::from("
|
let sql = String::from("
|
||||||
CREATE TABLE bazaar.settings (
|
CREATE TABLE bazaar.settings (
|
||||||
user_id uuid,
|
settings_id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
user_id uuid UNIQUE,
|
||||||
value text[],
|
value text[],
|
||||||
settings_id uuid DEFAULT uuid_generate_v4() NOT NULL,
|
|
||||||
use_metric boolean DEFAULT true
|
use_metric boolean DEFAULT true
|
||||||
)
|
)
|
||||||
INHERITS (system.record)");
|
INHERITS (system.record)");
|
||||||
|
@ -1554,14 +1561,40 @@ mod tests {
|
||||||
assert_eq!("bazaar.settings", name);
|
assert_eq!("bazaar.settings", name);
|
||||||
|
|
||||||
let c_name = &columns[0];
|
let c_name = &columns[0];
|
||||||
|
assert_eq!("settings_id", c_name.name);
|
||||||
|
assert_eq!(SQLType::Custom("uuid".into()), c_name.data_type);
|
||||||
|
assert_eq!(false, c_name.allow_null);
|
||||||
|
assert_eq!(true, c_name.is_primary);
|
||||||
|
assert_eq!(false, c_name.is_unique);
|
||||||
|
|
||||||
|
let c_name = &columns[1];
|
||||||
assert_eq!("user_id", c_name.name);
|
assert_eq!("user_id", c_name.name);
|
||||||
assert_eq!(SQLType::Custom("uuid".into()), c_name.data_type);
|
assert_eq!(SQLType::Custom("uuid".into()), c_name.data_type);
|
||||||
assert_eq!(true, c_name.allow_null);
|
assert_eq!(true, c_name.allow_null);
|
||||||
|
assert_eq!(false, c_name.is_primary);
|
||||||
|
assert_eq!(true, c_name.is_unique);
|
||||||
}
|
}
|
||||||
_ => assert!(false),
|
_ => assert!(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_constraint_primary_key(){
|
||||||
|
let sql = String::from("
|
||||||
|
ALTER TABLE ONLY bazaar.address
|
||||||
|
ADD CONSTRAINT address_pkey PRIMARY KEY (address_id)");
|
||||||
|
let ast = parse_sql(&sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_alter_table_constraint_foreign_key(){
|
||||||
|
let sql = String::from("
|
||||||
|
ALTER TABLE ONLY public.customer
|
||||||
|
ADD CONSTRAINT customer_address_id_fkey FOREIGN KEY (address_id) REFERENCES public.address(address_id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||||
|
");
|
||||||
|
let ast = parse_sql(&sql);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_copy_example(){
|
fn parse_copy_example(){
|
||||||
let sql = String::from(r#"
|
let sql = String::from(r#"
|
||||||
|
@ -1681,7 +1714,7 @@ PHP ₱ USD $
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parser(sql: &str) -> Parser {
|
fn parser(sql: &str) -> Parser {
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = PostgreSqlDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
debug!("tokens: {:#?}", tokens);
|
debug!("tokens: {:#?}", tokens);
|
||||||
|
|
|
@ -203,14 +203,6 @@ impl<'a> Tokenizer<'a> {
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
}
|
}
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
/*
|
|
||||||
Ok(tokens
|
|
||||||
.into_iter()
|
|
||||||
.filter(|t| match t {
|
|
||||||
Token::Whitespace(..) => false,
|
|
||||||
_ => true,
|
|
||||||
}).collect())
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next token or return None
|
/// Get the next token or return None
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue