| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package clickhouse
- import (
- "bytes"
- "database/sql/driver"
- "fmt"
- "reflect"
- "regexp"
- "strings"
- "time"
- )
- func numInput(query string) int {
- var (
- count int
- args = make(map[string]struct{})
- reader = bytes.NewReader([]byte(query))
- quote, gravis bool
- escape bool
- keyword bool
- inBetween bool
- like = newMatcher("like")
- limit = newMatcher("limit")
- offset = newMatcher("offset")
- between = newMatcher("between")
- in = newMatcher("in")
- and = newMatcher("and")
- from = newMatcher("from")
- join = newMatcher("join")
- subSelect = newMatcher("select")
- )
- for {
- if char, _, err := reader.ReadRune(); err == nil {
- if escape {
- escape = false
- continue
- }
- switch char {
- case '\\':
- if gravis || quote {
- escape = true
- }
- case '\'':
- if !gravis {
- quote = !quote
- }
- case '`':
- if !quote {
- gravis = !gravis
- }
- }
- if quote || gravis {
- continue
- }
- switch {
- case char == '?' && keyword:
- count++
- case char == '@':
- if param := paramParser(reader); len(param) != 0 {
- if _, found := args[param]; !found {
- args[param] = struct{}{}
- count++
- }
- }
- case
- char == '=',
- char == '<',
- char == '>',
- char == '(',
- char == ',',
- char == '[',
- char == '%':
- keyword = true
- default:
- if limit.matchRune(char) || offset.matchRune(char) || like.matchRune(char) ||
- in.matchRune(char) || from.matchRune(char) || join.matchRune(char) || subSelect.matchRune(char) {
- keyword = true
- } else if between.matchRune(char) {
- keyword = true
- inBetween = true
- } else if inBetween && and.matchRune(char) {
- keyword = true
- inBetween = false
- } else {
- keyword = keyword && (char == ' ' || char == '\t' || char == '\n')
- }
- }
- } else {
- break
- }
- }
- return count
- }
- func paramParser(reader *bytes.Reader) string {
- var name bytes.Buffer
- for {
- if char, _, err := reader.ReadRune(); err == nil {
- if char == '_' || char >= '0' && char <= '9' || 'a' <= char && char <= 'z' || 'A' <= char && char <= 'Z' {
- name.WriteRune(char)
- } else {
- reader.UnreadRune()
- break
- }
- } else {
- break
- }
- }
- return name.String()
- }
- var selectRe = regexp.MustCompile(`\s+SELECT\s+`)
- func isInsert(query string) bool {
- if f := strings.Fields(query); len(f) > 2 {
- return strings.EqualFold("INSERT", f[0]) && strings.EqualFold("INTO", f[1]) && !selectRe.MatchString(strings.ToUpper(query))
- }
- return false
- }
- func quote(v driver.Value) string {
- switch v := reflect.ValueOf(v); v.Kind() {
- case reflect.Slice:
- values := make([]string, 0, v.Len())
- for i := 0; i < v.Len(); i++ {
- values = append(values, quote(v.Index(i).Interface()))
- }
- return strings.Join(values, ", ")
- }
- switch v := v.(type) {
- case string:
- return "'" + strings.NewReplacer(`\`, `\\`, `'`, `\'`).Replace(v) + "'"
- case time.Time:
- return formatTime(v)
- case nil:
- return "null"
- }
- return fmt.Sprint(v)
- }
- func formatTime(v time.Time) string {
- return v.Format("toDateTime('2006-01-02 15:04:05', '" + v.Location().String() + "')")
- }
|