118 lines
3.5 KiB
Go
118 lines
3.5 KiB
Go
package sqliteparserutils
|
|
|
|
import (
|
|
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
|
"github.com/libsql/sqlite-antlr4-parser/sqliteparser"
|
|
)
|
|
|
|
// TODO: Shell test begin transaction on shell
|
|
|
|
type SplitStatementExtraInfo struct {
|
|
IncompleteCreateTriggerStatement bool
|
|
IncompleteMultilineComment bool
|
|
LastTokenType int
|
|
}
|
|
|
|
func SplitStatement(statement string) (stmts []string, extraInfo SplitStatementExtraInfo) {
|
|
tokenStream := createTokenStream(statement)
|
|
|
|
stmtIntervals := make([]*antlr.Interval, 0)
|
|
currentIntervalStart := -1
|
|
insideCreateTriggerStmt := false
|
|
insideMultilineComment := false
|
|
|
|
var previousToken antlr.Token
|
|
var currentToken antlr.Token
|
|
for currentToken = tokenStream.LT(1); currentToken.GetTokenType() != antlr.TokenEOF; currentToken = tokenStream.LT(1) {
|
|
// We break loop here because we're sure multiline comment didn't finished, otherwise lexer would have just ignored
|
|
// it
|
|
if atIncompleteMultilineCommentStart(tokenStream) {
|
|
insideMultilineComment = true
|
|
break
|
|
}
|
|
|
|
if currentIntervalStart == -1 {
|
|
if currentToken.GetTokenType() == sqliteparser.SQLiteLexerSCOL {
|
|
previousToken = currentToken
|
|
tokenStream.Consume()
|
|
continue
|
|
}
|
|
currentIntervalStart = currentToken.GetTokenIndex()
|
|
|
|
if atCreateTriggerStart(tokenStream) {
|
|
insideCreateTriggerStmt = true
|
|
previousToken = currentToken
|
|
tokenStream.Consume()
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
if insideCreateTriggerStmt {
|
|
if currentToken.GetTokenType() == sqliteparser.SQLiteLexerEND_ {
|
|
insideCreateTriggerStmt = false
|
|
}
|
|
} else if currentToken.GetTokenType() == sqliteparser.SQLiteLexerSCOL {
|
|
stmtIntervals = append(stmtIntervals, antlr.NewInterval(currentIntervalStart, previousToken.GetTokenIndex()))
|
|
currentIntervalStart = -1
|
|
}
|
|
|
|
previousToken = currentToken
|
|
tokenStream.Consume()
|
|
}
|
|
|
|
if currentIntervalStart != -1 && previousToken != nil {
|
|
stmtIntervals = append(stmtIntervals, antlr.NewInterval(currentIntervalStart, previousToken.GetTokenIndex()))
|
|
}
|
|
|
|
stmts = make([]string, 0)
|
|
for _, stmtInterval := range stmtIntervals {
|
|
stmts = append(stmts, tokenStream.GetTextFromInterval(stmtInterval))
|
|
}
|
|
|
|
lastTokenType := antlr.TokenInvalidType
|
|
if previousToken != nil {
|
|
lastTokenType = previousToken.GetTokenType()
|
|
}
|
|
return stmts, SplitStatementExtraInfo{IncompleteCreateTriggerStatement: insideCreateTriggerStmt, IncompleteMultilineComment: insideMultilineComment, LastTokenType: lastTokenType}
|
|
}
|
|
|
|
func atCreateTriggerStart(tokenStream antlr.TokenStream) bool {
|
|
if tokenStream.LT(1).GetTokenType() != sqliteparser.SQLiteLexerCREATE_ {
|
|
return false
|
|
}
|
|
|
|
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTRIGGER_ {
|
|
return true
|
|
}
|
|
|
|
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTEMP_ || tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerTEMPORARY_ &&
|
|
tokenStream.LT(3).GetTokenType() == sqliteparser.SQLiteLexerTRIGGER_ {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
// Note: Only starts for incomplete multiline comments will be detected cause lexer automatically ignores complete
|
|
// multiline comments
|
|
func atIncompleteMultilineCommentStart(tokenStream antlr.TokenStream) bool {
|
|
if tokenStream.LT(1).GetTokenType() != sqliteparser.SQLiteLexerDIV {
|
|
return false
|
|
}
|
|
|
|
if tokenStream.LT(2).GetTokenType() == sqliteparser.SQLiteLexerSTAR {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func createTokenStream(statement string) *antlr.CommonTokenStream {
|
|
statementStream := antlr.NewInputStream(statement)
|
|
|
|
lexer := sqliteparser.NewSQLiteLexer(statementStream)
|
|
return antlr.NewCommonTokenStream(lexer, 0)
|
|
}
|