@@ -486,6 +486,8 @@ func statementToJSON(stmt ast.Statement) jsonNode {
486486 return dropSchemaStatementToJSON (s )
487487 case * ast.AlterTableTriggerModificationStatement :
488488 return alterTableTriggerModificationStatementToJSON (s )
489+ case * ast.AlterTableFileTableNamespaceStatement :
490+ return alterTableFileTableNamespaceStatementToJSON (s )
489491 case * ast.AlterTableSwitchStatement :
490492 return alterTableSwitchStatementToJSON (s )
491493 case * ast.AlterTableConstraintModificationStatement :
@@ -3621,10 +3623,24 @@ func (p *Parser) parseCreateTableStatement() (*ast.CreateTableStatement, error)
36213623 }
36223624 stmt .SchemaObjectName = name
36233625
3624- // Expect ( - if not present, be lenient
3626+ // Check for AS FILETABLE
3627+ if p .curTok .Type == TokenAs {
3628+ p .nextToken () // consume AS
3629+ if strings .ToUpper (p .curTok .Literal ) == "FILETABLE" {
3630+ stmt .AsFileTable = true
3631+ p .nextToken ()
3632+ } else if strings .ToUpper (p .curTok .Literal ) == "NODE" {
3633+ stmt .AsNode = true
3634+ p .nextToken ()
3635+ } else if strings .ToUpper (p .curTok .Literal ) == "EDGE" {
3636+ stmt .AsEdge = true
3637+ p .nextToken ()
3638+ }
3639+ }
3640+
3641+ // Check for ON, TEXTIMAGE_ON, FILESTREAM_ON, WITH clauses (for AS FILETABLE)
36253642 if p .curTok .Type != TokenLParen {
3626- p .skipToEndOfStatement ()
3627- return stmt , nil
3643+ return p .parseCreateTableOptions (stmt )
36283644 }
36293645 p .nextToken ()
36303646
@@ -3805,6 +3821,229 @@ func (p *Parser) parseCreateTableStatement() (*ast.CreateTableStatement, error)
38053821 stmt .AsEdge = true
38063822 p .nextToken ()
38073823 }
3824+ } else if upperLit == "FEDERATED" {
3825+ p .nextToken () // consume FEDERATED
3826+ // Expect ON
3827+ if p .curTok .Type == TokenOn {
3828+ p .nextToken () // consume ON
3829+ }
3830+ // Expect (
3831+ if p .curTok .Type == TokenLParen {
3832+ p .nextToken () // consume (
3833+ }
3834+ // Parse distribution_name = column_name
3835+ distributionName := p .parseIdentifier ()
3836+ if p .curTok .Type == TokenEquals {
3837+ p .nextToken () // consume =
3838+ }
3839+ columnName := p .parseIdentifier ()
3840+ stmt .FederationScheme = & ast.FederationScheme {
3841+ DistributionName : distributionName ,
3842+ ColumnName : columnName ,
3843+ }
3844+ // Expect )
3845+ if p .curTok .Type == TokenRParen {
3846+ p .nextToken () // consume )
3847+ }
3848+ } else {
3849+ break
3850+ }
3851+ }
3852+
3853+ // Skip optional semicolon
3854+ if p .curTok .Type == TokenSemicolon {
3855+ p .nextToken ()
3856+ }
3857+
3858+ return stmt , nil
3859+ }
3860+
3861+ // parseCreateTableOptions parses table options (ON, TEXTIMAGE_ON, FILESTREAM_ON, WITH) for tables without column definitions (like AS FILETABLE)
3862+ func (p * Parser ) parseCreateTableOptions (stmt * ast.CreateTableStatement ) (* ast.CreateTableStatement , error ) {
3863+ for {
3864+ upperLit := strings .ToUpper (p .curTok .Literal )
3865+ if p .curTok .Type == TokenOn {
3866+ p .nextToken () // consume ON
3867+ // Parse filegroup or partition scheme with optional columns
3868+ fg , err := p .parseFileGroupOrPartitionScheme ()
3869+ if err != nil {
3870+ return nil , err
3871+ }
3872+ stmt .OnFileGroupOrPartitionScheme = fg
3873+ } else if upperLit == "TEXTIMAGE_ON" {
3874+ p .nextToken () // consume TEXTIMAGE_ON
3875+ // Parse filegroup identifier or string literal
3876+ if p .curTok .Type == TokenString {
3877+ value := p .curTok .Literal
3878+ // Strip quotes from string literal
3879+ if len (value ) >= 2 && value [0 ] == '\'' && value [len (value )- 1 ] == '\'' {
3880+ value = value [1 : len (value )- 1 ]
3881+ }
3882+ stmt .TextImageOn = & ast.IdentifierOrValueExpression {
3883+ Value : value ,
3884+ ValueExpression : & ast.StringLiteral {
3885+ LiteralType : "String" ,
3886+ Value : value ,
3887+ },
3888+ }
3889+ p .nextToken ()
3890+ } else {
3891+ ident := p .parseIdentifier ()
3892+ stmt .TextImageOn = & ast.IdentifierOrValueExpression {
3893+ Value : ident .Value ,
3894+ Identifier : ident ,
3895+ }
3896+ }
3897+ } else if upperLit == "FILESTREAM_ON" {
3898+ p .nextToken () // consume FILESTREAM_ON
3899+ // Parse filegroup identifier or string literal
3900+ if p .curTok .Type == TokenString {
3901+ value := p .curTok .Literal
3902+ // Strip quotes from string literal
3903+ if len (value ) >= 2 && value [0 ] == '\'' && value [len (value )- 1 ] == '\'' {
3904+ value = value [1 : len (value )- 1 ]
3905+ }
3906+ stmt .FileStreamOn = & ast.IdentifierOrValueExpression {
3907+ Value : value ,
3908+ ValueExpression : & ast.StringLiteral {
3909+ LiteralType : "String" ,
3910+ Value : value ,
3911+ },
3912+ }
3913+ p .nextToken ()
3914+ } else {
3915+ ident := p .parseIdentifier ()
3916+ stmt .FileStreamOn = & ast.IdentifierOrValueExpression {
3917+ Value : ident .Value ,
3918+ Identifier : ident ,
3919+ }
3920+ }
3921+ } else if p .curTok .Type == TokenWith {
3922+ // Parse WITH clause with table options
3923+ p .nextToken () // consume WITH
3924+ if p .curTok .Type == TokenLParen {
3925+ p .nextToken () // consume (
3926+ // Parse table options
3927+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
3928+ optionName := strings .ToUpper (p .curTok .Literal )
3929+ p .nextToken () // consume option name
3930+
3931+ if optionName == "DATA_COMPRESSION" {
3932+ if p .curTok .Type == TokenEquals {
3933+ p .nextToken () // consume =
3934+ }
3935+ opt , err := p .parseDataCompressionOption ()
3936+ if err != nil {
3937+ break
3938+ }
3939+ stmt .Options = append (stmt .Options , & ast.TableDataCompressionOption {
3940+ DataCompressionOption : opt ,
3941+ OptionKind : "DataCompression" ,
3942+ })
3943+ } else if optionName == "FILETABLE_DIRECTORY" {
3944+ if p .curTok .Type == TokenEquals {
3945+ p .nextToken () // consume =
3946+ }
3947+ // Parse the directory name as a literal or NULL
3948+ opt := & ast.FileTableDirectoryTableOption {
3949+ OptionKind : "FileTableDirectory" ,
3950+ }
3951+ if strings .ToUpper (p .curTok .Literal ) == "NULL" {
3952+ opt .Value = & ast.NullLiteral {
3953+ LiteralType : "Null" ,
3954+ Value : "NULL" ,
3955+ }
3956+ p .nextToken ()
3957+ } else if p .curTok .Type == TokenString {
3958+ value := p .curTok .Literal
3959+ if len (value ) >= 2 && value [0 ] == '\'' && value [len (value )- 1 ] == '\'' {
3960+ value = value [1 : len (value )- 1 ]
3961+ }
3962+ opt .Value = & ast.StringLiteral {
3963+ LiteralType : "String" ,
3964+ Value : value ,
3965+ IsNational : false ,
3966+ IsLargeObject : false ,
3967+ }
3968+ p .nextToken ()
3969+ } else {
3970+ value := p .curTok .Literal
3971+ opt .Value = & ast.StringLiteral {
3972+ LiteralType : "String" ,
3973+ Value : value ,
3974+ IsNational : false ,
3975+ IsLargeObject : false ,
3976+ }
3977+ p .nextToken ()
3978+ }
3979+ stmt .Options = append (stmt .Options , opt )
3980+ } else if optionName == "FILETABLE_COLLATE_FILENAME" {
3981+ if p .curTok .Type == TokenEquals {
3982+ p .nextToken () // consume =
3983+ }
3984+ // Parse the collation name as an identifier
3985+ collationName := p .parseIdentifier ()
3986+ stmt .Options = append (stmt .Options , & ast.FileTableCollateFileNameTableOption {
3987+ OptionKind : "FileTableCollateFileName" ,
3988+ Value : collationName ,
3989+ })
3990+ } else if optionName == "MEMORY_OPTIMIZED" {
3991+ if p .curTok .Type == TokenEquals {
3992+ p .nextToken () // consume =
3993+ }
3994+ stateUpper := strings .ToUpper (p .curTok .Literal )
3995+ state := "On"
3996+ if stateUpper == "OFF" {
3997+ state = "Off"
3998+ }
3999+ p .nextToken () // consume ON/OFF
4000+ stmt .Options = append (stmt .Options , & ast.MemoryOptimizedTableOption {
4001+ OptionKind : "MemoryOptimized" ,
4002+ OptionState : state ,
4003+ })
4004+ } else if optionName == "FILETABLE_PRIMARY_KEY_CONSTRAINT_NAME" {
4005+ if p .curTok .Type == TokenEquals {
4006+ p .nextToken () // consume =
4007+ }
4008+ constraintName := p .parseIdentifier ()
4009+ stmt .Options = append (stmt .Options , & ast.FileTableConstraintNameTableOption {
4010+ OptionKind : "FileTablePrimaryKeyConstraintName" ,
4011+ Value : constraintName ,
4012+ })
4013+ } else if optionName == "FILETABLE_STREAMID_UNIQUE_CONSTRAINT_NAME" {
4014+ if p .curTok .Type == TokenEquals {
4015+ p .nextToken () // consume =
4016+ }
4017+ constraintName := p .parseIdentifier ()
4018+ stmt .Options = append (stmt .Options , & ast.FileTableConstraintNameTableOption {
4019+ OptionKind : "FileTableStreamIdUniqueConstraintName" ,
4020+ Value : constraintName ,
4021+ })
4022+ } else if optionName == "FILETABLE_FULLPATH_UNIQUE_CONSTRAINT_NAME" {
4023+ if p .curTok .Type == TokenEquals {
4024+ p .nextToken () // consume =
4025+ }
4026+ constraintName := p .parseIdentifier ()
4027+ stmt .Options = append (stmt .Options , & ast.FileTableConstraintNameTableOption {
4028+ OptionKind : "FileTableFullPathUniqueConstraintName" ,
4029+ Value : constraintName ,
4030+ })
4031+ } else {
4032+ // Skip unknown option value
4033+ if p .curTok .Type == TokenEquals {
4034+ p .nextToken ()
4035+ }
4036+ p .nextToken ()
4037+ }
4038+
4039+ if p .curTok .Type == TokenComma {
4040+ p .nextToken ()
4041+ }
4042+ }
4043+ if p .curTok .Type == TokenRParen {
4044+ p .nextToken ()
4045+ }
4046+ }
38084047 } else {
38094048 break
38104049 }
@@ -5794,6 +6033,22 @@ func createTableStatementToJSON(s *ast.CreateTableStatement) jsonNode {
57946033 }
57956034 node ["Options" ] = opts
57966035 }
6036+ if s .FederationScheme != nil {
6037+ node ["FederationScheme" ] = federationSchemeToJSON (s .FederationScheme )
6038+ }
6039+ return node
6040+ }
6041+
6042+ func federationSchemeToJSON (fs * ast.FederationScheme ) jsonNode {
6043+ node := jsonNode {
6044+ "$type" : "FederationScheme" ,
6045+ }
6046+ if fs .DistributionName != nil {
6047+ node ["DistributionName" ] = identifierToJSON (fs .DistributionName )
6048+ }
6049+ if fs .ColumnName != nil {
6050+ node ["ColumnName" ] = identifierToJSON (fs .ColumnName )
6051+ }
57976052 return node
57986053}
57996054
@@ -5816,6 +6071,33 @@ func tableOptionToJSON(opt ast.TableOption) jsonNode {
58166071 "OptionKind" : o .OptionKind ,
58176072 "OptionState" : o .OptionState ,
58186073 }
6074+ case * ast.FileTableDirectoryTableOption :
6075+ node := jsonNode {
6076+ "$type" : "FileTableDirectoryTableOption" ,
6077+ "OptionKind" : o .OptionKind ,
6078+ }
6079+ if o .Value != nil {
6080+ node ["Value" ] = scalarExpressionToJSON (o .Value )
6081+ }
6082+ return node
6083+ case * ast.FileTableCollateFileNameTableOption :
6084+ node := jsonNode {
6085+ "$type" : "FileTableCollateFileNameTableOption" ,
6086+ "OptionKind" : o .OptionKind ,
6087+ }
6088+ if o .Value != nil {
6089+ node ["Value" ] = identifierToJSON (o .Value )
6090+ }
6091+ return node
6092+ case * ast.FileTableConstraintNameTableOption :
6093+ node := jsonNode {
6094+ "$type" : "FileTableConstraintNameTableOption" ,
6095+ "OptionKind" : o .OptionKind ,
6096+ }
6097+ if o .Value != nil {
6098+ node ["Value" ] = identifierToJSON (o .Value )
6099+ }
6100+ return node
58196101 default :
58206102 return jsonNode {"$type" : "UnknownTableOption" }
58216103 }
@@ -11922,6 +12204,17 @@ func alterTableTriggerModificationStatementToJSON(s *ast.AlterTableTriggerModifi
1192212204 return node
1192312205}
1192412206
12207+ func alterTableFileTableNamespaceStatementToJSON (s * ast.AlterTableFileTableNamespaceStatement ) jsonNode {
12208+ node := jsonNode {
12209+ "$type" : "AlterTableFileTableNamespaceStatement" ,
12210+ "IsEnable" : s .IsEnable ,
12211+ }
12212+ if s .SchemaObjectName != nil {
12213+ node ["SchemaObjectName" ] = schemaObjectNameToJSON (s .SchemaObjectName )
12214+ }
12215+ return node
12216+ }
12217+
1192512218func alterTableSwitchStatementToJSON (s * ast.AlterTableSwitchStatement ) jsonNode {
1192612219 node := jsonNode {
1192712220 "$type" : "AlterTableSwitchStatement" ,
0 commit comments