Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql/migrate: support GO command in lexer #3299

Merged
merged 1 commit into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions sql/migrate/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"regexp"
"strconv"
"strings"
"unicode"
"unicode/utf8"
Expand Down Expand Up @@ -116,6 +117,8 @@ type (
EscapedStringExt bool
// HashComments enables MySQL/MariaDB hash-like (#) comments.
HashComments bool
// Enable the "GO" command as a delimiter.
GoCommand bool
}
)

Expand Down Expand Up @@ -170,6 +173,7 @@ var (
reBegin = regexp.MustCompile(`(?i)^\s*BEGIN\s+`)
reEnd = regexp.MustCompile(`(?i)^\s*END\s*`)
reEndCatch = regexp.MustCompile(`(?i)^\s*END\s*CATCH\s*`)
reGoCmd = regexp.MustCompile(`(?i)^GO(?:\s+|$)`)
)

func (s *Scanner) stmt() (*Stmt, error) {
Expand Down Expand Up @@ -213,6 +217,19 @@ Scan:
return nil, err
}
s.skipSpaces()
// GO command takes over the delimiter '\nGO'
// in cases it can't parse the statements correctly.
case s.GoCommand && r == '\n' && reGoCmd.MatchString(s.input[s.pos:]):
s.next() // skip '\n'
fallthrough
case s.GoCommand && (s.pos == 1 || s.pos > 1 && s.input[s.pos-2] == '\n') && reGoCmd.MatchString(s.input[s.pos-1:]):
text = s.input[:s.pos-1]
s.next() // skip 'O'
if err := s.skipGoCount(); err != nil {
return nil, err
}
s.skipSpaces()
break Scan
// Delimiters take precedence over comments.
case depth == 0 && strings.HasPrefix(s.input[s.pos-s.width:], s.delim):
s.addPos(len(s.delim) - s.width)
Expand Down Expand Up @@ -464,6 +481,24 @@ func (s *Scanner) delimCmd() error {
return nil
}

// skipGoCount checks if the scanned "GO"
func (s *Scanner) skipGoCount() (err error) {
// GO [count]\n
if s.pick() == ' ' {
c := s.pos
// Scan [count]\n
for r := s.pick(); r != eos && r != '\n'; {
r = s.next()
}
_, err := strconv.Atoi(strings.TrimSpace(s.input[c:s.pos]))
if err != nil {
return fmt.Errorf("sql/migrate: invalid GO command, expect digits got %q: %w",
s.input[c:s.pos], err)
}
}
return nil
}

func (s *Scanner) setDelim(d string) error {
if d == "" {
return errors.New("empty delimiter")
Expand Down
1 change: 1 addition & 0 deletions sql/migrate/lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestLocalFile_Stmts(t *testing.T) {
BackslashEscapes: true,
EscapedStringExt: true,
HashComments: !strings.Contains(f.Name(), "_pg"),
GoCommand: strings.Contains(f.Name(), "_ms"),
},
}
decls, err := sc.Scan(string(f.Bytes()))
Expand Down
14 changes: 14 additions & 0 deletions sql/migrate/testdata/lex/19_ms_gocmd.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
go
SELECT 1
-- comment here
GO
SELECT 2 -- another comment
GO
SELECT 3 GO
GO
SELECT 4
GOTO
SELECT 5
GO 11
SELECT 6
GO
14 changes: 14 additions & 0 deletions sql/migrate/testdata/lex/19_ms_gocmd.sql.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

-- end --
SELECT 1
-- comment here
-- end --
SELECT 2 -- another comment
-- end --
SELECT 3 GO
-- end --
SELECT 4
GOTO
SELECT 5
-- end --
SELECT 6
16 changes: 16 additions & 0 deletions sql/migrate/testdata/lex/20_ms_go-delim.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- atlas:delimiter \nGO

go
SELECT 1
-- comment here
GO
SELECT 2 -- another comment
GO
SELECT 3 GO
gO
SELECT 4
GOTO -- this command is truncated by delimiter
SELECT 5
GO 11
SELECT 6
GO
15 changes: 15 additions & 0 deletions sql/migrate/testdata/lex/20_ms_go-delim.sql.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

-- end --
SELECT 1
-- comment here
-- end --
SELECT 2 -- another comment
-- end --
SELECT 3 GO
-- end --
SELECT 4
-- end --
TO -- this command is truncated by delimiter
SELECT 5
-- end --
SELECT 6
Loading