parseCastLike implements the body shared between CAST and TRY_CAST. The caller is responsible for ensuring the current token is the leading keyword.
(try bool)
| 147 | // parseCastLike implements the body shared between CAST and TRY_CAST. The |
| 148 | // caller is responsible for ensuring the current token is the leading keyword. |
| 149 | func (p *Parser) parseCastLike(try bool) (*ast.CastExpression, error) { |
| 150 | // Consume CAST / TRY_CAST keyword |
| 151 | p.advance() |
| 152 | |
| 153 | // Expect opening parenthesis |
| 154 | if !p.isType(models.TokenTypeLParen) { |
| 155 | return nil, p.expectedError("(") |
| 156 | } |
| 157 | p.advance() // Consume ( |
| 158 | |
| 159 | // Parse the expression to be cast |
| 160 | expr, err := p.parseExpression() |
| 161 | if err != nil { |
| 162 | return nil, err |
| 163 | } |
| 164 | |
| 165 | // Expect AS keyword |
| 166 | if !p.isType(models.TokenTypeAs) { |
| 167 | return nil, p.expectedError("AS") |
| 168 | } |
| 169 | p.advance() // Consume AS |
| 170 | |
| 171 | // Parse the target data type |
| 172 | // The type can be: |
| 173 | // - Simple type: VARCHAR, INT, DECIMAL, etc. |
| 174 | // - Type with precision: VARCHAR(100), DECIMAL(10,2), etc. |
| 175 | if !p.isType(models.TokenTypeIdentifier) { |
| 176 | return nil, p.expectedError("data type") |
| 177 | } |
| 178 | |
| 179 | dataType := p.currentToken.Token.Value |
| 180 | p.advance() // Consume type name |
| 181 | |
| 182 | // Check for type parameters (e.g., VARCHAR(100), DECIMAL(10,2)) |
| 183 | if p.isType(models.TokenTypeLParen) { |
| 184 | p.advance() // Consume ( |
| 185 | |
| 186 | // Build the full type string including parameters |
| 187 | typeParams := "(" |
| 188 | paramCount := 0 |
| 189 | |
| 190 | for !p.isType(models.TokenTypeRParen) { |
| 191 | if paramCount > 0 { |
| 192 | if !p.isType(models.TokenTypeComma) { |
| 193 | return nil, p.expectedError(", or )") |
| 194 | } |
| 195 | typeParams += p.currentToken.Token.Value |
| 196 | p.advance() // Consume comma |
| 197 | } |
| 198 | |
| 199 | // Parse parameter (should be a number) |
| 200 | if !p.isNumericLiteral() && !p.isType(models.TokenTypeIdentifier) { |
| 201 | return nil, goerrors.InvalidSyntaxError( |
| 202 | "expected numeric type parameter", |
| 203 | p.currentLocation(), |
| 204 | "Use CAST(expr AS TYPE(precision[, scale]))", |
| 205 | ) |
| 206 | } |
no test coverage detected