parseColumnDef parses a column definition including column constraints
()
| 50 | |
| 51 | // parseColumnDef parses a column definition including column constraints |
| 52 | func (p *Parser) parseColumnDef() (*ast.ColumnDef, error) { |
| 53 | name := p.parseColumnName() |
| 54 | if name == nil { |
| 55 | return nil, goerrors.ExpectedTokenError( |
| 56 | "column name", |
| 57 | p.currentToken.Token.Type.String(), |
| 58 | p.currentLocation(), |
| 59 | "", |
| 60 | ) |
| 61 | } |
| 62 | |
| 63 | // Parse data type (including parameterized types like VARCHAR(100), DECIMAL(10,2)). |
| 64 | // Use parseColumnName to accept keyword-based type names such as INTEGER, TEXT, REAL. |
| 65 | dataType := p.parseColumnName() |
| 66 | if dataType == nil { |
| 67 | return nil, goerrors.ExpectedTokenError( |
| 68 | "data type", |
| 69 | p.currentToken.Token.Type.String(), |
| 70 | p.currentLocation(), |
| 71 | "", |
| 72 | ) |
| 73 | } |
| 74 | |
| 75 | dataTypeStr := dataType.Name |
| 76 | |
| 77 | // Check for type parameters. The simple form is VARCHAR(100) or |
| 78 | // DECIMAL(10,2), but ClickHouse also has nested/parameterised types like |
| 79 | // Array(Nullable(String)), Map(String, Array(UInt32)), Tuple(a UInt8, b String), |
| 80 | // FixedString(16), DateTime64(3, 'UTC'), LowCardinality(String), Decimal(38, 18), |
| 81 | // and engines like ReplicatedMergeTree('/path', '{replica}'). Use a depth-tracking |
| 82 | // token collector that round-trips the type string. |
| 83 | if p.isType(models.TokenTypeLParen) { |
| 84 | args, err := p.parseTypeArgsString() |
| 85 | if err != nil { |
| 86 | return nil, err |
| 87 | } |
| 88 | dataTypeStr += args |
| 89 | } |
| 90 | |
| 91 | colDef := &ast.ColumnDef{ |
| 92 | Name: name.Name, |
| 93 | Type: dataTypeStr, |
| 94 | } |
| 95 | |
| 96 | // ClickHouse column options that may appear between the type and the |
| 97 | // standard constraint list: CODEC(...), DEFAULT expr, MATERIALIZED expr, |
| 98 | // ALIAS expr, EPHEMERAL expr, TTL expr. Consume permissively; they are |
| 99 | // appended to the type string for now so formatters can round-trip, and |
| 100 | // not yet modeled on the AST. |
| 101 | if p.dialect == string(keywords.DialectClickHouse) { |
| 102 | for { |
| 103 | upper := strings.ToUpper(p.currentToken.Token.Value) |
| 104 | if upper == "CODEC" && p.peekToken().Token.Type == models.TokenTypeLParen { |
| 105 | p.advance() // CODEC |
| 106 | args, err := p.parseTypeArgsString() |
| 107 | if err != nil { |
| 108 | return nil, err |
| 109 | } |
no test coverage detected