github.com/goplus/yap@v0.8.1/ydb/utils.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ydb 18 19 import ( 20 "fmt" 21 "log" 22 "reflect" 23 "strings" 24 "unicode/utf8" 25 26 "github.com/qiniu/x/ctype" 27 ) 28 29 // ----------------------------------------------------------------------------- 30 31 func recoverErr(e any) error { 32 if v, ok := e.(error); ok { 33 return v 34 } 35 return fmt.Errorf("%v", e) 36 } 37 38 // ----------------------------------------------------------------------------- 39 40 func isSlice(v any) bool { 41 return reflect.ValueOf(v).Kind() == reflect.Slice 42 } 43 44 func checkArgSlice(args []any) int { 45 iArgSlice := -1 46 for i, arg := range args { 47 if isSlice(arg) { 48 if iArgSlice >= 0 { 49 log.Panicf( 50 "query: multiple arguments (%dth, %dth) are slices (only one can be)\n", 51 iArgSlice+1, i+1, 52 ) 53 } 54 iArgSlice = i 55 } 56 } 57 return iArgSlice 58 } 59 60 // ----------------------------------------------------------------------------- 61 62 func (p *Class) tblFromNames(names []string) (tbl string) { 63 var v string 64 tbl, names[0] = tblFromName(names[0]) 65 for i := 1; i < len(names); i++ { 66 if v, names[i] = tblFromName(names[i]); v != tbl { 67 log.Panicln("insert: multiple tables") 68 } 69 } 70 if tbl == "" { 71 tbl = p.tbl 72 } 73 return 74 } 75 76 func tblFromName(name string) (string, string) { 77 if pos := strings.IndexByte(name, '.'); pos > 0 { 78 return name[:pos], name[pos+1:] 79 } 80 return "", name 81 } 82 83 // ----------------------------------------------------------------------------- 84 85 func (p *Class) exprTblname(cond string) string { 86 tbls := exprTblnames(cond) 87 tbl := "" 88 switch len(tbls) { 89 case 0: 90 case 1: 91 tbl = tbls[0] 92 default: 93 log.Panicln("query currently doesn't support multiple tables") 94 } 95 if tbl == "" { 96 tbl = p.tbl 97 } 98 return tbl 99 } 100 101 func exprTblnames(expr string) (tbls []string) { 102 for expr != "" { 103 pos := ctype.ScanCSymbol(expr) 104 if pos != 0 { 105 name := "" 106 if pos > 0 { 107 switch expr[pos] { 108 case '.': 109 name = expr[:pos] 110 expr = ctype.SkipCSymbol(expr[pos+1:]) 111 case '(': // function call, eg. SUM(...) 112 expr = expr[pos+1:] 113 continue 114 default: 115 expr = expr[pos:] 116 } 117 } else { 118 expr = "" 119 } 120 switch name { 121 case "AND", "OR": 122 default: 123 tbls = addTblname(tbls, name) 124 } 125 continue 126 } 127 pos = ctype.ScanTypeEx(ctype.FLOAT_FIRST_CHAT, ctype.CSYMBOL_NEXT_CHAR, expr) 128 if pos == 0 { 129 c, size := utf8.DecodeRuneInString(expr) 130 switch c { 131 case '\'': 132 expr = skipStringConst(expr[1:], '\'') 133 default: 134 expr = expr[size:] 135 } 136 } else if pos < 0 { 137 break 138 } else { 139 expr = expr[pos:] 140 } 141 } 142 return 143 } 144 145 func skipStringConst(next string, quot rune) string { 146 skip := false 147 for i, c := range next { 148 if skip { 149 skip = false 150 } else if c == '\\' { 151 skip = true 152 } else if c == quot { 153 return next[i+1:] 154 } 155 } 156 return "" 157 } 158 159 func addTblname(tbls []string, tbl string) []string { 160 for _, v := range tbls { 161 if v == tbl { 162 return tbls 163 } 164 } 165 return append(tbls, tbl) 166 } 167 168 // -----------------------------------------------------------------------------