diff --git a/fuzz/fuzz_seeds/postgres_2407_generated_column.sql b/fuzz/fuzz_seeds/postgres_2407_generated_column.sql new file mode 100644 index 0000000000..606621cd3f --- /dev/null +++ b/fuzz/fuzz_seeds/postgres_2407_generated_column.sql @@ -0,0 +1 @@ +CREATE TABLE t (a INT GENERATED ALWAYS AS (1)); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b630070939..faf6e1595d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -10376,18 +10376,15 @@ impl<'a> Parser<'a> { let expr: Expr = self.with_state(ParserState::Normal, |p| p.parse_expr())?; self.expect_token(&Token::RParen)?; let (gen_as, expr_mode) = if self.parse_keywords(&[Keyword::STORED]) { - Ok(( + ( GeneratedAs::ExpStored, Some(GeneratedExpressionMode::Stored), - )) - } else if dialect_of!(self is PostgreSqlDialect) { - // Postgres' AS IDENTITY branches are above, this one needs STORED - self.expected_ref("STORED", self.peek_token_ref()) + ) } else if self.parse_keywords(&[Keyword::VIRTUAL]) { - Ok((GeneratedAs::Always, Some(GeneratedExpressionMode::Virtual))) + (GeneratedAs::Always, Some(GeneratedExpressionMode::Virtual)) } else { - Ok((GeneratedAs::Always, None)) - }?; + (GeneratedAs::Always, None) + }; Ok(Some(ColumnOption::Generated { generated_as: gen_as, diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index f4726b96e3..0734c9cb2d 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -11229,3 +11229,22 @@ fn parse_alter_table_attach_partition_of() { ); } } + +#[test] +fn parse_create_table_generated_column_modes() { + pg().verified_stmt("CREATE TABLE t (a TEXT, b TEXT GENERATED ALWAYS AS (a))"); + pg().verified_stmt("CREATE TABLE t (a TEXT, b TEXT GENERATED ALWAYS AS (a) VIRTUAL)"); + pg().verified_stmt("CREATE TABLE t (a TEXT, b TEXT GENERATED ALWAYS AS (a) STORED)"); + + pg().one_statement_parses_to( + r#"CREATE TABLE users ( + first_name text NOT NULL, + last_name text NOT NULL, + name character varying(255) GENERATED ALWAYS AS (((first_name || ' '::text) || last_name)) NOT NULL +)"#, + "CREATE TABLE users (\ + first_name TEXT NOT NULL, \ + last_name TEXT NOT NULL, \ + name CHARACTER VARYING(255) GENERATED ALWAYS AS (((first_name || ' '::TEXT) || last_name)) NOT NULL)", + ); +}