Skip to content

Commit c86de0b

Browse files
committed
Add parser features and enable 12 more tests
Add support for: - Cursor statements (OPEN, CLOSE, FETCH, DEALLOCATE) - DECLARE CURSOR statement - UPDATE STATISTICS statement with options - CREATE STATISTICS with columns and options - ALTER DATABASE autogrow options (AUTOGROW_ALL_FILES, AUTOGROW_SINGLE_FILE) Enabled tests: - AlterDatabaseStatementTests130 - Baselines130_AlterDatabaseStatementTests130 - BaselinesCommon_BigIntRowCountPageCountTests - BigIntRowCountPageCountTests - BaselinesCommon_CreateStatisticsStatementTests - CreateStatisticsStatementTests - BaselinesCommon_CursorStatementsTests - CursorStatementsTests - BaselinesCommon_DeclareCursorStatementTests - DeclareCursorStatementTests - BaselinesCommon_UpdateStatisticsStatementTests - UpdateStatisticsStatementTests
1 parent 5df3fae commit c86de0b

File tree

21 files changed

+955
-19
lines changed

21 files changed

+955
-19
lines changed

ast/create_simple_statements.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,11 @@ func (s *CreateIndexStatement) statement() {}
150150

151151
// CreateStatisticsStatement represents a CREATE STATISTICS statement.
152152
type CreateStatisticsStatement struct {
153-
Name *Identifier `json:"Name,omitempty"`
154-
OnName *SchemaObjectName `json:"OnName,omitempty"`
153+
Name *Identifier `json:"Name,omitempty"`
154+
OnName *SchemaObjectName `json:"OnName,omitempty"`
155+
Columns []*ColumnReferenceExpression `json:"Columns,omitempty"`
156+
StatisticsOptions []StatisticsOption `json:"StatisticsOptions,omitempty"`
157+
FilterPredicate BooleanExpression `json:"FilterPredicate,omitempty"`
155158
}
156159

157160
func (s *CreateStatisticsStatement) node() {}

ast/cursor_statements.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package ast
2+
3+
// FetchType represents the orientation for a FETCH statement.
4+
type FetchType struct {
5+
Orientation string `json:"Orientation,omitempty"`
6+
RowOffset ScalarExpression `json:"RowOffset,omitempty"`
7+
}
8+
9+
// DeclareCursorStatement represents DECLARE cursor_name CURSOR FOR SELECT.
10+
type DeclareCursorStatement struct {
11+
Name *Identifier `json:"Name,omitempty"`
12+
CursorDefinition *CursorDefinition `json:"CursorDefinition,omitempty"`
13+
}
14+
15+
func (s *DeclareCursorStatement) node() {}
16+
func (s *DeclareCursorStatement) statement() {}
17+
18+
// OpenCursorStatement represents OPEN cursor_name.
19+
type OpenCursorStatement struct {
20+
Cursor *CursorId `json:"Cursor,omitempty"`
21+
}
22+
23+
func (s *OpenCursorStatement) node() {}
24+
func (s *OpenCursorStatement) statement() {}
25+
26+
// CloseCursorStatement represents CLOSE cursor_name.
27+
type CloseCursorStatement struct {
28+
Cursor *CursorId `json:"Cursor,omitempty"`
29+
}
30+
31+
func (s *CloseCursorStatement) node() {}
32+
func (s *CloseCursorStatement) statement() {}
33+
34+
// DeallocateCursorStatement represents DEALLOCATE cursor_name.
35+
type DeallocateCursorStatement struct {
36+
Cursor *CursorId `json:"Cursor,omitempty"`
37+
}
38+
39+
func (s *DeallocateCursorStatement) node() {}
40+
func (s *DeallocateCursorStatement) statement() {}
41+
42+
// FetchCursorStatement represents FETCH cursor_name.
43+
type FetchCursorStatement struct {
44+
FetchType *FetchType `json:"FetchType,omitempty"`
45+
Cursor *CursorId `json:"Cursor,omitempty"`
46+
IntoVariables []ScalarExpression `json:"IntoVariables,omitempty"`
47+
}
48+
49+
func (s *FetchCursorStatement) node() {}
50+
func (s *FetchCursorStatement) statement() {}

