github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/sqltypes/value.go (about)

     1  /*
     2  Copyright 2017 Google 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 sqltypes implements interfaces and types that represent SQL values.
    18  package sqltypes
    19  
    20  import (
    21  	"encoding/base64"
    22  	"errors"
    23  	"strconv"
    24  
    25  	"github.com/bingoohuang/gg/pkg/sqlparse/bytes2"
    26  	"github.com/bingoohuang/gg/pkg/sqlparse/hack"
    27  )
    28  
    29  var (
    30  	// NULL represents the NULL value.
    31  	NULL = Value{}
    32  	// DontEscape tells you if a character should not be escaped.
    33  	DontEscape = byte(255)
    34  	nullstr    = []byte("null")
    35  )
    36  
    37  // BinWriter interface is used for encoding values.
    38  // Types like bytes.Buffer conform to this interface.
    39  // We expect the writer objects to be in-memory buffers.
    40  // So, we don't expect the write operations to fail.
    41  type BinWriter interface {
    42  	Write([]byte) (int, error)
    43  }
    44  
    45  // Value can store any SQL value. If the value represents
    46  // an integral type, the bytes are always stored as a cannonical
    47  // representation that matches how MySQL returns such values.
    48  type Value struct {
    49  	typ Type
    50  	val []byte
    51  }
    52  
    53  // MakeTrusted makes a new Value based on the type.
    54  // If the value is an integral, then val must be in its cannonical
    55  // form. This function should only be used if you know the value
    56  // and type conform to the rules.  Every place this function is
    57  // called, a comment is needed that explains why it's justified.
    58  // Functions within this package are exempt.
    59  func MakeTrusted(typ Type, val []byte) Value {
    60  	if typ == Null {
    61  		return NULL
    62  	}
    63  	return Value{typ: typ, val: val}
    64  }
    65  
    66  // MakeString makes a VarBinary Value.
    67  func MakeString(val []byte) Value {
    68  	return MakeTrusted(VarBinary, val)
    69  }
    70  
    71  // Type returns the type of Value.
    72  func (v Value) Type() Type {
    73  	return v.typ
    74  }
    75  
    76  // Raw returns the raw bytes. All types are currently implemented as []byte.
    77  // You should avoid using this function. If you do, you should treat the
    78  // bytes as read-only.
    79  func (v Value) Raw() []byte {
    80  	return v.val
    81  }
    82  
    83  // Bytes returns a copy of the raw data. All types are currently implemented as []byte.
    84  // Use this function instead of Raw if you can't be sure about maintaining the read-only
    85  // requirements of the bytes.
    86  func (v Value) Bytes() []byte {
    87  	out := make([]byte, len(v.val))
    88  	copy(out, v.val)
    89  	return out
    90  }
    91  
    92  // Len returns the length.
    93  func (v Value) Len() int {
    94  	return len(v.val)
    95  }
    96  
    97  // String returns the raw value as a string.
    98  func (v Value) String() string {
    99  	return hack.String(v.val)
   100  }
   101  
   102  // ToNative converts Value to a native go type.
   103  // This does not work for sqltypes.Tuple. The function
   104  // panics if there are inconsistencies.
   105  func (v Value) ToNative() interface{} {
   106  	var out interface{}
   107  	var err error
   108  	switch {
   109  	case v.typ == Null:
   110  		// no-op
   111  	case IsSigned(v.typ):
   112  		out, err = v.ParseInt64()
   113  	case IsUnsigned(v.typ):
   114  		out, err = v.ParseUint64()
   115  	case IsFloat(v.typ):
   116  		out, err = v.ParseFloat64()
   117  	case v.typ == Tuple:
   118  		err = errors.New("unexpected tuple")
   119  	default:
   120  		out = v.val
   121  	}
   122  	if err != nil {
   123  		panic(err)
   124  	}
   125  	return out
   126  }
   127  
   128  // ParseInt64 will parse a Value into an int64. It does
   129  // not check the type.
   130  // TODO(sougou): deprecate this function in favor of a
   131  // more type-aware implemention in arithmetic.
   132  func (v Value) ParseInt64() (val int64, err error) {
   133  	return strconv.ParseInt(v.String(), 10, 64)
   134  }
   135  
   136  // ParseUint64 will parse a Value into a uint64. It does
   137  // not check the type.
   138  // TODO(sougou): deprecate this function in favor of a
   139  // more type-aware implemention in arithmetic.
   140  func (v Value) ParseUint64() (val uint64, err error) {
   141  	return strconv.ParseUint(v.String(), 10, 64)
   142  }
   143  
   144  // ParseFloat64 will parse a Value into an float64. It does
   145  // not check the type.
   146  // TODO(sougou): deprecate this function in favor of a
   147  // more type-aware implemention in arithmetic.
   148  func (v Value) ParseFloat64() (val float64, err error) {
   149  	return strconv.ParseFloat(v.String(), 64)
   150  }
   151  
   152  // EncodeSQL encodes the value into an SQL statement. Can be binary.
   153  func (v Value) EncodeSQL(b BinWriter) {
   154  	// ToNative panics if v is invalid.
   155  	_ = v.ToNative()
   156  	switch {
   157  	case v.typ == Null:
   158  		b.Write(nullstr)
   159  	case IsQuoted(v.typ):
   160  		encodeBytesSQL(v.val, b)
   161  	default:
   162  		b.Write(v.val)
   163  	}
   164  }
   165  
   166  // EncodeASCII encodes the value using 7-bit clean ascii bytes.
   167  func (v Value) EncodeASCII(b BinWriter) {
   168  	// ToNative panics if v is invalid.
   169  	_ = v.ToNative()
   170  	switch {
   171  	case v.typ == Null:
   172  		b.Write(nullstr)
   173  	case IsQuoted(v.typ):
   174  		encodeBytesASCII(v.val, b)
   175  	default:
   176  		b.Write(v.val)
   177  	}
   178  }
   179  
   180  func encodeBytesSQL(val []byte, b BinWriter) {
   181  	buf := &bytes2.Buffer{}
   182  	buf.WriteByte('\'')
   183  	for _, ch := range val {
   184  		if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape {
   185  			buf.WriteByte(ch)
   186  		} else {
   187  			buf.WriteByte('\\')
   188  			buf.WriteByte(encodedChar)
   189  		}
   190  	}
   191  	buf.WriteByte('\'')
   192  	b.Write(buf.Bytes())
   193  }
   194  
   195  func encodeBytesASCII(val []byte, b BinWriter) {
   196  	buf := &bytes2.Buffer{}
   197  	buf.WriteByte('\'')
   198  	encoder := base64.NewEncoder(base64.StdEncoding, buf)
   199  	encoder.Write(val)
   200  	encoder.Close()
   201  	buf.WriteByte('\'')
   202  	b.Write(buf.Bytes())
   203  }
   204  
   205  // SQLEncodeMap specifies how to escape binary data with '\'.
   206  // Complies to http://dev.mysql.com/doc/refman/5.1/en/string-syntax.html
   207  var SQLEncodeMap [256]byte
   208  
   209  // SQLDecodeMap is the reverse of SQLEncodeMap
   210  var SQLDecodeMap [256]byte
   211  
   212  var encodeRef = map[byte]byte{
   213  	'\x00': '0',
   214  	'\'':   '\'',
   215  	//'"':    '"',
   216  	//'\b': 'b',
   217  	//'\n': 'n',
   218  	//'\r': 'r',
   219  	//'\t': 't',
   220  	26:   'Z', // ctl-Z
   221  	'\\': '\\',
   222  }
   223  
   224  func init() {
   225  	for i := range SQLEncodeMap {
   226  		SQLEncodeMap[i] = DontEscape
   227  		SQLDecodeMap[i] = DontEscape
   228  	}
   229  	for i := range SQLEncodeMap {
   230  		if to, ok := encodeRef[byte(i)]; ok {
   231  			SQLEncodeMap[byte(i)] = to
   232  			SQLDecodeMap[to] = byte(i)
   233  		}
   234  	}
   235  }