go.temporal.io/server@v1.23.0/common/persistence/visibility/store/sql/query_converter_util.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package sql 26 27 import ( 28 "strings" 29 "time" 30 31 "github.com/temporalio/sqlparser" 32 33 enumspb "go.temporal.io/api/enums/v1" 34 "go.temporal.io/server/common/persistence/visibility/store/query" 35 "go.temporal.io/server/common/searchattribute" 36 ) 37 38 type ( 39 // unsafeSQLString don't escape the string value; unlike sqlparser.SQLVal. 40 // This is used for building string known to be safe. 41 unsafeSQLString struct { 42 sqlparser.Expr 43 Val string 44 } 45 46 colName struct { 47 sqlparser.Expr 48 Name string 49 } 50 51 saColName struct { 52 sqlparser.Expr 53 dbColName *colName 54 alias string 55 fieldName string 56 valueType enumspb.IndexedValueType 57 } 58 ) 59 60 const ( 61 coalesceFuncName = "coalesce" 62 ) 63 64 var _ sqlparser.Expr = (*unsafeSQLString)(nil) 65 var _ sqlparser.Expr = (*colName)(nil) 66 var _ sqlparser.Expr = (*saColName)(nil) 67 68 var ( 69 maxDatetimeValue = getMaxDatetimeValue() 70 71 closeTimeSaColName = newSAColName( 72 searchattribute.GetSqlDbColName(searchattribute.CloseTime), 73 searchattribute.CloseTime, 74 searchattribute.CloseTime, 75 enumspb.INDEXED_VALUE_TYPE_DATETIME, 76 ) 77 ) 78 79 func (node *unsafeSQLString) Format(buf *sqlparser.TrackedBuffer) { 80 buf.Myprintf("'%s'", node.Val) 81 } 82 83 func (node *colName) Format(buf *sqlparser.TrackedBuffer) { 84 buf.Myprintf("%s", node.Name) 85 } 86 87 func (node *saColName) Format(buf *sqlparser.TrackedBuffer) { 88 buf.Myprintf("%v", node.dbColName) 89 } 90 91 func newUnsafeSQLString(val string) *unsafeSQLString { 92 return &unsafeSQLString{Val: val} 93 } 94 95 func newColName(name string) *colName { 96 return &colName{Name: name} 97 } 98 99 func newSAColName( 100 dbColName string, 101 alias string, 102 fieldName string, 103 valueType enumspb.IndexedValueType, 104 ) *saColName { 105 return &saColName{ 106 dbColName: newColName(dbColName), 107 alias: alias, 108 fieldName: fieldName, 109 valueType: valueType, 110 } 111 } 112 113 func newFuncExpr(name string, exprs ...sqlparser.Expr) *sqlparser.FuncExpr { 114 args := make([]sqlparser.SelectExpr, len(exprs)) 115 for i := range exprs { 116 args[i] = &sqlparser.AliasedExpr{Expr: exprs[i]} 117 } 118 return &sqlparser.FuncExpr{ 119 Name: sqlparser.NewColIdent(name), 120 Exprs: args, 121 } 122 } 123 124 func addPrefix(prefix string, fields []string) []string { 125 out := make([]string, len(fields)) 126 for i, field := range fields { 127 out[i] = prefix + field 128 } 129 return out 130 } 131 132 func getMaxDatetimeValue() time.Time { 133 t, _ := time.Parse(time.RFC3339, "9999-12-31T23:59:59Z") 134 return t 135 } 136 137 // formatComparisonExprStringForError formats comparison expression after 138 // custom search attribute was mapped to field name to show alias name for 139 // better user experience. 140 func formatComparisonExprStringForError(expr sqlparser.ComparisonExpr) string { 141 if colNameExpr, ok := expr.Left.(*saColName); ok { 142 expr.Left = newColName(colNameExpr.alias) 143 } 144 return sqlparser.String(&expr) 145 } 146 147 // Simple tokenizer by spaces. It's a temporary solution as it doesn't cover tokenizer used by 148 // PostgreSQL or SQLite. 149 func tokenizeTextQueryString(s string) []string { 150 tokens := strings.Split(s, " ") 151 nonEmptyTokens := make([]string, 0, len(tokens)) 152 for _, token := range tokens { 153 if token != "" { 154 nonEmptyTokens = append(nonEmptyTokens, token) 155 } 156 } 157 return nonEmptyTokens 158 } 159 160 func getUnsafeStringTupleValues(valTuple sqlparser.ValTuple) ([]string, error) { 161 values := make([]string, len(valTuple)) 162 for i, val := range valTuple { 163 switch v := val.(type) { 164 case *unsafeSQLString: 165 values[i] = v.Val 166 default: 167 return nil, query.NewConverterError( 168 "%s: unexpected value type in tuple (expected string, got %v)", 169 query.InvalidExpressionErrMessage, 170 sqlparser.String(v), 171 ) 172 } 173 } 174 return values, nil 175 }