ast/update_statistics_statement.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package ast
2+
3+
// UpdateStatisticsStatement represents UPDATE STATISTICS.
4+
type UpdateStatisticsStatement struct {
5+
SchemaObjectName *SchemaObjectName `json:"SchemaObjectName,omitempty"`
6+
SubElements []*Identifier `json:"SubElements,omitempty"`
7+
StatisticsOptions []StatisticsOption `json:"StatisticsOptions,omitempty"`
8+
}
9+
10+
func (u *UpdateStatisticsStatement) node() {}
11+
func (u *UpdateStatisticsStatement) statement() {}
12+
13+
// StatisticsOption is an interface for statistics options.
14+
type StatisticsOption interface {
15+
statisticsOption()
16+
}
17+
18+
// SimpleStatisticsOption represents a simple statistics option like ALL, FULLSCAN, etc.
19+
type SimpleStatisticsOption struct {
20+
OptionKind string `json:"OptionKind,omitempty"`
21+
}
22+
23+
func (s *SimpleStatisticsOption) statisticsOption() {}
24+
25+
// LiteralStatisticsOption represents a statistics option with a literal value.
26+
type LiteralStatisticsOption struct {
27+
OptionKind string `json:"OptionKind,omitempty"`
28+
Literal ScalarExpression `json:"Literal,omitempty"`
29+
}
30+
31+
func (l *LiteralStatisticsOption) statisticsOption() {}
32+
33+
// OnOffStatisticsOption represents a statistics option with ON/OFF value.
34+
type OnOffStatisticsOption struct {
35+
OptionKind string `json:"OptionKind,omitempty"`
36+
OptionState string `json:"OptionState,omitempty"`
37+
}
38+
39+
func (o *OnOffStatisticsOption) statisticsOption() {}
40+
41+
// ResampleStatisticsOption represents RESAMPLE statistics option.
42+
type ResampleStatisticsOption struct {
43+
OptionKind string `json:"OptionKind,omitempty"`
44+
Partitions []ScalarExpression `json:"Partitions,omitempty"`
45+
}
46+
47+
func (r *ResampleStatisticsOption) statisticsOption() {}

parser/marshal.go

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ func statementToJSON(stmt ast.Statement) jsonNode {
5454
return insertStatementToJSON(s)
5555
case *ast.UpdateStatement:
5656
return updateStatementToJSON(s)
57+
case *ast.UpdateStatisticsStatement:
58+
return updateStatisticsStatementToJSON(s)
5759
case *ast.DeleteStatement:
5860
return deleteStatementToJSON(s)
5961
case *ast.DeclareVariableStatement:
@@ -430,6 +432,16 @@ func statementToJSON(stmt ast.Statement) jsonNode {
430432
return alterServiceMasterKeyStatementToJSON(s)
431433
case *ast.RenameEntityStatement:
432434
return renameEntityStatementToJSON(s)
435+
case *ast.OpenCursorStatement:
436+
return openCursorStatementToJSON(s)
437+
case *ast.CloseCursorStatement:
438+
return closeCursorStatementToJSON(s)
439+
case *ast.DeallocateCursorStatement:
440+
return deallocateCursorStatementToJSON(s)
441+
case *ast.FetchCursorStatement:
442+
return fetchCursorStatementToJSON(s)
443+
case *ast.DeclareCursorStatement:
444+
return declareCursorStatementToJSON(s)
433445
default:
434446
return jsonNode{"$type": "UnknownStatement"}
435447
}
@@ -6183,6 +6195,23 @@ func createStatisticsStatementToJSON(s *ast.CreateStatisticsStatement) jsonNode
61836195
if s.OnName != nil {
61846196
node["OnName"] = schemaObjectNameToJSON(s.OnName)
61856197
}
6198+
if len(s.Columns) > 0 {
6199+
cols := make([]jsonNode, len(s.Columns))
6200+
for i, c := range s.Columns {
6201+
cols[i] = columnReferenceExpressionToJSON(c)
6202+
}
6203+
node["Columns"] = cols
6204+
}
6205+
if len(s.StatisticsOptions) > 0 {
6206+
opts := make([]jsonNode, len(s.StatisticsOptions))
6207+
for i, o := range s.StatisticsOptions {
6208+
opts[i] = statisticsOptionToJSON(o)
6209+
}
6210+
node["StatisticsOptions"] = opts
6211+
}
6212+
if s.FilterPredicate != nil {
6213+
node["FilterPredicate"] = booleanExpressionToJSON(s.FilterPredicate)
6214+
}
61866215
return node
61876216
}
61886217

