229 lines
5.7 KiB
Go
229 lines
5.7 KiB
Go
// Copyright 2019 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//go:build !codes
|
|
// +build !codes
|
|
|
|
package test_driver
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/pingcap/tidb/parser/ast"
|
|
"github.com/pingcap/tidb/parser/charset"
|
|
"github.com/pingcap/tidb/parser/format"
|
|
"github.com/pingcap/tidb/parser/mysql"
|
|
)
|
|
|
|
func init() {
|
|
ast.NewValueExpr = newValueExpr
|
|
ast.NewParamMarkerExpr = newParamMarkerExpr
|
|
ast.NewDecimal = func(str string) (interface{}, error) {
|
|
dec := new(MyDecimal)
|
|
err := dec.FromString([]byte(str))
|
|
return dec, err
|
|
}
|
|
ast.NewHexLiteral = func(str string) (interface{}, error) {
|
|
h, err := NewHexLiteral(str)
|
|
return h, err
|
|
}
|
|
ast.NewBitLiteral = func(str string) (interface{}, error) {
|
|
b, err := NewBitLiteral(str)
|
|
return b, err
|
|
}
|
|
}
|
|
|
|
var (
|
|
_ ast.ParamMarkerExpr = &ParamMarkerExpr{}
|
|
_ ast.ValueExpr = &ValueExpr{}
|
|
)
|
|
|
|
// ValueExpr is the simple value expression.
|
|
type ValueExpr struct {
|
|
ast.TexprNode
|
|
Datum
|
|
projectionOffset int
|
|
}
|
|
|
|
// Restore implements Node interface.
|
|
func (n *ValueExpr) Restore(ctx *format.RestoreCtx) error {
|
|
switch n.Kind() {
|
|
case KindNull:
|
|
ctx.WriteKeyWord("NULL")
|
|
case KindInt64:
|
|
if n.Type.Flag&mysql.IsBooleanFlag != 0 {
|
|
if n.GetInt64() > 0 {
|
|
ctx.WriteKeyWord("TRUE")
|
|
} else {
|
|
ctx.WriteKeyWord("FALSE")
|
|
}
|
|
} else {
|
|
ctx.WritePlain(strconv.FormatInt(n.GetInt64(), 10))
|
|
}
|
|
case KindUint64:
|
|
ctx.WritePlain(strconv.FormatUint(n.GetUint64(), 10))
|
|
case KindFloat32:
|
|
ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32))
|
|
case KindFloat64:
|
|
ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64))
|
|
case KindString:
|
|
if n.Type.Charset != "" {
|
|
ctx.WritePlain("_")
|
|
ctx.WriteKeyWord(n.Type.Charset)
|
|
}
|
|
ctx.WriteString(n.GetString())
|
|
case KindBytes:
|
|
ctx.WriteString(n.GetString())
|
|
case KindMysqlDecimal:
|
|
ctx.WritePlain(n.GetMysqlDecimal().String())
|
|
case KindBinaryLiteral:
|
|
if n.Type.Charset != "" && n.Type.Charset != mysql.DefaultCharset &&
|
|
n.Type.Charset != charset.CharsetBin {
|
|
ctx.WritePlain("_")
|
|
ctx.WriteKeyWord(n.Type.Charset + " ")
|
|
}
|
|
if n.Type.Flag&mysql.UnsignedFlag != 0 {
|
|
ctx.WritePlainf("x'%x'", n.GetBytes())
|
|
} else {
|
|
ctx.WritePlain(n.GetBinaryLiteral().ToBitLiteralString(true))
|
|
}
|
|
case KindMysqlDuration, KindMysqlEnum,
|
|
KindMysqlBit, KindMysqlSet, KindMysqlTime,
|
|
KindInterface, KindMinNotNull, KindMaxValue,
|
|
KindRaw, KindMysqlJSON:
|
|
// TODO implement Restore function
|
|
return fmt.Errorf("not implemented")
|
|
default:
|
|
return fmt.Errorf("can't format to string")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDatumString implements the ValueExpr interface.
|
|
func (n *ValueExpr) GetDatumString() string {
|
|
return n.GetString()
|
|
}
|
|
|
|
// Format the ExprNode into a Writer.
|
|
func (n *ValueExpr) Format(w io.Writer) {
|
|
var s string
|
|
switch n.Kind() {
|
|
case KindNull:
|
|
s = "NULL"
|
|
case KindInt64:
|
|
if n.Type.Flag&mysql.IsBooleanFlag != 0 {
|
|
if n.GetInt64() > 0 {
|
|
s = "TRUE"
|
|
} else {
|
|
s = "FALSE"
|
|
}
|
|
} else {
|
|
s = strconv.FormatInt(n.GetInt64(), 10)
|
|
}
|
|
case KindUint64:
|
|
s = strconv.FormatUint(n.GetUint64(), 10)
|
|
case KindFloat32:
|
|
s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32)
|
|
case KindFloat64:
|
|
s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64)
|
|
case KindString, KindBytes:
|
|
s = strconv.Quote(n.GetString())
|
|
case KindMysqlDecimal:
|
|
s = n.GetMysqlDecimal().String()
|
|
case KindBinaryLiteral:
|
|
if n.Type.Flag&mysql.UnsignedFlag != 0 {
|
|
s = fmt.Sprintf("x'%x'", n.GetBytes())
|
|
} else {
|
|
s = n.GetBinaryLiteral().ToBitLiteralString(true)
|
|
}
|
|
default:
|
|
panic("Can't format to string")
|
|
}
|
|
_, _ = fmt.Fprint(w, s)
|
|
}
|
|
|
|
// newValueExpr creates a ValueExpr with value, and sets default field type.
|
|
func newValueExpr(value interface{}, charset string, collate string) ast.ValueExpr {
|
|
if ve, ok := value.(*ValueExpr); ok {
|
|
return ve
|
|
}
|
|
ve := &ValueExpr{}
|
|
ve.SetValue(value)
|
|
DefaultTypeForValue(value, &ve.Type, charset, collate)
|
|
ve.projectionOffset = -1
|
|
return ve
|
|
}
|
|
|
|
// SetProjectionOffset sets ValueExpr.projectionOffset for logical plan builder.
|
|
func (n *ValueExpr) SetProjectionOffset(offset int) {
|
|
n.projectionOffset = offset
|
|
}
|
|
|
|
// GetProjectionOffset returns ValueExpr.projectionOffset.
|
|
func (n *ValueExpr) GetProjectionOffset() int {
|
|
return n.projectionOffset
|
|
}
|
|
|
|
// Accept implements Node interface.
|
|
func (n *ValueExpr) Accept(v ast.Visitor) (ast.Node, bool) {
|
|
newNode, skipChildren := v.Enter(n)
|
|
if skipChildren {
|
|
return v.Leave(newNode)
|
|
}
|
|
n = newNode.(*ValueExpr)
|
|
return v.Leave(n)
|
|
}
|
|
|
|
// ParamMarkerExpr expression holds a place for another expression.
|
|
// Used in parsing prepare statement.
|
|
type ParamMarkerExpr struct {
|
|
ValueExpr
|
|
Offset int
|
|
Order int
|
|
InExecute bool
|
|
}
|
|
|
|
// Restore implements Node interface.
|
|
func (n *ParamMarkerExpr) Restore(ctx *format.RestoreCtx) error {
|
|
ctx.WritePlain("?")
|
|
return nil
|
|
}
|
|
|
|
func newParamMarkerExpr(offset int) ast.ParamMarkerExpr {
|
|
return &ParamMarkerExpr{
|
|
Offset: offset,
|
|
}
|
|
}
|
|
|
|
// Format the ExprNode into a Writer.
|
|
func (n *ParamMarkerExpr) Format(w io.Writer) {
|
|
panic("Not implemented")
|
|
}
|
|
|
|
// Accept implements Node Accept interface.
|
|
func (n *ParamMarkerExpr) Accept(v ast.Visitor) (ast.Node, bool) {
|
|
newNode, skipChildren := v.Enter(n)
|
|
if skipChildren {
|
|
return v.Leave(newNode)
|
|
}
|
|
n = newNode.(*ParamMarkerExpr)
|
|
return v.Leave(n)
|
|
}
|
|
|
|
// SetOrder implements the ParamMarkerExpr interface.
|
|
func (n *ParamMarkerExpr) SetOrder(order int) {
|
|
n.Order = order
|
|
}
|