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",
|
||||
"TIME",
|
||||
"TIMESTAMP",
|
||||
"VALUES",
|
||||
"DEFAULT",
|
||||
"ZONE",
|
||||
"REGCLASS",
|
||||
"TEXT",
|
||||
"BYTEA",
|
||||
"TRUE",
|
||||
"FALSE",
|
||||
"COPY",
|
||||
"STDIN",
|
||||
];
|
||||
}
|
||||
|
||||
fn is_identifier_start(&self, ch: char) -> bool {
|
||||
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '@'
|
||||
}
|
||||
|
||||
fn is_identifier_part(&self, ch: char) -> bool {
|
||||
(ch >= 'a' && ch <= 'z')
|
||||
|| (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 data_type: SQLType,
|
||||
pub allow_null: bool,
|
||||
pub is_primary: bool,
|
||||
pub is_unique: bool,
|
||||
pub default: Option<Box<ASTNode>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -478,6 +478,8 @@ impl Parser {
|
|||
loop {
|
||||
if let Some(Token::Identifier(column_name)) = self.next_token() {
|
||||
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 expr = self.parse_expr(0)?;
|
||||
Some(Box::new(expr))
|
||||
|
@ -500,6 +502,8 @@ impl Parser {
|
|||
name: column_name,
|
||||
data_type: data_type,
|
||||
allow_null,
|
||||
is_primary,
|
||||
is_unique,
|
||||
default,
|
||||
});
|
||||
}
|
||||
|
@ -509,6 +513,8 @@ impl Parser {
|
|||
name: column_name,
|
||||
data_type: data_type,
|
||||
allow_null,
|
||||
is_primary,
|
||||
is_unique,
|
||||
default,
|
||||
});
|
||||
break;
|
||||
|
@ -538,6 +544,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Parse a copy statement
|
||||
pub fn parse_copy(&mut self) -> Result<ASTNode, ParserError> {
|
||||
let table_name = self.parse_tablename()?;
|
||||
|
@ -1090,13 +1097,13 @@ impl Parser {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::super::dialect::GenericSqlDialect;
|
||||
use super::super::dialect::PostgreSqlDialect;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_prev_index(){
|
||||
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 mut parser = Parser::new(tokens);
|
||||
assert_eq!(parser.prev_token(), None);
|
||||
|
@ -1542,9 +1549,9 @@ mod tests {
|
|||
fn parse_create_table_with_inherit() {
|
||||
let sql = String::from("
|
||||
CREATE TABLE bazaar.settings (
|
||||
user_id uuid,
|
||||
settings_id uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
user_id uuid UNIQUE,
|
||||
value text[],
|
||||
settings_id uuid DEFAULT uuid_generate_v4() NOT NULL,
|
||||
use_metric boolean DEFAULT true
|
||||
)
|
||||
INHERITS (system.record)");
|
||||
|
@ -1554,14 +1561,40 @@ mod tests {
|
|||
assert_eq!("bazaar.settings", name);
|
||||
|
||||
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!(SQLType::Custom("uuid".into()), c_name.data_type);
|
||||
assert_eq!(true, c_name.allow_null);
|
||||
assert_eq!(false, c_name.is_primary);
|
||||
assert_eq!(true, c_name.is_unique);
|
||||
}
|
||||
_ => 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]
|
||||
fn parse_copy_example(){
|
||||
let sql = String::from(r#"
|
||||
|
@ -1681,7 +1714,7 @@ PHP ₱ USD $
|
|||
}
|
||||
|
||||
fn parser(sql: &str) -> Parser {
|
||||
let dialect = GenericSqlDialect {};
|
||||
let dialect = PostgreSqlDialect {};
|
||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||
let tokens = tokenizer.tokenize().unwrap();
|
||||
debug!("tokens: {:#?}", tokens);
|
||||
|
|
|
@ -203,14 +203,6 @@ impl<'a> Tokenizer<'a> {
|
|||
tokens.push(token);
|
||||
}
|
||||
Ok(tokens)
|
||||
/*
|
||||
Ok(tokens
|
||||
.into_iter()
|
||||
.filter(|t| match t {
|
||||
Token::Whitespace(..) => false,
|
||||
_ => true,
|
||||
}).collect())
|
||||
*/
|
||||
}
|
||||
|
||||
/// Get the next token or return None
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue