storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/s3select/sql/utils.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 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 sql 18 19 import ( 20 "fmt" 21 "strings" 22 ) 23 24 // String functions 25 26 // String - returns the JSONPath representation 27 func (e *JSONPath) String() string { 28 if len(e.pathString) == 0 { 29 parts := make([]string, len(e.PathExpr)+1) 30 parts[0] = e.BaseKey.String() 31 for i, pe := range e.PathExpr { 32 parts[i+1] = pe.String() 33 } 34 e.pathString = strings.Join(parts, "") 35 } 36 return e.pathString 37 } 38 39 // StripTableAlias removes a table alias from the path. The result is also 40 // cached for repeated lookups during SQL query evaluation. 41 func (e *JSONPath) StripTableAlias(tableAlias string) []*JSONPathElement { 42 if e.strippedTableAlias == tableAlias { 43 return e.strippedPathExpr 44 } 45 46 hasTableAlias := e.BaseKey.String() == tableAlias || strings.ToLower(e.BaseKey.String()) == baseTableName 47 var pathExpr []*JSONPathElement 48 if hasTableAlias { 49 pathExpr = e.PathExpr 50 } else { 51 pathExpr = make([]*JSONPathElement, len(e.PathExpr)+1) 52 pathExpr[0] = &JSONPathElement{Key: &ObjectKey{ID: e.BaseKey}} 53 copy(pathExpr[1:], e.PathExpr) 54 } 55 e.strippedTableAlias = tableAlias 56 e.strippedPathExpr = pathExpr 57 return e.strippedPathExpr 58 } 59 60 func (e *JSONPathElement) String() string { 61 switch { 62 case e.Key != nil: 63 return e.Key.String() 64 case e.Index != nil: 65 return fmt.Sprintf("[%d]", *e.Index) 66 case e.ObjectWildcard: 67 return ".*" 68 case e.ArrayWildcard: 69 return "[*]" 70 } 71 return "" 72 } 73 74 // String removes double quotes in quoted identifiers 75 func (i *Identifier) String() string { 76 if i.Unquoted != nil { 77 return *i.Unquoted 78 } 79 return string(*i.Quoted) 80 } 81 82 func (o *ObjectKey) String() string { 83 if o.Lit != nil { 84 return fmt.Sprintf("['%s']", string(*o.Lit)) 85 } 86 return fmt.Sprintf(".%s", o.ID.String()) 87 } 88 89 func (o *ObjectKey) keyString() string { 90 if o.Lit != nil { 91 return string(*o.Lit) 92 } 93 return o.ID.String() 94 } 95 96 // getLastKeypathComponent checks if the given expression is a path 97 // expression, and if so extracts the last dot separated component of 98 // the path. Otherwise it returns false. 99 func getLastKeypathComponent(e *Expression) (string, bool) { 100 if len(e.And) > 1 || 101 len(e.And[0].Condition) > 1 || 102 e.And[0].Condition[0].Not != nil || 103 e.And[0].Condition[0].Operand.ConditionRHS != nil { 104 return "", false 105 } 106 107 operand := e.And[0].Condition[0].Operand.Operand 108 if operand.Right != nil || 109 operand.Left.Right != nil || 110 operand.Left.Left.Negated != nil || 111 operand.Left.Left.Primary.JPathExpr == nil { 112 return "", false 113 } 114 115 // Check if path expression ends in a key 116 jpath := operand.Left.Left.Primary.JPathExpr 117 n := len(jpath.PathExpr) 118 if n > 0 && jpath.PathExpr[n-1].Key == nil { 119 return "", false 120 } 121 ps := jpath.String() 122 if idx := strings.LastIndex(ps, "."); idx >= 0 { 123 // Get last part of path string. 124 ps = ps[idx+1:] 125 } 126 return ps, true 127 } 128 129 // HasKeypath returns if the from clause has a key path - 130 // e.g. S3object[*].id 131 func (from *TableExpression) HasKeypath() bool { 132 return len(from.Table.PathExpr) > 1 133 }