@@ -6302,6 +6331,10 @@ func alterDatabaseModifyFileGroupStatementToJSON(s *ast.AlterDatabaseModifyFileG
63026331
node["FileGroup"] = identifierToJSON(s.FileGroupName)
63036332
}
63046333
node["MakeDefault"] = s.MakeDefault
6334+
// Only output UseCurrent when UpdatabilityOption is an autogrow option
6335+
if strings.HasPrefix(s.UpdatabilityOption, "Autogrow") {
6336+
node["UseCurrent"] = false
6337+
}
63056338
if s.NewFileGroupName != nil {
63066339
node["NewFileGroupName"] = identifierToJSON(s.NewFileGroupName)
63076340
}
@@ -6581,3 +6614,195 @@ func alterExternalLibraryStatementToJSON(s *ast.AlterExternalLibraryStatement) j
65816614
return node
65826615
}
65836616

6617+
func fetchTypeToJSON(f *ast.FetchType) jsonNode {
6618+
node := jsonNode{
6619+
"$type": "FetchType",
6620+
}
6621+
if f.Orientation != "" {
6622+
node["Orientation"] = f.Orientation
6623+
}
6624+
if f.RowOffset != nil {
6625+
node["RowOffset"] = scalarExpressionToJSON(f.RowOffset)
6626+
}
6627+
return node
6628+
}
6629+
6630+
func openCursorStatementToJSON(s *ast.OpenCursorStatement) jsonNode {
6631+
node := jsonNode{
6632+
"$type": "OpenCursorStatement",
6633+
}
6634+
if s.Cursor != nil {
6635+
node["Cursor"] = cursorIdToJSON(s.Cursor)
6636+
}
6637+
return node
6638+
}
6639+
6640+
func closeCursorStatementToJSON(s *ast.CloseCursorStatement) jsonNode {
6641+
node := jsonNode{
6642+
"$type": "CloseCursorStatement",
6643+
}
6644+
if s.Cursor != nil {
6645+
node["Cursor"] = cursorIdToJSON(s.Cursor)
6646+
}
6647+
return node
6648+
}
6649+
6650+
func deallocateCursorStatementToJSON(s *ast.DeallocateCursorStatement) jsonNode {
6651+
node := jsonNode{
6652+
"$type": "DeallocateCursorStatement",
6653+
}
6654+
if s.Cursor != nil {
6655+
node["Cursor"] = cursorIdToJSON(s.Cursor)
6656+
}
6657+
return node
6658+
}
6659+
6660+
func fetchCursorStatementToJSON(s *ast.FetchCursorStatement) jsonNode {
6661+
node := jsonNode{
6662+
"$type": "FetchCursorStatement",
6663+
}
6664+
if s.FetchType != nil {
6665+
node["FetchType"] = fetchTypeToJSON(s.FetchType)
6666+
}
6667+
if s.Cursor != nil {
6668+
node["Cursor"] = cursorIdToJSON(s.Cursor)
6669+
}
6670+
if len(s.IntoVariables) > 0 {
6671+
vars := make([]jsonNode, len(s.IntoVariables))
6672+
for i, v := range s.IntoVariables {
6673+
vars[i] = scalarExpressionToJSON(v)
6674+
}
6675+
node["IntoVariables"] = vars
6676+
}
6677+
return node
6678+
}
6679+
6680+
func updateStatisticsStatementToJSON(s *ast.UpdateStatisticsStatement) jsonNode {
6681+
node := jsonNode{
6682+
"$type": "UpdateStatisticsStatement",
6683+
}
6684+
if s.SchemaObjectName != nil {
6685+
node["SchemaObjectName"] = schemaObjectNameToJSON(s.SchemaObjectName)
6686+
}
6687+
if len(s.SubElements) > 0 {
6688+
elems := make([]jsonNode, len(s.SubElements))
6689+
for i, e := range s.SubElements {
6690+
elems[i] = identifierToJSON(e)
6691+
}
6692+
node["SubElements"] = elems
6693+
}
6694+
if len(s.StatisticsOptions) > 0 {
6695+
opts := make([]jsonNode, len(s.StatisticsOptions))
6696+
for i, o := range s.StatisticsOptions {
6697+
opts[i] = statisticsOptionToJSON(o)
6698+
}
6699+
node["StatisticsOptions"] = opts
6700+
}
6701+
return node
6702+
}
6703+
6704+
func statisticsOptionToJSON(opt ast.StatisticsOption) jsonNode {
6705+
switch o := opt.(type) {
6706+
case *ast.SimpleStatisticsOption:
6707+
return simpleStatisticsOptionToJSON(o)
6708+
case *ast.LiteralStatisticsOption:
6709+
return literalStatisticsOptionToJSON(o)
6710+
case *ast.OnOffStatisticsOption:
6711+
return onOffStatisticsOptionToJSON(o)
6712+
case *ast.ResampleStatisticsOption:
6713+
return resampleStatisticsOptionToJSON(o)
6714+
default:
6715+
return jsonNode{"$type": "UnknownStatisticsOption"}
6716+
}
6717+
}
6718+
6719+
func simpleStatisticsOptionToJSON(o *ast.SimpleStatisticsOption) jsonNode {
6720+
node := jsonNode{
6721+
"$type": "StatisticsOption",
6722+
}
6723+
if o.OptionKind != "" {
6724+
node["OptionKind"] = o.OptionKind
6725+
}
6726+
return node
6727+
}
6728+
6729+
func literalStatisticsOptionToJSON(o *ast.LiteralStatisticsOption) jsonNode {
6730+
node := jsonNode{
6731+
"$type": "LiteralStatisticsOption",
6732+
}
6733+
if o.OptionKind != "" {
6734+
node["OptionKind"] = o.OptionKind
6735+
}
6736+
if o.Literal != nil {
6737+
node["Literal"] = scalarExpressionToJSON(o.Literal)
6738+
}
6739+
return node
6740+
}
6741+
6742+
func onOffStatisticsOptionToJSON(o *ast.OnOffStatisticsOption) jsonNode {
6743+
node := jsonNode{
6744+
"$type": "OnOffStatisticsOption",
6745+
}
6746+
if o.OptionKind != "" {
6747+
node["OptionKind"] = o.OptionKind
6748+
}
6749+
if o.OptionState != "" {
6750+
node["OptionState"] = o.OptionState
6751+
}
6752+
return node
6753+
}
6754+
6755+
func resampleStatisticsOptionToJSON(o *ast.ResampleStatisticsOption) jsonNode {
6756+
node := jsonNode{
6757+
"$type": "ResampleStatisticsOption",
6758+
}
6759+
if o.OptionKind != "" {
6760+
node["OptionKind"] = o.OptionKind
6761+
}
6762+
if len(o.Partitions) > 0 {
6763+
partitions := make([]jsonNode, len(o.Partitions))
6764+
for i, p := range o.Partitions {
6765+
partitions[i] = scalarExpressionToJSON(p)
6766+
}
6767+
node["Partitions"] = partitions
6768+
}
6769+
return node
6770+
}
6771+
6772+
func declareCursorStatementToJSON(s *ast.DeclareCursorStatement) jsonNode {
6773+
node := jsonNode{
6774+
"$type": "DeclareCursorStatement",
6775+
}
6776+
if s.Name != nil {
6777+
node["Name"] = identifierToJSON(s.Name)
6778+
}
6779+
if s.CursorDefinition != nil {
6780+
node["CursorDefinition"] = declareCursorDefinitionToJSON(s.CursorDefinition)
6781+
}
6782+
return node
6783+
}
6784+
6785+
func declareCursorDefinitionToJSON(d *ast.CursorDefinition) jsonNode {
6786+
node := jsonNode{
6787+
"$type": "CursorDefinition",
6788+
}
6789+
if len(d.Options) > 0 {
6790+
opts := make([]jsonNode, len(d.Options))
6791+
for i, o := range d.Options {
6792+
opts[i] = jsonNode{
6793+
"$type": "CursorOption",
6794+
"OptionKind": o.OptionKind,
6795+
}
6796+
}
6797+
node["Options"] = opts
6798+
}
6799+
if d.Select != nil {
6800+
// For DeclareCursorStatement, we need to wrap the QueryExpression in a SelectStatement format
6801+
selectNode := jsonNode{
6802+
"$type": "SelectStatement",
6803+
"QueryExpression": queryExpressionToJSON(d.Select),
6804+
}
6805+
node["Select"] = selectNode
6806+
}
6807+
return node
6808+
}

parser/parse_ddl.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,12 @@ func (p *Parser) parseAlterDatabaseModifyStatement(dbName *ast.Identifier) (ast.
15861586
case "READWRITE", "READ_WRITE":
15871587
stmt.UpdatabilityOption = "ReadWrite"
15881588
p.nextToken()
1589+
case "AUTOGROW_ALL_FILES":
1590+
stmt.UpdatabilityOption = "AutogrowAllFiles"
1591+
p.nextToken()
1592+
case "AUTOGROW_SINGLE_FILE":
1593+
stmt.UpdatabilityOption = "AutogrowSingleFile"
1594+
p.nextToken()
15891595
case "NAME":
15901596
p.nextToken() // consume NAME
15911597
if p.curTok.Type == TokenEquals {

0 commit comments

Comments
 (0)