Skip to content

Commit 4013de1

Browse files
kyleconroyclaude
andcommitted
Add complete external file format options parsing support
- Add SERDE_METHOD and DATA_COMPRESSION as top-level options - Add ExternalFileFormatUseDefaultTypeOption for USE_TYPE_DEFAULT - Change ExternalFileFormatLiteralOption.Value to ScalarExpression to support both StringLiteral and IntegerLiteral - Handle FIRST_ROW as IntegerLiteral Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 112e786 commit 4013de1

File tree

5 files changed

+70
-6
lines changed

5 files changed

+70
-6
lines changed

ast/external_statements.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,19 @@ func (o *ExternalFileFormatContainerOption) externalFileFormatOption() {}
4343
// ExternalFileFormatLiteralOption represents a literal value option
4444
type ExternalFileFormatLiteralOption struct {
4545
OptionKind string
46-
Value *StringLiteral
46+
Value ScalarExpression // Can be StringLiteral or IntegerLiteral
4747
}
4848

4949
func (o *ExternalFileFormatLiteralOption) externalFileFormatOption() {}
5050

51+
// ExternalFileFormatUseDefaultTypeOption represents USE_TYPE_DEFAULT option
52+
type ExternalFileFormatUseDefaultTypeOption struct {
53+
OptionKind string
54+
ExternalFileFormatUseDefaultType string // "True" or "False"
55+
}
56+
57+
func (o *ExternalFileFormatUseDefaultTypeOption) externalFileFormatOption() {}
58+
5159
// CreateExternalTableStatement represents CREATE EXTERNAL TABLE statement
5260
type CreateExternalTableStatement struct {
5361
SchemaObjectName *SchemaObjectName

parser/marshal.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16647,9 +16647,15 @@ func externalFileFormatOptionToJSON(opt ast.ExternalFileFormatOption) jsonNode {
1664716647
"OptionKind": o.OptionKind,
1664816648
}
1664916649
if o.Value != nil {
16650-
node["Value"] = stringLiteralToJSON(o.Value)
16650+
node["Value"] = scalarExpressionToJSON(o.Value)
1665116651
}
1665216652
return node
16653+
case *ast.ExternalFileFormatUseDefaultTypeOption:
16654+
return jsonNode{
16655+
"$type": "ExternalFileFormatUseDefaultTypeOption",
16656+
"ExternalFileFormatUseDefaultType": o.ExternalFileFormatUseDefaultType,
16657+
"OptionKind": o.OptionKind,
16658+
}
1665316659
default:
1665416660
return jsonNode{"$type": "UnknownExternalFileFormatOption"}
1665516661
}

parser/parse_statements.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8350,10 +8350,29 @@ func (p *Parser) parseCreateExternalFileFormatStatement() (*ast.CreateExternalFi
83508350
}
83518351
stmt.ExternalFileFormatOptions = append(stmt.ExternalFileFormatOptions, opt)
83528352
} else {
8353-
// Skip other options for now
8353+
// Handle other options (SERDE_METHOD, DATA_COMPRESSION) as literal options
8354+
optionKind := p.externalFileFormatOptionKind(optName)
83548355
if p.curTok.Type == TokenEquals {
83558356
p.nextToken() // consume =
8356-
p.nextToken() // consume value
8357+
// Parse value (string literal or identifier like FALSE/TRUE)
8358+
if p.curTok.Type == TokenString {
8359+
val, _ := p.parseStringLiteral()
8360+
stmt.ExternalFileFormatOptions = append(stmt.ExternalFileFormatOptions, &ast.ExternalFileFormatLiteralOption{
8361+
OptionKind: optionKind,
8362+
Value: val,
8363+
})
8364+
} else {
8365+
// Handle identifiers like FALSE, TRUE, etc.
8366+
val := &ast.StringLiteral{
8367+
LiteralType: "String",
8368+
Value: p.curTok.Literal,
8369+
}
8370+
p.nextToken()
8371+
stmt.ExternalFileFormatOptions = append(stmt.ExternalFileFormatOptions, &ast.ExternalFileFormatLiteralOption{
8372+
OptionKind: optionKind,
8373+
Value: val,
8374+
})
8375+
}
83578376
}
83588377
}
83598378
if p.curTok.Type == TokenComma {
@@ -8400,6 +8419,35 @@ func (p *Parser) parseExternalFileFormatSuboption() ast.ExternalFileFormatOption
84008419

84018420
if p.curTok.Type == TokenEquals {
84028421
p.nextToken() // consume =
8422+
8423+
// Special handling for USE_TYPE_DEFAULT which uses ExternalFileFormatUseDefaultTypeOption
8424+
if optName == "USE_TYPE_DEFAULT" {
8425+
// Value is TRUE or FALSE (as identifier, not string)
8426+
value := strings.ToUpper(p.curTok.Literal)
8427+
defaultType := "False"
8428+
if value == "TRUE" {
8429+
defaultType = "True"
8430+
}
8431+
p.nextToken()
8432+
return &ast.ExternalFileFormatUseDefaultTypeOption{
8433+
OptionKind: optionKind,
8434+
ExternalFileFormatUseDefaultType: defaultType,
8435+
}
8436+
}
8437+
8438+
// Handle integer values for FIRST_ROW
8439+
if optName == "FIRST_ROW" {
8440+
val := &ast.IntegerLiteral{
8441+
LiteralType: "Integer",
8442+
Value: p.curTok.Literal,
8443+
}
8444+
p.nextToken()
8445+
return &ast.ExternalFileFormatLiteralOption{
8446+
OptionKind: optionKind,
8447+
Value: val,
8448+
}
8449+
}
8450+
84038451
val, _ := p.parseStringLiteral()
84048452
return &ast.ExternalFileFormatLiteralOption{
84058453
OptionKind: optionKind,
@@ -8427,6 +8475,8 @@ func (p *Parser) externalFileFormatOptionKind(name string) string {
84278475
return "DataCompression"
84288476
case "FIRST_ROW":
84298477
return "FirstRow"
8478+
case "SERDE_METHOD":
8479+
return "SerDeMethod"
84308480
default:
84318481
return name
84328482
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}

0 commit comments

Comments
 (0)