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  // -----------------------------------------------------------------------------