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  }