@@ -8374,7 +8374,15 @@ impl<'a> Parser<'a> {
83748374 };
83758375
83768376 // parse optional column list (schema)
8377- let (columns, constraints) = self.parse_columns()?;
8377+ // Redshift CTAS allows column names without types:
8378+ // CREATE TABLE t (col1, col2) AS SELECT 1, 2
8379+ // Detect this by peeking for `( ident ,` or `( ident )` patterns.
8380+ let (columns, constraints) =
8381+ if dialect_of!(self is RedshiftSqlDialect) && self.peek_column_names_only() {
8382+ self.parse_columns_without_types()?
8383+ } else {
8384+ self.parse_columns()?
8385+ };
83788386 let comment_after_column_def =
83798387 if dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::COMMENT) {
83808388 let next_token = self.next_token();
@@ -8993,6 +9001,42 @@ impl<'a> Parser<'a> {
89939001 Ok((columns, constraints))
89949002 }
89959003
9004+ /// Returns true if the token stream looks like a parenthesized list of
9005+ /// bare column names (no types), e.g. `(col1, col2)`.
9006+ fn peek_column_names_only(&self) -> bool {
9007+ if self.peek_token_ref().token != Token::LParen {
9008+ return false;
9009+ }
9010+ matches!(
9011+ (
9012+ &self.peek_nth_token_ref(1).token,
9013+ &self.peek_nth_token_ref(2).token
9014+ ),
9015+ (Token::Word(_), Token::Comma | Token::RParen)
9016+ )
9017+ }
9018+
9019+ /// Parse a parenthesized list of column names without data types,
9020+ /// used for Redshift CTAS: `CREATE TABLE t (c1, c2) AS SELECT ...`
9021+ fn parse_columns_without_types(
9022+ &mut self,
9023+ ) -> Result<(Vec<ColumnDef>, Vec<TableConstraint>), ParserError> {
9024+ if !self.consume_token(&Token::LParen) || self.consume_token(&Token::RParen) {
9025+ return Ok((vec![], vec![]));
9026+ }
9027+ let column_names = self.parse_comma_separated(|p| p.parse_identifier())?;
9028+ self.expect_token(&Token::RParen)?;
9029+ let columns = column_names
9030+ .into_iter()
9031+ .map(|name| ColumnDef {
9032+ name,
9033+ data_type: DataType::Unspecified,
9034+ options: vec![],
9035+ })
9036+ .collect();
9037+ Ok((columns, vec![]))
9038+ }
9039+
89969040 /// Parse procedure parameter.
89979041 pub fn parse_procedure_param(&mut self) -> Result<ProcedureParam, ParserError> {
89989042 let mode = if self.parse_keyword(Keyword::IN) {
0 commit comments