(mode GeneratorMode, stmt *parser.DDL, defaultSchema string, rawDDL string)
| 371 | } |
| 372 | |
| 373 | func parseTable(mode GeneratorMode, stmt *parser.DDL, defaultSchema string, rawDDL string) (Table, error) { |
| 374 | var columns = map[string]*Column{} |
| 375 | var indexes []Index |
| 376 | var checks []CheckDefinition |
| 377 | var foreignKeys []ForeignKey |
| 378 | var exclusions []Exclusion |
| 379 | |
| 380 | columnComments := extractColumnComments(rawDDL, mode) |
| 381 | indexComments := extractIndexComments(rawDDL, mode) |
| 382 | |
| 383 | for i, parsedCol := range stmt.TableSpec.Columns { |
| 384 | // Normalize PostgreSQL type aliases from generic parser |
| 385 | typeName := parsedCol.Type.Type |
| 386 | typeIdent := parsedCol.Type.TypeIdent |
| 387 | timezone := castBool(parsedCol.Type.Timezone) |
| 388 | // references is used for: |
| 389 | // 1. Schema-qualified type names (e.g., "public." for public.mytype) - stored with trailing dot |
| 390 | // 2. Simple REFERENCES clause without column names (e.g., "REFERENCES table_name") |
| 391 | var references Ident |
| 392 | |
| 393 | // For simple REFERENCES (without column names), store the table name in references |
| 394 | // This is separate from the ForeignKey logic which handles REFERENCES with explicit columns |
| 395 | if !parsedCol.Type.References.Name.IsEmpty() && len(parsedCol.Type.ReferenceNames) == 0 { |
| 396 | references = parsedCol.Type.References.Name |
| 397 | } |
| 398 | |
| 399 | if mode == GeneratorModePostgres { |
| 400 | // Handle short timezone forms: timestamptz -> timestamp, timetz -> time |
| 401 | // The generic parser parses these as custom identifiers without setting Timezone flag. |
| 402 | // Clear typeIdent so the quote-aware comparison path doesn't see a stale name. |
| 403 | switch strings.ToLower(typeName) { |
| 404 | case "timestamptz": |
| 405 | typeName = "timestamp" |
| 406 | typeIdent = Ident{} |
| 407 | timezone = true |
| 408 | case "timetz": |
| 409 | typeName = "time" |
| 410 | typeIdent = Ident{} |
| 411 | timezone = true |
| 412 | } |
| 413 | |
| 414 | // Handle schema-qualified types from generic parser |
| 415 | // Generic parser stores "schema.type" in typeName field |
| 416 | // pgquery parser stores "schema." in references and "type" in typeName |
| 417 | // Normalize to the pgquery format for consistent comparison |
| 418 | if strings.Contains(typeName, ".") && references.IsEmpty() { |
| 419 | parts := strings.SplitN(typeName, ".", 2) |
| 420 | if len(parts) == 2 { |
| 421 | // Store schema with trailing dot to match pgquery format |
| 422 | references = Ident{Name: parts[0] + "."} |
| 423 | typeName = parts[1] |
| 424 | } |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | column := Column{ |
| 429 | name: parsedCol.Name, |
| 430 | position: i, |
no test coverage detected