xorm/dialects/filter.go
antialiasis 44f892fddc Ignore comments when deciding when to replace question marks. #1954 (#1955)
This should solve #1954 and adds some tests for it. I will note I'm not 100% clear on whether there are other edge cases that should be covered here. From what I understand the only standard SQL way to escape single quotes is to double them, which shouldn't cause any problems with this, but if some SQL flavors allow other kinds of escaping, for instance, that would probably need to be covered too for ideal results.

Co-authored-by: Hlín Önnudóttir <hlin@nanitor.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: xorm/xorm#1955
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: antialiasis <antialiasis@noreply.gitea.io>
Co-committed-by: antialiasis <antialiasis@noreply.gitea.io>
2021-06-26 19:19:13 +08:00

77 lines
1.7 KiB
Go

// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dialects
import (
"fmt"
"strings"
)
// Filter is an interface to filter SQL
type Filter interface {
Do(sql string) string
}
// SeqFilter filter SQL replace ?, ? ... to $1, $2 ...
type SeqFilter struct {
Prefix string
Start int
}
func convertQuestionMark(sql, prefix string, start int) string {
var buf strings.Builder
var beginSingleQuote bool
var isLineComment bool
var isComment bool
var isMaybeLineComment bool
var isMaybeComment bool
var isMaybeCommentEnd bool
var index = start
for _, c := range sql {
if !beginSingleQuote && !isLineComment && !isComment && c == '?' {
buf.WriteString(fmt.Sprintf("%s%v", prefix, index))
index++
} else {
if isMaybeLineComment {
if c == '-' {
isLineComment = true
}
isMaybeLineComment = false
} else if isMaybeComment {
if c == '*' {
isComment = true
}
isMaybeComment = false
} else if isMaybeCommentEnd {
if c == '/' {
isComment = false
}
isMaybeCommentEnd = false
} else if isLineComment {
if c == '\n' {
isLineComment = false
}
} else if isComment {
if c == '*' {
isMaybeCommentEnd = true
}
} else if !beginSingleQuote && c == '-' {
isMaybeLineComment = true
} else if !beginSingleQuote && c == '/' {
isMaybeComment = true
} else if c == '\'' {
beginSingleQuote = !beginSingleQuote
}
buf.WriteRune(c)
}
}
return buf.String()
}
// Do implements Filter
func (s *SeqFilter) Do(sql string) string {
return convertQuestionMark(sql, s.Prefix, s.Start)
}