Skip to content

Commit b1f22b0

Browse files
committed
Add parser features and enable 15 more tests
Features added: - String concat operator (||) and concat-equals (||=) - Compound assignment operators (+=, -=, *=, /=, %=, &=, |=, ^=) - CREATE WORKLOAD CLASSIFIER statement with options - SEND statement with multiple conversation handles - SelectSetVariable for SELECT @var = expr patterns Bug fixes: - Fixed NullLiteral value to use lowercase "null" - Fixed StringLiteral to always include Value field (even empty) - Fixed WorkloadGroup parameter types - Fixed SeparatorType output for NotSpecified Tests enabled: - StringConcatOperatorTests160 (2) - SendStatementTests110 (3) - AlterWorkloadGroupStatementSqlDwTests (2) - CreateWorkloadGroupStatementSqlDwTests130 (2) - AssignmentWithOperationTests (2) - CreateWorkloadClassifierStatementSqlDwTests (2) - FuzzyStringMatchingTests160 (2)
1 parent 8fa9ff9 commit b1f22b0

File tree

67 files changed

+778
-154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+778
-154
lines changed

ast/select_set_variable.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ast
2+
3+
// SelectSetVariable represents a variable assignment in a SELECT statement.
4+
// Example: SELECT @a = 1, @b ||= 'foo'
5+
type SelectSetVariable struct {
6+
Variable *VariableReference `json:"Variable,omitempty"`
7+
Expression ScalarExpression `json:"Expression,omitempty"`
8+
AssignmentKind string `json:"AssignmentKind,omitempty"`
9+
}
10+
11+
func (*SelectSetVariable) node() {}
12+
func (*SelectSetVariable) selectElement() {}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Package ast provides AST types for T-SQL parsing.
2+
package ast
3+
4+
// CreateWorkloadClassifierStatement represents a CREATE WORKLOAD CLASSIFIER statement.
5+
type CreateWorkloadClassifierStatement struct {
6+
ClassifierName *Identifier
7+
Options []WorkloadClassifierOption
8+
}
9+
10+
func (s *CreateWorkloadClassifierStatement) statement() {}
11+
func (s *CreateWorkloadClassifierStatement) node() {}
12+
13+
// WorkloadClassifierOption is the interface for workload classifier options.
14+
type WorkloadClassifierOption interface {
15+
node()
16+
workloadClassifierOption()
17+
}
18+
19+
// ClassifierWorkloadGroupOption represents the WORKLOAD_GROUP option.
20+
type ClassifierWorkloadGroupOption struct {
21+
WorkloadGroupName *StringLiteral
22+
OptionType string
23+
}
24+
25+
func (o *ClassifierWorkloadGroupOption) node() {}
26+
func (o *ClassifierWorkloadGroupOption) workloadClassifierOption() {}
27+
28+
// ClassifierMemberNameOption represents the MEMBERNAME option.
29+
type ClassifierMemberNameOption struct {
30+
MemberName *StringLiteral
31+
OptionType string
32+
}
33+
34+
func (o *ClassifierMemberNameOption) node() {}
35+
func (o *ClassifierMemberNameOption) workloadClassifierOption() {}
36+
37+
// ClassifierWlmContextOption represents the WLM_CONTEXT option.
38+
type ClassifierWlmContextOption struct {
39+
WlmContext *StringLiteral
40+
OptionType string
41+
}
42+
43+
func (o *ClassifierWlmContextOption) node() {}
44+
func (o *ClassifierWlmContextOption) workloadClassifierOption() {}
45+
46+
// WlmTimeLiteral represents a time literal for WLM START_TIME/END_TIME options.
47+
type WlmTimeLiteral struct {
48+
TimeString *StringLiteral
49+
}
50+
51+
func (t *WlmTimeLiteral) node() {}
52+
53+
// ClassifierStartTimeOption represents the START_TIME option.
54+
type ClassifierStartTimeOption struct {
55+
Time *WlmTimeLiteral
56+
OptionType string
57+
}
58+
59+
func (o *ClassifierStartTimeOption) node() {}
60+
func (o *ClassifierStartTimeOption) workloadClassifierOption() {}
61+
62+
// ClassifierEndTimeOption represents the END_TIME option.
63+
type ClassifierEndTimeOption struct {
64+
Time *WlmTimeLiteral
65+
OptionType string
66+
}
67+
68+
func (o *ClassifierEndTimeOption) node() {}
69+
func (o *ClassifierEndTimeOption) workloadClassifierOption() {}
70+
71+
// ClassifierWlmLabelOption represents the WLM_LABEL option.
72+
type ClassifierWlmLabelOption struct {
73+
WlmLabel *StringLiteral
74+
OptionType string
75+
}
76+
77+
func (o *ClassifierWlmLabelOption) node() {}
78+
func (o *ClassifierWlmLabelOption) workloadClassifierOption() {}
79+
80+
// ClassifierImportanceOption represents the IMPORTANCE option.
81+
type ClassifierImportanceOption struct {
82+
Importance string
83+
OptionType string
84+
}
85+
86+
func (o *ClassifierImportanceOption) node() {}
87+
func (o *ClassifierImportanceOption) workloadClassifierOption() {}

