Skip to content

Commit 0c0cbca

Browse files
committed
Support basic CREATE VIEW
1 parent 346d1ff commit 0c0cbca

File tree

4 files changed

+100
-59
lines changed

4 files changed

+100
-59
lines changed

src/dialect/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ keyword!(
350350
VARCHAR,
351351
VARYING,
352352
VERSIONING,
353+
VIEW,
353354
WHEN,
354355
WHENEVER,
355356
WHERE,
@@ -697,6 +698,7 @@ pub const ALL_KEYWORDS: &'static [&'static str] = &[
697698
VARCHAR,
698699
VARYING,
699700
VERSIONING,
701+
VIEW,
700702
WHEN,
701703
WHENEVER,
702704
WHERE,

src/sqlast/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ pub enum SQLStatement {
173173
/// WHERE
174174
selection: Option<ASTNode>,
175175
},
176+
/// CREATE VIEW
177+
SQLCreateView {
178+
/// View name
179+
name: SQLObjectName,
180+
query: SQLSelect,
181+
},
176182
/// CREATE TABLE
177183
SQLCreateTable {
178184
/// Table name
@@ -278,6 +284,9 @@ impl ToString for SQLStatement {
278284
}
279285
s
280286
}
287+
SQLStatement::SQLCreateView { name, query } => {
288+
format!("CREATE VIEW {} AS {}", name.to_string(), query.to_string())
289+
}
281290
SQLStatement::SQLCreateTable { name, columns } => format!(
282291
"CREATE TABLE {} ({})",
283292
name.to_string(),

src/sqlparser.rs

Lines changed: 77 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -546,65 +546,10 @@ impl Parser {
546546

547547
/// Parse a SQL CREATE statement
548548
pub fn parse_create(&mut self) -> Result<SQLStatement, ParserError> {
549-
if self.parse_keywords(vec!["TABLE"]) {
550-
let table_name = self.parse_object_name()?;
551-
// parse optional column list (schema)
552-
let mut columns = vec![];
553-
if self.consume_token(&Token::LParen) {
554-
loop {
555-
match self.next_token() {
556-
Some(Token::SQLWord(column_name)) => {
557-
let data_type = self.parse_data_type()?;
558-
let is_primary = self.parse_keywords(vec!["PRIMARY", "KEY"]);
559-
let is_unique = self.parse_keyword("UNIQUE");
560-
let default = if self.parse_keyword("DEFAULT") {
561-
let expr = self.parse_default_expr(0)?;
562-
Some(expr)
563-
} else {
564-
None
565-
};
566-
let allow_null = if self.parse_keywords(vec!["NOT", "NULL"]) {
567-
false
568-
} else if self.parse_keyword("NULL") {
569-
true
570-
} else {
571-
true
572-
};
573-
debug!("default: {:?}", default);
574-
575-
columns.push(SQLColumnDef {
576-
name: column_name.as_sql_ident(),
577-
data_type: data_type,
578-
allow_null,
579-
is_primary,
580-
is_unique,
581-
default,
582-
});
583-
match self.next_token() {
584-
Some(Token::Comma) => {}
585-
Some(Token::RParen) => {
586-
break;
587-
}
588-
other => {
589-
return parser_err!(
590-
format!("Expected ',' or ')' after column definition but found {:?}", other)
591-
);
592-
}
593-
}
594-
}
595-
unexpected => {
596-
return parser_err!(format!(
597-
"Expected column name, got {:?}",
598-
unexpected
599-
));
600-
}
601-
}
602-
}
603-
}
604-
Ok(SQLStatement::SQLCreateTable {
605-
name: table_name,
606-
columns,
607-
})
549+
if self.parse_keyword("TABLE") {
550+
self.parse_create_table()
551+
} else if self.parse_keyword("VIEW") {
552+
self.parse_create_view()
608553
} else {
609554
parser_err!(format!(
610555
"Unexpected token after CREATE: {:?}",
@@ -613,6 +558,79 @@ impl Parser {
613558
}
614559
}
615560

561+
pub fn parse_create_view(&mut self) -> Result<SQLStatement, ParserError> {
562+
// Many dialects support `OR REPLACE` | `OR ALTER` right after `CREATE`, but we don't (yet).
563+
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
564+
let name = self.parse_object_name()?;
565+
// Parenthesized "output" columns list could be handled here.
566+
// Some dialects allow WITH here, followed by some keywords (e.g. MS SQL)
567+
// or `(k1=v1, k2=v2, ...)` (Postgres)
568+
self.expect_keyword("AS")?;
569+
self.expect_keyword("SELECT")?;
570+
let query = self.parse_select()?;
571+
// Optional `WITH [ CASCADED | LOCAL ] CHECK OPTION` is widely supported here.
572+
Ok(SQLStatement::SQLCreateView { name, query })
573+
}
574+
575+
pub fn parse_create_table(&mut self) -> Result<SQLStatement, ParserError> {
576+
let table_name = self.parse_object_name()?;
577+
// parse optional column list (schema)
578+
let mut columns = vec![];
579+
if self.consume_token(&Token::LParen) {
580+
loop {
581+
match self.next_token() {
582+
Some(Token::SQLWord(column_name)) => {
583+
let data_type = self.parse_data_type()?;
584+
let is_primary = self.parse_keywords(vec!["PRIMARY", "KEY"]);
585+
let is_unique = self.parse_keyword("UNIQUE");
586+
let default = if self.parse_keyword("DEFAULT") {
587+
let expr = self.parse_default_expr(0)?;
588+
Some(expr)
589+
} else {
590+
None
591+
};
592+
let allow_null = if self.parse_keywords(vec!["NOT", "NULL"]) {
593+
false
594+
} else if self.parse_keyword("NULL") {
595+
true
596+
} else {
597+
true
598+
};
599+
debug!("default: {:?}", default);
600+
601+
columns.push(SQLColumnDef {
602+
name: column_name.as_sql_ident(),
603+
data_type: data_type,
604+
allow_null,
605+
is_primary,
606+
is_unique,
607+
default,
608+
});
609+
match self.next_token() {
610+
Some(Token::Comma) => {}
611+
Some(Token::RParen) => {
612+
break;
613+
}
614+
other => {
615+
return parser_err!(format!(
616+
"Expected ',' or ')' after column definition but found {:?}",
617+
other
618+
));
619+
}
620+
}
621+
}
622+
unexpected => {
623+
return parser_err!(format!("Expected column name, got {:?}", unexpected));
624+
}
625+
}
626+
}
627+
}
628+
Ok(SQLStatement::SQLCreateTable {
629+
name: table_name,
630+
columns,
631+
})
632+
}
633+
616634
pub fn parse_table_key(&mut self, constraint_name: SQLIdent) -> Result<TableKey, ParserError> {
617635
let is_primary_key = self.parse_keywords(vec!["PRIMARY", "KEY"]);
618636
let is_unique_key = self.parse_keywords(vec!["UNIQUE", "KEY"]);

tests/sqlparser_generic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,18 @@ fn parse_scalar_subqueries() {
700700
};
701701
}
702702

703+
#[test]
704+
fn parse_create_view() {
705+
let sql = "CREATE VIEW myschema.myview AS SELECT foo FROM bar";
706+
match verified_stmt(sql) {
707+
SQLStatement::SQLCreateView { name, query } => {
708+
assert_eq!("myschema.myview", name.to_string());
709+
assert_eq!("SELECT foo FROM bar", query.to_string());
710+
}
711+
_ => assert!(false),
712+
}
713+
}
714+
703715
#[test]
704716
fn parse_invalid_subquery_without_parens() {
705717
let res = parse_sql_statements("SELECT SELECT 1 FROM bar WHERE 1=1 FROM baz");

0 commit comments

Comments
 (0)