parseDataType parses a SQL data type for CAST or :: expressions Handles: simple types (INTEGER, TEXT), parameterized types (VARCHAR(100), NUMERIC(10,2))
()
| 287 | // parseDataType parses a SQL data type for CAST or :: expressions |
| 288 | // Handles: simple types (INTEGER, TEXT), parameterized types (VARCHAR(100), NUMERIC(10,2)) |
| 289 | func (p *Parser) parseDataType() (string, error) { |
| 290 | // Data type can be an identifier or a keyword like INT, VARCHAR, etc. |
| 291 | if !p.isIdentifier() && !p.isDataTypeKeyword() { |
| 292 | return "", p.expectedError("data type") |
| 293 | } |
| 294 | |
| 295 | // Use strings.Builder for efficient string concatenation |
| 296 | var sb strings.Builder |
| 297 | sb.WriteString(p.currentToken.Token.Value) |
| 298 | p.advance() // Consume type name |
| 299 | |
| 300 | // Check for type parameters (e.g., VARCHAR(100), DECIMAL(10,2)) |
| 301 | if p.isType(models.TokenTypeLParen) { |
| 302 | p.advance() // Consume ( |
| 303 | sb.WriteByte('(') |
| 304 | |
| 305 | paramCount := 0 |
| 306 | for !p.isType(models.TokenTypeRParen) { |
| 307 | if paramCount > 0 { |
| 308 | if !p.isType(models.TokenTypeComma) { |
| 309 | return "", p.expectedError(", or )") |
| 310 | } |
| 311 | sb.WriteString(p.currentToken.Token.Value) |
| 312 | p.advance() // Consume comma |
| 313 | } |
| 314 | |
| 315 | // Parse parameter (should be a number or identifier) |
| 316 | // Use token type constants for consistency |
| 317 | if !p.isType(models.TokenTypeNumber) && !p.isType(models.TokenTypeIdentifier) && !p.isNumericLiteral() { |
| 318 | return "", goerrors.InvalidSyntaxError( |
| 319 | fmt.Sprintf("expected numeric type parameter, got '%s'", p.currentToken.Token.Value), |
| 320 | p.currentLocation(), |
| 321 | "Use TYPE(precision[, scale]) syntax", |
| 322 | ) |
| 323 | } |
| 324 | |
| 325 | sb.WriteString(p.currentToken.Token.Value) |
| 326 | p.advance() |
| 327 | paramCount++ |
| 328 | } |
| 329 | |
| 330 | sb.WriteByte(')') |
| 331 | |
| 332 | if !p.isType(models.TokenTypeRParen) { |
| 333 | return "", p.expectedError(")") |
| 334 | } |
| 335 | p.advance() // Consume ) |
| 336 | } |
| 337 | |
| 338 | // Check for array type suffix (e.g., INTEGER[], TEXT[]) |
| 339 | if p.isType(models.TokenTypeLBracket) { |
| 340 | p.advance() // Consume [ |
| 341 | if !p.isType(models.TokenTypeRBracket) { |
| 342 | return "", p.expectedError("]") |
| 343 | } |
| 344 | p.advance() // Consume ] |
| 345 | sb.WriteString("[]") |
| 346 | } |
no test coverage detected