parseCreateTable parses CREATE TABLE statement with partitioning support
(temporary bool)
| 154 | |
| 155 | // parseCreateTable parses CREATE TABLE statement with partitioning support |
| 156 | func (p *Parser) parseCreateTable(temporary bool) (*ast.CreateTableStatement, error) { |
| 157 | stmt := &ast.CreateTableStatement{ |
| 158 | Temporary: temporary, |
| 159 | } |
| 160 | |
| 161 | // Check for IF NOT EXISTS |
| 162 | if p.isType(models.TokenTypeIf) { |
| 163 | p.advance() // Consume IF |
| 164 | if !p.isType(models.TokenTypeNot) { |
| 165 | return nil, p.expectedError("NOT after IF") |
| 166 | } |
| 167 | p.advance() // Consume NOT |
| 168 | if !p.isType(models.TokenTypeExists) { |
| 169 | return nil, p.expectedError("EXISTS after NOT") |
| 170 | } |
| 171 | p.advance() // Consume EXISTS |
| 172 | stmt.IfNotExists = true |
| 173 | } |
| 174 | |
| 175 | // Parse table name (supports schema.table qualification and double-quoted identifiers) |
| 176 | createTableName, err := p.parseQualifiedName() |
| 177 | if err != nil { |
| 178 | return nil, p.expectedError("table name") |
| 179 | } |
| 180 | stmt.Name = createTableName |
| 181 | |
| 182 | // Snowflake: COPY GRANTS modifier before the column list or AS SELECT. |
| 183 | // Consumed but not modeled on the AST. |
| 184 | if strings.EqualFold(p.currentToken.Token.Value, "COPY") && |
| 185 | strings.EqualFold(p.peekToken().Token.Value, "GRANTS") { |
| 186 | p.advance() // COPY |
| 187 | p.advance() // GRANTS |
| 188 | } |
| 189 | |
| 190 | // CREATE TABLE ... AS SELECT — no column list, just a query. |
| 191 | if p.isType(models.TokenTypeAs) { |
| 192 | p.advance() // AS |
| 193 | if p.isType(models.TokenTypeSelect) || p.isType(models.TokenTypeWith) { |
| 194 | p.advance() // SELECT / WITH |
| 195 | query, err := p.parseSelectWithSetOperations() |
| 196 | if err != nil { |
| 197 | return nil, err |
| 198 | } |
| 199 | _ = query // CTAS query not modeled on CreateTableStatement yet |
| 200 | return stmt, nil |
| 201 | } |
| 202 | return nil, p.expectedError("SELECT after AS") |
| 203 | } |
| 204 | |
| 205 | // Expect opening parenthesis for column definitions |
| 206 | if !p.isType(models.TokenTypeLParen) { |
| 207 | return nil, p.expectedError("(") |
| 208 | } |
| 209 | p.advance() // Consume ( |
| 210 | |
| 211 | // Parse column definitions and constraints |
| 212 | for { |
| 213 | // MariaDB: PERIOD FOR name (start_col, end_col) — application-time or system-time period |
no test coverage detected