Skip to content

Commit c7223cb

Browse files
committed
Add WHERE clause and WITH options support for CREATE COLUMNSTORE INDEX
- Add CompressionDelayIndexOption and OrderIndexOption AST types - Change FilterClause from ScalarExpression to BooleanExpression - Parse WHERE clause for filtered columnstore indexes - Parse WITH clause with COMPRESSION_DELAY, SORT_IN_TEMPDB, ORDER options - Parse ORDER clause for Azure Synapse/DW syntax (directly after ON table) - Add JSON marshaling for columnstore index options - Enable Baselines130_CreateColumnStoreIndexTests130 and CreateColumnStoreIndexTests130
1 parent 7e842a8 commit c7223cb

5 files changed

Lines changed: 171 additions & 15 deletions

File tree

ast/alter_table_alter_index_statement.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,22 @@ type IndexExpressionOption struct {
3434

3535
func (i *IndexExpressionOption) indexOption() {}
3636
func (i *IndexExpressionOption) node() {}
37+
38+
// CompressionDelayIndexOption represents a COMPRESSION_DELAY option
39+
type CompressionDelayIndexOption struct {
40+
Expression ScalarExpression
41+
TimeUnit string // "Unitless", "Minute", "Minutes"
42+
OptionKind string // "CompressionDelay"
43+
}
44+
45+
func (c *CompressionDelayIndexOption) indexOption() {}
46+
func (c *CompressionDelayIndexOption) node() {}
47+
48+
// OrderIndexOption represents an ORDER option for clustered columnstore indexes
49+
type OrderIndexOption struct {
50+
Columns []*ColumnReferenceExpression
51+
OptionKind string // "Order"
52+
}
53+
54+
func (o *OrderIndexOption) indexOption() {}
55+
func (o *OrderIndexOption) node() {}

ast/create_columnstore_index_statement.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type CreateColumnStoreIndexStatement struct {
99
Columns []*ColumnReferenceExpression
1010
OrderedColumns []*ColumnReferenceExpression
1111
IndexOptions []IndexOption
12-
FilterClause ScalarExpression
12+
FilterClause BooleanExpression
1313
OnPartition *PartitionSpecifier
1414
}
1515

parser/marshal.go

Lines changed: 149 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5759,8 +5759,8 @@ func (p *Parser) parseCreateColumnStoreIndexStatement() (*ast.CreateColumnStoreI
57595759
}
57605760
}
57615761

