@@ -4555,6 +4555,95 @@ func (p *Parser) parseCreateTableStatement() (*ast.CreateTableStatement, error)
45554555 return nil , err
45564556 }
45574557 stmt .Options = append (stmt .Options , opt )
4558+ } else if optionName == "CLUSTERED" {
4559+ // Could be CLUSTERED INDEX or CLUSTERED COLUMNSTORE INDEX
4560+ if strings .ToUpper (p .curTok .Literal ) == "COLUMNSTORE" {
4561+ p .nextToken () // consume COLUMNSTORE
4562+ if p .curTok .Type == TokenIndex {
4563+ p .nextToken () // consume INDEX
4564+ }
4565+ stmt .Options = append (stmt .Options , & ast.TableIndexOption {
4566+ Value : & ast.TableClusteredIndexType {
4567+ ColumnStore : true ,
4568+ },
4569+ OptionKind : "LockEscalation" ,
4570+ })
4571+ } else if p .curTok .Type == TokenIndex {
4572+ p .nextToken () // consume INDEX
4573+ // Parse column list
4574+ indexType := & ast.TableClusteredIndexType {
4575+ ColumnStore : false ,
4576+ }
4577+ if p .curTok .Type == TokenLParen {
4578+ p .nextToken () // consume (
4579+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
4580+ col := & ast.ColumnWithSortOrder {
4581+ SortOrder : ast .SortOrderNotSpecified ,
4582+ Column : & ast.ColumnReferenceExpression {
4583+ ColumnType : "Regular" ,
4584+ MultiPartIdentifier : & ast.MultiPartIdentifier {
4585+ Identifiers : []* ast.Identifier {p .parseIdentifier ()},
4586+ Count : 1 ,
4587+ },
4588+ },
4589+ }
4590+ indexType .Columns = append (indexType .Columns , col )
4591+ if p .curTok .Type == TokenComma {
4592+ p .nextToken ()
4593+ } else {
4594+ break
4595+ }
4596+ }
4597+ if p .curTok .Type == TokenRParen {
4598+ p .nextToken ()
4599+ }
4600+ }
4601+ stmt .Options = append (stmt .Options , & ast.TableIndexOption {
4602+ Value : indexType ,
4603+ OptionKind : "LockEscalation" ,
4604+ })
4605+ }
4606+ } else if optionName == "HEAP" {
4607+ stmt .Options = append (stmt .Options , & ast.TableIndexOption {
4608+ Value : & ast.TableNonClusteredIndexType {},
4609+ OptionKind : "LockEscalation" ,
4610+ })
4611+ } else if optionName == "DISTRIBUTION" {
4612+ // Parse DISTRIBUTION = HASH(col1, col2, ...) or ROUND_ROBIN or REPLICATE
4613+ if p .curTok .Type == TokenEquals {
4614+ p .nextToken () // consume =
4615+ }
4616+ distTypeUpper := strings .ToUpper (p .curTok .Literal )
4617+ if distTypeUpper == "HASH" {
4618+ p .nextToken () // consume HASH
4619+ if p .curTok .Type == TokenLParen {
4620+ p .nextToken () // consume (
4621+ distOpt := & ast.TableDistributionOption {
4622+ OptionKind : "Distribution" ,
4623+ Value : & ast.TableHashDistributionPolicy {},
4624+ }
4625+ // Parse column list
4626+ for p .curTok .Type != TokenRParen && p .curTok .Type != TokenEOF {
4627+ col := p .parseIdentifier ()
4628+ if distOpt .Value .DistributionColumn == nil {
4629+ distOpt .Value .DistributionColumn = col
4630+ }
4631+ distOpt .Value .DistributionColumns = append (distOpt .Value .DistributionColumns , col )
4632+ if p .curTok .Type == TokenComma {
4633+ p .nextToken ()
4634+ } else {
4635+ break
4636+ }
4637+ }
4638+ if p .curTok .Type == TokenRParen {
4639+ p .nextToken ()
4640+ }
4641+ stmt .Options = append (stmt .Options , distOpt )
4642+ }
4643+ } else {
4644+ // ROUND_ROBIN or REPLICATE - skip for now
4645+ p .nextToken ()
4646+ }
45584647 } else {
45594648 // Skip unknown option value
45604649 if p .curTok .Type == TokenEquals {
@@ -7423,6 +7512,24 @@ func tableOptionToJSON(opt ast.TableOption) jsonNode {
74237512 node ["XmlCompressionOption" ] = xmlCompressionOptionToJSON (o .XmlCompressionOption )
74247513 }
74257514 return node
7515+ case * ast.TableIndexOption :
7516+ node := jsonNode {
7517+ "$type" : "TableIndexOption" ,
7518+ "OptionKind" : o .OptionKind ,
7519+ }
7520+ if o .Value != nil {
7521+ node ["Value" ] = tableIndexTypeToJSON (o .Value )
7522+ }
7523+ return node
7524+ case * ast.TableDistributionOption :
7525+ node := jsonNode {
7526+ "$type" : "TableDistributionOption" ,
7527+ "OptionKind" : o .OptionKind ,
7528+ }
7529+ if o .Value != nil {
7530+ node ["Value" ] = tableHashDistributionPolicyToJSON (o .Value )
7531+ }
7532+ return node
74267533 case * ast.SystemVersioningTableOption :
74277534 return systemVersioningTableOptionToJSON (o )
74287535 case * ast.MemoryOptimizedTableOption :
@@ -7540,6 +7647,52 @@ func xmlCompressionOptionToJSON(opt *ast.XmlCompressionOption) jsonNode {
75407647 return node
75417648}
75427649
7650+ func tableHashDistributionPolicyToJSON (policy * ast.TableHashDistributionPolicy ) jsonNode {
7651+ node := jsonNode {
7652+ "$type" : "TableHashDistributionPolicy" ,
7653+ }
7654+ if policy .DistributionColumn != nil {
7655+ node ["DistributionColumn" ] = identifierToJSON (policy .DistributionColumn )
7656+ }
7657+ if len (policy .DistributionColumns ) > 0 {
7658+ cols := make ([]jsonNode , len (policy .DistributionColumns ))
7659+ for i , c := range policy .DistributionColumns {
7660+ // First column is same as DistributionColumn, use $ref
7661+ if i == 0 && policy .DistributionColumn != nil {
7662+ cols [i ] = jsonNode {"$ref" : "Identifier" }
7663+ } else {
7664+ cols [i ] = identifierToJSON (c )
7665+ }
7666+ }
7667+ node ["DistributionColumns" ] = cols
7668+ }
7669+ return node
7670+ }
7671+
7672+ func tableIndexTypeToJSON (t ast.TableIndexType ) jsonNode {
7673+ switch v := t .(type ) {
7674+ case * ast.TableClusteredIndexType :
7675+ node := jsonNode {
7676+ "$type" : "TableClusteredIndexType" ,
7677+ "ColumnStore" : v .ColumnStore ,
7678+ }
7679+ if len (v .Columns ) > 0 {
7680+ cols := make ([]jsonNode , len (v .Columns ))
7681+ for i , c := range v .Columns {
7682+ cols [i ] = columnWithSortOrderToJSON (c )
7683+ }
7684+ node ["Columns" ] = cols
7685+ }
7686+ return node
7687+ case * ast.TableNonClusteredIndexType :
7688+ return jsonNode {
7689+ "$type" : "TableNonClusteredIndexType" ,
7690+ }
7691+ default :
7692+ return jsonNode {"$type" : "UnknownTableIndexType" }
7693+ }
7694+ }
7695+
75437696func compressionPartitionRangeToJSON (pr * ast.CompressionPartitionRange ) jsonNode {
75447697 node := jsonNode {
75457698 "$type" : "CompressionPartitionRange" ,
0 commit comments