parser/lexer.go

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ const (
8585
TokenRBrace
8686
TokenLeftShift
8787
TokenRightShift
88+
TokenPipe // |
89+
TokenDoublePipe // ||
90+
TokenConcatEquals // ||=
91+
TokenBitwiseAnd // &
92+
TokenPlusEquals // +=
93+
TokenMinusEquals // -=
94+
TokenStarEquals // *=
95+
TokenSlashEquals // /=
96+
TokenModuloEquals // %=
97+
TokenAndEquals // &=
98+
TokenOrEquals // |=
99+
TokenXorEquals // ^=
100+
TokenCaret // ^
88101

89102
// DML Keywords
90103
TokenInsert
@@ -265,9 +278,16 @@ func (l *Lexer) NextToken() Token {
265278
tok.Type = TokenEOF
266279
tok.Literal = ""
267280
case '*':
268-
tok.Type = TokenStar
269-
tok.Literal = "*"
270-
l.readChar()
281+
if l.peekChar() == '=' {
282+
l.readChar()
283+
tok.Type = TokenStarEquals
284+
tok.Literal = "*="
285+
l.readChar()
286+
} else {
287+
tok.Type = TokenStar
288+
tok.Literal = "*"
289+
l.readChar()
290+
}
271291
case ',':
272292
tok.Type = TokenComma
273293
tok.Literal = ","
@@ -355,21 +375,94 @@ func (l *Lexer) NextToken() Token {
355375
tok.Literal = "}"
356376
l.readChar()
357377
case '+':
358-
tok.Type = TokenPlus
359-
tok.Literal = "+"
360-
l.readChar()
378+
if l.peekChar() == '=' {
379+
l.readChar()
380+
tok.Type = TokenPlusEquals
381+
tok.Literal = "+="
382+
l.readChar()
383+
} else {
384+
tok.Type = TokenPlus
385+
tok.Literal = "+"
386+
l.readChar()
387+
}
361388
case '-':
362-
tok.Type = TokenMinus
363-
tok.Literal = "-"
364-
l.readChar()
389+
if l.peekChar() == '=' {
390+
l.readChar()
391+
tok.Type = TokenMinusEquals
392+
tok.Literal = "-="
393+
l.readChar()
394+
} else {
395+
tok.Type = TokenMinus
396+
tok.Literal = "-"
397+
l.readChar()
398+
}
365399
case '/':
366-
tok.Type = TokenSlash
367-
tok.Literal = "/"
368-
l.readChar()
400+
if l.peekChar() == '=' {
401+
l.readChar()
402+
tok.Type = TokenSlashEquals
403+
tok.Literal = "/="
404+
l.readChar()
405+
} else {
406+
tok.Type = TokenSlash
407+
tok.Literal = "/"
408+
l.readChar()
409+
}
369410
case '%':
370-
tok.Type = TokenModulo
371-
tok.Literal = "%"
372-
l.readChar()
411+
if l.peekChar() == '=' {
412+
l.readChar()
413+
tok.Type = TokenModuloEquals
414+
tok.Literal = "%="
415+
l.readChar()
416+
} else {
417+
tok.Type = TokenModulo
418+
tok.Literal = "%"
419+
l.readChar()
420+
}
421+
case '|':
422+
if l.peekChar() == '|' {
423+
l.readChar() // consume first |
424+
if l.peekChar() == '=' {
425+
l.readChar() // consume second |
426+
tok.Type = TokenConcatEquals
427+
tok.Literal = "||="
428+
l.readChar() // consume =
429+
} else {
430+
tok.Type = TokenDoublePipe
431+
tok.Literal = "||"
432+
l.readChar() // consume second |
433+
}
434+
} else if l.peekChar() == '=' {
435+
l.readChar()
436+
tok.Type = TokenOrEquals
437+
tok.Literal = "|="
438+
l.readChar()
439+
} else {
440+
tok.Type = TokenPipe
441+
tok.Literal = "|"
442+
l.readChar()
443+
}
444+
case '&':
445+
if l.peekChar() == '=' {
446+
l.readChar()
447+
tok.Type = TokenAndEquals
448+
tok.Literal = "&="
449+
l.readChar()
450+
} else {
451+
tok.Type = TokenBitwiseAnd
452+
tok.Literal = "&"
453+
l.readChar()
454+
}
455+
case '^':
456+
if l.peekChar() == '=' {
457+
l.readChar()
458+
tok.Type = TokenXorEquals
459+
tok.Literal = "^="
460+
l.readChar()
461+
} else {
462+
tok.Type = TokenCaret
463+
tok.Literal = "^"
464+
l.readChar()
465+
}
373466
case '\'':
374467
tok = l.readString()
375468
default:

0 commit comments

Comments
 (0)