github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/literal.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package expression 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/vitess/go/vt/proto/query" 22 "github.com/shopspring/decimal" 23 24 "github.com/dolthub/go-mysql-server/sql" 25 "github.com/dolthub/go-mysql-server/sql/types" 26 ) 27 28 // Literal represents a literal expression (string, number, bool, ...). 29 type Literal struct { 30 value interface{} 31 val2 sql.Value 32 fieldType sql.Type 33 } 34 35 var _ sql.Expression = &Literal{} 36 var _ sql.Expression2 = &Literal{} 37 var _ sql.CollationCoercible = &Literal{} 38 39 // NewLiteral creates a new Literal expression. 40 func NewLiteral(value interface{}, fieldType sql.Type) *Literal { 41 val2, _ := sql.ConvertToValue(value) 42 return &Literal{ 43 value: value, 44 val2: val2, 45 fieldType: fieldType, 46 } 47 } 48 49 // Resolved implements the Expression interface. 50 func (lit *Literal) Resolved() bool { 51 return true 52 } 53 54 // IsNullable implements the Expression interface. 55 func (lit *Literal) IsNullable() bool { 56 return lit.value == nil 57 } 58 59 // Type implements the Expression interface. 60 func (lit *Literal) Type() sql.Type { 61 return lit.fieldType 62 } 63 64 // CollationCoercibility implements the interface sql.CollationCoercible. 65 func (lit *Literal) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 66 if types.IsText(lit.fieldType) { 67 collation, _ = lit.fieldType.CollationCoercibility(ctx) 68 return collation, 4 69 } 70 return sql.Collation_binary, 5 71 } 72 73 // Eval implements the Expression interface. 74 func (lit *Literal) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 75 return lit.value, nil 76 } 77 78 func (lit *Literal) String() string { 79 switch litVal := lit.value.(type) { 80 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 81 return fmt.Sprintf("%d", litVal) 82 case string: 83 switch lit.fieldType.Type() { 84 // utf8 charset cannot encode binary string 85 case query.Type_VARBINARY, query.Type_BINARY: 86 return fmt.Sprintf("'0x%X'", litVal) 87 } 88 // Conversion of \' to \'\' required as this string will be interpreted by the sql engine. 89 // Backslash chars also need to be replaced. 90 escaped := strings.ReplaceAll(litVal, "'", "''") 91 escaped = strings.ReplaceAll(escaped, "\\", "\\\\") 92 return fmt.Sprintf("'%s'", escaped) 93 case decimal.Decimal: 94 return litVal.StringFixed(litVal.Exponent() * -1) 95 case []byte: 96 return fmt.Sprintf("0x%X", litVal) 97 case nil: 98 return "NULL" 99 default: 100 return fmt.Sprint(litVal) 101 } 102 } 103 104 func (lit *Literal) DebugString() string { 105 typeStr := lit.fieldType.String() 106 switch v := lit.value.(type) { 107 case string: 108 return fmt.Sprintf("%s (%s)", v, typeStr) 109 case []byte: 110 return fmt.Sprintf("BLOB(%s)", string(v)) 111 case nil: 112 return fmt.Sprintf("NULL (%s)", typeStr) 113 case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64: 114 return fmt.Sprintf("%d (%s)", v, typeStr) 115 case float32, float64: 116 return fmt.Sprintf("%f (%s)", v, typeStr) 117 case bool: 118 return fmt.Sprintf("%t (%s)", v, typeStr) 119 default: 120 return fmt.Sprintf("%s (%s)", v, typeStr) 121 } 122 } 123 124 // WithChildren implements the Expression interface. 125 func (lit *Literal) WithChildren(children ...sql.Expression) (sql.Expression, error) { 126 if len(children) != 0 { 127 return nil, sql.ErrInvalidChildrenNumber.New(lit, len(children), 0) 128 } 129 return lit, nil 130 } 131 132 // Children implements the Expression interface. 133 func (*Literal) Children() []sql.Expression { 134 return nil 135 } 136 137 func (lit *Literal) Eval2(ctx *sql.Context, row sql.Row2) (sql.Value, error) { 138 return lit.val2, nil 139 } 140 141 func (lit *Literal) Type2() sql.Type2 { 142 t2, ok := lit.fieldType.(sql.Type2) 143 if !ok { 144 panic(fmt.Errorf("expected Type2, but was %T", lit.fieldType)) 145 } 146 return t2 147 } 148 149 // Value returns the literal value. 150 func (p *Literal) Value() interface{} { 151 return p.value 152 }