@@ -4248,19 +4248,44 @@ func (p *Parser) parseCreateExternalFileFormatStatement() (*ast.CreateExternalFi
42484248 p .nextToken () // consume (
42494249
42504250 for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
4251- opt := & ast.ExternalFileFormatOption {
4252- OptionKind : p .curTok .Literal ,
4253- }
4251+ optName := strings .ToUpper (p .curTok .Literal )
42544252 p .nextToken () // consume option name
4255- if p .curTok .Type == TokenEquals {
4256- p .nextToken ()
4257- val , err := p .parseScalarExpression ()
4258- if err != nil {
4259- return nil , err
4253+
4254+ if optName == "FORMAT_TYPE" {
4255+ if p .curTok .Type == TokenEquals {
4256+ p .nextToken () // consume =
4257+ }
4258+ // Parse format type value and convert to PascalCase
4259+ stmt .FormatType = p .formatTypeToPascalCase (p .curTok .Literal )
4260+ p .nextToken () // consume value
4261+ } else if optName == "FORMAT_OPTIONS" {
4262+ // Parse container option with suboptions
4263+ opt := & ast.ExternalFileFormatContainerOption {
4264+ OptionKind : "FormatOptions" ,
4265+ }
4266+ if p .curTok .Type == TokenLParen {
4267+ p .nextToken () // consume (
4268+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
4269+ subOpt := p .parseExternalFileFormatSuboption ()
4270+ if subOpt != nil {
4271+ opt .Suboptions = append (opt .Suboptions , subOpt )
4272+ }
4273+ if p .curTok .Type == TokenComma {
4274+ p .nextToken ()
4275+ }
4276+ }
4277+ if p .curTok .Type == TokenRParen {
4278+ p .nextToken () // consume )
4279+ }
4280+ }
4281+ stmt .ExternalFileFormatOptions = append (stmt .ExternalFileFormatOptions , opt )
4282+ } else {
4283+ // Skip other options for now
4284+ if p .curTok .Type == TokenEquals {
4285+ p .nextToken () // consume =
4286+ p .nextToken () // consume value
42604287 }
4261- opt .Value = val
42624288 }
4263- stmt .Options = append (stmt .Options , opt )
42644289 if p .curTok .Type == TokenComma {
42654290 p .nextToken ()
42664291 }
@@ -4276,6 +4301,67 @@ func (p *Parser) parseCreateExternalFileFormatStatement() (*ast.CreateExternalFi
42764301 return stmt , nil
42774302}
42784303
4304+ func (p * Parser ) formatTypeToPascalCase (s string ) string {
4305+ upper := strings .ToUpper (s )
4306+ switch upper {
4307+ case "DELTA" :
4308+ return "Delta"
4309+ case "DELIMITEDTEXT" :
4310+ return "DelimitedText"
4311+ case "PARQUET" :
4312+ return "Parquet"
4313+ case "ORC" :
4314+ return "Orc"
4315+ case "RCFILE" :
4316+ return "RcFile"
4317+ case "JSON" :
4318+ return "Json"
4319+ default :
4320+ return s
4321+ }
4322+ }
4323+
4324+ func (p * Parser ) parseExternalFileFormatSuboption () ast.ExternalFileFormatOption {
4325+ optName := strings .ToUpper (p .curTok .Literal )
4326+ p .nextToken () // consume option name
4327+
4328+ // Map to option kind
4329+ optionKind := p .externalFileFormatOptionKind (optName )
4330+
4331+ if p .curTok .Type == TokenEquals {
4332+ p .nextToken () // consume =
4333+ val , _ := p .parseStringLiteral ()
4334+ return & ast.ExternalFileFormatLiteralOption {
4335+ OptionKind : optionKind ,
4336+ Value : val ,
4337+ }
4338+ }
4339+ return nil
4340+ }
4341+
4342+ func (p * Parser ) externalFileFormatOptionKind (name string ) string {
4343+ switch strings .ToUpper (name ) {
4344+ case "PARSER_VERSION" :
4345+ return "ParserVersion"
4346+ case "FIELD_TERMINATOR" :
4347+ return "FieldTerminator"
4348+ case "STRING_DELIMITER" :
4349+ return "StringDelimiter"
4350+ case "DATE_FORMAT" :
4351+ return "DateFormat"
4352+ case "USE_TYPE_DEFAULT" :
4353+ return "UseTypeDefault"
4354+ case "ENCODING" :
4355+ return "Encoding"
4356+ case "DATA_COMPRESSION" :
4357+ return "DataCompression"
4358+ case "FIRST_ROW" :
4359+ return "FirstRow"
4360+ default :
4361+ return name
4362+ }
4363+ }
4364+
42794365func (p * Parser ) parseCreateExternalTableStatement () (* ast.CreateExternalTableStatement , error ) {
42804366 // TABLE name - skip rest of statement for now
42814367 p .nextToken () // consume TABLE
0 commit comments