5762-
// Parse optional ORDER clause
5763-
if strings.ToUpper(p.curTok.Literal) == "ORDER" {
5762+
// Parse optional ORDER clause (Azure Synapse/DW syntax - ORDER directly after ON table)
5763+
if p.curTok.Type == TokenOrder || strings.ToUpper(p.curTok.Literal) == "ORDER" {
57645764
p.nextToken() // consume ORDER
57655765
if p.curTok.Type == TokenLParen {
57665766
p.nextToken() // consume (
@@ -5786,19 +5786,110 @@ func (p *Parser) parseCreateColumnStoreIndexStatement() (*ast.CreateColumnStoreI
57865786
}
57875787
}
57885788

5789-
// Skip optional WITH clause for now
5789+
// Parse optional WHERE clause (filtered index)
5790+
if p.curTok.Type == TokenWhere {
5791+
p.nextToken() // consume WHERE
5792+
pred, err := p.parseBooleanExpression()
5793+
if err != nil {
5794+
return nil, err
5795+
}
5796+
stmt.FilterClause = pred
5797+
}
5798+
5799+
// Parse optional WITH clause
57905800
if p.curTok.Type == TokenWith {
5791-
// TODO: parse WITH options
5792-
p.nextToken()
5801+
p.nextToken() // consume WITH
57935802
if p.curTok.Type == TokenLParen {
5794-
p.nextToken()
5795-
depth := 1
5796-
for depth > 0 && p.curTok.Type != TokenEOF {
5797-
if p.curTok.Type == TokenLParen {
5798-
depth++
5799-
} else if p.curTok.Type == TokenRParen {
5800-
depth--
5803+
p.nextToken() // consume (
5804+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
5805+
if p.curTok.Type == TokenComma {
5806+
p.nextToken()
5807+
continue
58015808
}
5809+
5810+
optName := strings.ToUpper(p.curTok.Literal)
5811+
switch optName {
5812+
case "COMPRESSION_DELAY":
5813+
p.nextToken() // consume COMPRESSION_DELAY
5814+
if p.curTok.Type == TokenEquals {
5815+
p.nextToken() // consume =
5816+
}
5817+
expr, err := p.parseScalarExpression()
5818+
if err != nil {
5819+
return nil, err
5820+
}
5821+
opt := &ast.CompressionDelayIndexOption{
5822+
Expression: expr,
5823+
TimeUnit: "Unitless",
5824+
OptionKind: "CompressionDelay",
5825+
}
5826+
// Check for MINUTE/MINUTES
5827+
if strings.ToUpper(p.curTok.Literal) == "MINUTE" {
5828+
opt.TimeUnit = "Minute"
5829+
p.nextToken()
5830+
} else if strings.ToUpper(p.curTok.Literal) == "MINUTES" {
5831+
opt.TimeUnit = "Minutes"
5832+
p.nextToken()
5833+
}
5834+
stmt.IndexOptions = append(stmt.IndexOptions, opt)
5835+
5836+
case "SORT_IN_TEMPDB":
5837+
p.nextToken() // consume SORT_IN_TEMPDB
5838+
if p.curTok.Type == TokenEquals {
5839+
p.nextToken() // consume =
5840+
}
5841+
state := "NotSet"
5842+
if p.curTok.Type == TokenOn {
5843+
state = "On"
5844+
p.nextToken()
5845+
} else if strings.ToUpper(p.curTok.Literal) == "OFF" {
5846+
state = "Off"
5847+
p.nextToken()
5848+
}
5849+
stmt.IndexOptions = append(stmt.IndexOptions, &ast.IndexStateOption{
5850+
OptionKind: "SortInTempDB",
5851+
OptionState: state,
5852+
})
5853+
5854+
case "ORDER":
5855+
p.nextToken() // consume ORDER
5856+
if p.curTok.Type == TokenLParen {
5857+
p.nextToken() // consume (
5858+
orderOpt := &ast.OrderIndexOption{
5859+
OptionKind: "Order",
5860+
}
5861+
for p.curTok.Type != TokenRParen && p.curTok.Type != TokenEOF {
5862+
colRef := &ast.ColumnReferenceExpression{
5863+
ColumnType: "Regular",
5864+
MultiPartIdentifier: &ast.MultiPartIdentifier{
5865+
Identifiers: []*ast.Identifier{p.parseIdentifier()},
5866+
},
5867+
}
5868+
colRef.MultiPartIdentifier.Count = len(colRef.MultiPartIdentifier.Identifiers)
5869+
orderOpt.Columns = append(orderOpt.Columns, colRef)
5870+
5871+
if p.curTok.Type == TokenComma {
5872+
p.nextToken()
5873+
} else {
5874+
break
5875+
}
5876+
}
5877+
if p.curTok.Type == TokenRParen {
5878+
p.nextToken()
5879+
}
5880+
stmt.IndexOptions = append(stmt.IndexOptions, orderOpt)
5881+
}
5882+
5883+
default:
5884+
// Skip unknown options
5885+
p.nextToken()
5886+
if p.curTok.Type == TokenEquals {
5887+
p.nextToken()
5888+
p.nextToken() // skip value
5889+
}
5890+
}
5891+
}
5892+
if p.curTok.Type == TokenRParen {
58025893
p.nextToken()
58035894
}
58045895
}
@@ -6887,6 +6978,16 @@ func createColumnStoreIndexStatementToJSON(s *ast.CreateColumnStoreIndexStatemen
68876978
}
68886979
node["Columns"] = cols
68896980
}
6981+
if s.FilterClause != nil {
6982+
node["FilterPredicate"] = booleanExpressionToJSON(s.FilterClause)
6983+
}
6984+
if len(s.IndexOptions) > 0 {
6985+
opts := make([]jsonNode, len(s.IndexOptions))
6986+
for i, opt := range s.IndexOptions {
6987+
opts[i] = columnStoreIndexOptionToJSON(opt)
6988+
}
6989+
node["IndexOptions"] = opts
6990+
}
68906991
if len(s.OrderedColumns) > 0 {
68916992
cols := make([]jsonNode, len(s.OrderedColumns))
68926993
for i, col := range s.OrderedColumns {
@@ -6897,6 +6998,42 @@ func createColumnStoreIndexStatementToJSON(s *ast.CreateColumnStoreIndexStatemen
68976998
return node
68986999
}
68997000

7001+
func columnStoreIndexOptionToJSON(opt ast.IndexOption) jsonNode {
7002+
switch o := opt.(type) {
7003+
case *ast.CompressionDelayIndexOption:
7004+
node := jsonNode{
7005+
"$type": "CompressionDelayIndexOption",
7006+
"OptionKind": o.OptionKind,
7007+
"TimeUnit": o.TimeUnit,
7008+
}
7009+
if o.Expression != nil {
7010+
node["Expression"] = scalarExpressionToJSON(o.Expression)
7011+
}
7012+
return node
7013+
case *ast.OrderIndexOption:
7014+
node := jsonNode{
7015+
"$type": "OrderIndexOption",
7016+
"OptionKind": o.OptionKind,
7017+
}
7018+
if len(o.Columns) > 0 {
7019+
cols := make([]jsonNode, len(o.Columns))
7020+
for i, col := range o.Columns {
7021+
cols[i] = columnReferenceExpressionToJSON(col)
7022+
}
7023+
node["Columns"] = cols
7024+
}
7025+
return node
7026+
case *ast.IndexStateOption:
7027+
return jsonNode{
7028+
"$type": "IndexStateOption",
7029+
"OptionKind": o.OptionKind,
7030+
"OptionState": o.OptionState,
7031+
}
7032+
default:
7033+
return jsonNode{"$type": "UnknownIndexOption"}
7034+
}
7035+
}
7036+
69007037
func createSpatialIndexStatementToJSON(s *ast.CreateSpatialIndexStatement) jsonNode {
69017038
node := jsonNode{
69027039
"$type": "CreateSpatialIndexStatement",
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)