提交 ed7d982a 编写于 作者: martianzhang's avatar martianzhang

update vendor

上级 441b0e88
......@@ -222,6 +222,17 @@ func (n *IndexColName) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}
// MatchType is the type for reference match type.
type MatchType int
// match type
const (
MatchNone MatchType = iota
MatchFull
MatchPartial
MatchSimple
)
// ReferenceDef is used for parsing foreign key reference option from SQL.
// See http://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html
type ReferenceDef struct {
......@@ -231,6 +242,7 @@ type ReferenceDef struct {
IndexColNames []*IndexColName
OnDelete *OnDeleteOpt
OnUpdate *OnUpdateOpt
Match MatchType
}
// Restore implements Node interface.
......@@ -251,6 +263,17 @@ func (n *ReferenceDef) Restore(ctx *RestoreCtx) error {
}
}
ctx.WritePlain(")")
if n.Match != MatchNone {
ctx.WriteKeyWord(" MATCH ")
switch n.Match {
case MatchFull:
ctx.WriteKeyWord("FULL")
case MatchPartial:
ctx.WriteKeyWord("PARTIAL")
case MatchSimple:
ctx.WriteKeyWord("SIMPLE")
}
}
if n.OnDelete.ReferOpt != ReferOptionNoOption {
ctx.WritePlain(" ")
if err := n.OnDelete.Restore(ctx); err != nil {
......@@ -308,6 +331,7 @@ const (
ReferOptionCascade
ReferOptionSetNull
ReferOptionNoAction
ReferOptionSetDefault
)
// String implements fmt.Stringer interface.
......@@ -321,6 +345,8 @@ func (r ReferOptionType) String() string {
return "SET NULL"
case ReferOptionNoAction:
return "NO ACTION"
case ReferOptionSetDefault:
return "SET DEFAULT"
}
return ""
}
......@@ -393,6 +419,7 @@ const (
ColumnOptionGenerated
ColumnOptionReference
ColumnOptionCollate
ColumnOptionCheck
)
var (
......@@ -417,6 +444,8 @@ type ColumnOption struct {
// Refer is used for foreign key.
Refer *ReferenceDef
StrValue string
// Enforced is only for Check, default is true.
Enforced bool
}
// Restore implements Node interface.
......@@ -473,6 +502,18 @@ func (n *ColumnOption) Restore(ctx *RestoreCtx) error {
}
ctx.WriteKeyWord("COLLATE ")
ctx.WritePlain(n.StrValue)
case ColumnOptionCheck:
ctx.WriteKeyWord("CHECK")
ctx.WritePlain("(")
if err := n.Expr.Restore(ctx); err != nil {
return errors.Trace(err)
}
ctx.WritePlain(")")
if n.Enforced {
ctx.WriteKeyWord(" ENFORCED")
} else {
ctx.WriteKeyWord(" NOT ENFORCED")
}
default:
return errors.New("An error occurred while splicing ColumnOption")
}
......@@ -562,12 +603,17 @@ const (
ConstraintUniqIndex
ConstraintForeignKey
ConstraintFulltext
ConstraintCheck
)
// Constraint is constraint for table definition.
type Constraint struct {
node
// only supported by MariaDB 10.0.2+ (ADD {INDEX|KEY}, ADD FOREIGN KEY),
// see https://mariadb.com/kb/en/library/alter-table/
IfNotExists bool
Tp ConstraintType
Name string
......@@ -576,6 +622,10 @@ type Constraint struct {
Refer *ReferenceDef // Used for foreign key.
Option *IndexOption // Index Options
Expr ExprNode // Used for Check
Enforced bool // Used for Check
}
// Restore implements Node interface.
......@@ -587,8 +637,14 @@ func (n *Constraint) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("PRIMARY KEY")
case ConstraintKey:
ctx.WriteKeyWord("KEY")
if n.IfNotExists {
ctx.WriteKeyWord(" IF NOT EXISTS")
}
case ConstraintIndex:
ctx.WriteKeyWord("INDEX")
if n.IfNotExists {
ctx.WriteKeyWord(" IF NOT EXISTS")
}
case ConstraintUniq:
ctx.WriteKeyWord("UNIQUE")
case ConstraintUniqKey:
......@@ -597,6 +653,24 @@ func (n *Constraint) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("UNIQUE INDEX")
case ConstraintFulltext:
ctx.WriteKeyWord("FULLTEXT")
case ConstraintCheck:
if n.Name != "" {
ctx.WriteKeyWord("CONSTRAINT ")
ctx.WriteName(n.Name)
ctx.WritePlain(" ")
}
ctx.WriteKeyWord("CHECK")
ctx.WritePlain("(")
if err := n.Expr.Restore(ctx); err != nil {
return errors.Trace(err)
}
ctx.WritePlain(") ")
if n.Enforced {
ctx.WriteKeyWord("ENFORCED")
} else {
ctx.WriteKeyWord("NOT ENFORCED")
}
return nil
}
if n.Tp == ConstraintForeignKey {
......@@ -606,6 +680,9 @@ func (n *Constraint) Restore(ctx *RestoreCtx) error {
ctx.WritePlain(" ")
}
ctx.WriteKeyWord("FOREIGN KEY ")
if n.IfNotExists {
ctx.WriteKeyWord("IF NOT EXISTS ")
}
} else if n.Name != "" {
ctx.WritePlain(" ")
ctx.WriteName(n.Name)
......@@ -882,9 +959,10 @@ func (n *CreateTableStmt) Accept(v Visitor) (Node, bool) {
type DropTableStmt struct {
ddlNode
IfExists bool
Tables []*TableName
IsView bool
IfExists bool
Tables []*TableName
IsView bool
IsTemporary bool // make sense ONLY if/when IsView == false
}
// Restore implements Node interface.
......@@ -892,7 +970,11 @@ func (n *DropTableStmt) Restore(ctx *RestoreCtx) error {
if n.IsView {
ctx.WriteKeyWord("DROP VIEW ")
} else {
ctx.WriteKeyWord("DROP TABLE ")
if n.IsTemporary {
ctx.WriteKeyWord("DROP TEMPORARY TABLE ")
} else {
ctx.WriteKeyWord("DROP TABLE ")
}
}
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
......@@ -1120,6 +1202,10 @@ func (n *CreateViewStmt) Accept(v Visitor) (Node, bool) {
type CreateIndexStmt struct {
ddlNode
// only supported by MariaDB 10.0.2+,
// see https://mariadb.com/kb/en/library/create-index/
IfNotExists bool
IndexName string
Table *TableName
Unique bool
......@@ -1134,6 +1220,9 @@ func (n *CreateIndexStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("UNIQUE ")
}
ctx.WriteKeyWord("INDEX ")
if n.IfNotExists {
ctx.WriteKeyWord("IF NOT EXISTS ")
}
ctx.WriteName(n.IndexName)
ctx.WriteKeyWord(" ON ")
if err := n.Table.Restore(ctx); err != nil {
......@@ -1293,6 +1382,44 @@ func (n *UnlockTablesStmt) Restore(ctx *RestoreCtx) error {
return nil
}
// CleanupTableLockStmt is a statement to cleanup table lock.
type CleanupTableLockStmt struct {
ddlNode
Tables []*TableName
}
// Accept implements Node Accept interface.
func (n *CleanupTableLockStmt) Accept(v Visitor) (Node, bool) {
newNode, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNode)
}
n = newNode.(*CleanupTableLockStmt)
for i := range n.Tables {
node, ok := n.Tables[i].Accept(v)
if !ok {
return n, false
}
n.Tables[i] = node.(*TableName)
}
return v.Leave(n)
}
// Restore implements Node interface.
func (n *CleanupTableLockStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("ADMIN CLEANUP TABLE LOCK ")
for i, v := range n.Tables {
if i != 0 {
ctx.WritePlain(", ")
}
if err := v.Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while restore CleanupTableLockStmt.Tables[%d]", i)
}
}
return nil
}
// TableOptionType is the type for TableOption
type TableOptionType int
......@@ -1322,6 +1449,8 @@ const (
TableOptionNodegroup
TableOptionDataDirectory
TableOptionIndexDirectory
TableOptionStorageMedia
TableOptionStatsSamplePages
)
// RowFormat types
......@@ -1491,6 +1620,17 @@ func (n *TableOption) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("INDEX DIRECTORY ")
ctx.WritePlain("= ")
ctx.WriteString(n.StrValue)
case TableOptionStorageMedia:
ctx.WriteKeyWord("STORAGE ")
ctx.WriteKeyWord(n.StrValue)
case TableOptionStatsSamplePages:
ctx.WriteKeyWord("STATS_SAMPLE_PAGES ")
ctx.WritePlain("= ")
if n.UintValue == 0 {
ctx.WriteKeyWord("DEFAULT")
} else {
ctx.WritePlainf("%d", n.UintValue)
}
default:
return errors.Errorf("invalid TableOption: %d", n.Tp)
}
......@@ -1578,6 +1718,7 @@ const (
AlterTablePartition
AlterTableEnableKeys
AlterTableDisableKeys
AlterTableRemovePartitioning
// TODO: Add more actions
)
......@@ -1641,6 +1782,14 @@ func (a AlterAlgorithm) String() string {
type AlterTableSpec struct {
node
// only supported by MariaDB 10.0.2+ (DROP COLUMN, CHANGE COLUMN, MODIFY COLUMN, DROP INDEX, DROP FOREIGN KEY, DROP PARTITION)
// see https://mariadb.com/kb/en/library/alter-table/
IfExists bool
// only supported by MariaDB 10.0.2+ (ADD COLUMN, ADD PARTITION)
// see https://mariadb.com/kb/en/library/alter-table/
IfNotExists bool
Tp AlterTableType
Name string
Constraint *Constraint
......@@ -1684,6 +1833,9 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
}
case AlterTableAddColumns:
ctx.WriteKeyWord("ADD COLUMN ")
if n.IfNotExists {
ctx.WriteKeyWord("IF NOT EXISTS ")
}
if n.Position != nil && len(n.NewColumns) == 1 {
if err := n.NewColumns[0].Restore(ctx); err != nil {
return errors.Annotatef(err, "An error occurred while restore AlterTableSpec.NewColumns[%d]", 0)
......@@ -1713,6 +1865,9 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
}
case AlterTableDropColumn:
ctx.WriteKeyWord("DROP COLUMN ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
if err := n.OldColumnName.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.OldColumnName")
}
......@@ -1721,12 +1876,21 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("DROP PRIMARY KEY")
case AlterTableDropIndex:
ctx.WriteKeyWord("DROP INDEX ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
ctx.WriteName(n.Name)
case AlterTableDropForeignKey:
ctx.WriteKeyWord("DROP FOREIGN KEY ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
ctx.WriteName(n.Name)
case AlterTableModifyColumn:
ctx.WriteKeyWord("MODIFY COLUMN ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
if err := n.NewColumns[0].Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.NewColumns[0]")
}
......@@ -1738,6 +1902,9 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
}
case AlterTableChangeColumn:
ctx.WriteKeyWord("CHANGE COLUMN ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
if err := n.OldColumnName.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.OldColumnName")
}
......@@ -1763,8 +1930,17 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
}
if len(n.NewColumns[0].Options) == 1 {
ctx.WriteKeyWord("SET DEFAULT ")
if err := n.NewColumns[0].Options[0].Expr.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.NewColumns[0].Options[0].Expr")
expr := n.NewColumns[0].Options[0].Expr
if valueExpr, ok := expr.(ValueExpr); ok {
if err := valueExpr.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.NewColumns[0].Options[0].Expr")
}
} else {
ctx.WritePlain("(")
if err := expr.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore AlterTableSpec.NewColumns[0].Options[0].Expr")
}
ctx.WritePlain(")")
}
} else {
ctx.WriteKeyWord(" DROP DEFAULT")
......@@ -1788,6 +1964,9 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
ctx.WritePlain(" /* AlterTableForce is not supported */ ")
case AlterTableAddPartitions:
ctx.WriteKeyWord("ADD PARTITION")
if n.IfNotExists {
ctx.WriteKeyWord(" IF NOT EXISTS")
}
if n.PartDefinitions != nil {
ctx.WritePlain(" (")
for i, def := range n.PartDefinitions {
......@@ -1808,6 +1987,9 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
ctx.WritePlainf("%d", n.Num)
case AlterTableDropPartition:
ctx.WriteKeyWord("DROP PARTITION ")
if n.IfExists {
ctx.WriteKeyWord("IF EXISTS ")
}
for i, name := range n.PartitionNames {
if i != 0 {
ctx.WritePlain(",")
......@@ -1830,6 +2012,8 @@ func (n *AlterTableSpec) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("ENABLE KEYS")
case AlterTableDisableKeys:
ctx.WriteKeyWord("DISABLE KEYS")
case AlterTableRemovePartitioning:
ctx.WriteKeyWord("REMOVE PARTITIONING")
default:
// TODO: not support
ctx.WritePlainf(" /* AlterTableType(%d) is not supported */ ", n.Tp)
......@@ -1898,7 +2082,7 @@ func (n *AlterTableStmt) Restore(ctx *RestoreCtx) error {
return errors.Annotate(err, "An error occurred while restore AlterTableStmt.Table")
}
for i, spec := range n.Specs {
if i == 0 || spec.Tp == AlterTablePartition {
if i == 0 || spec.Tp == AlterTablePartition || spec.Tp == AlterTableRemovePartitioning {
ctx.WritePlain(" ")
} else {
ctx.WritePlain(", ")
......
......@@ -1827,6 +1827,7 @@ const (
ShowDrainerStatus
ShowOpenTables
ShowAnalyzeStatus
ShowRegions
)
const (
......@@ -1852,7 +1853,8 @@ type ShowStmt struct {
DBName string
Table *TableName // Used for showing columns.
Column *ColumnName // Used for `desc table column`.
Flag int // Some flag parsed from sql, such as FULL.
IndexName model.CIStr
Flag int // Some flag parsed from sql, such as FULL.
Full bool
User *auth.UserIdentity // Used for show grants/create user.
Roles []*auth.RoleIdentity // Used for show grants .. using
......@@ -2088,6 +2090,17 @@ func (n *ShowStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("DRAINER STATUS")
case ShowAnalyzeStatus:
ctx.WriteKeyWord("ANALYZE STATUS")
case ShowRegions:
ctx.WriteKeyWord("TABLE ")
if err := n.Table.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while restore SplitIndexRegionStmt.Table")
}
if len(n.IndexName.L) > 0 {
ctx.WriteKeyWord(" INDEX ")
ctx.WriteName(n.IndexName.String())
}
ctx.WriteKeyWord(" REGIONS")
return nil
default:
return errors.New("Unknown ShowStmt type")
}
......
......@@ -200,6 +200,7 @@ const (
MakeSet = "make_set"
Mid = "mid"
Oct = "oct"
OctetLength = "octet_length"
Ord = "ord"
Position = "position"
Quote = "quote"
......
......@@ -327,9 +327,10 @@ type Prepared struct {
type ExecuteStmt struct {
stmtNode
Name string
UsingVars []ExprNode
ExecID uint32
Name string
UsingVars []ExprNode
BinaryArgs interface{}
ExecID uint32
}
// Restore implements Node interface.
......@@ -1380,6 +1381,9 @@ const (
AdminShowSlow
AdminShowNextRowID
AdminReloadExprPushdownBlacklist
AdminReloadOptRuleBlacklist
AdminPluginDisable
AdminPluginEnable
)
// HandleRange represents a range where handle value >= Begin and < End.
......@@ -1455,6 +1459,7 @@ type AdminStmt struct {
HandleRanges []HandleRange
ShowSlow *ShowSlow
Plugins []string
}
// Restore implements Node interface.
......@@ -1550,6 +1555,28 @@ func (n *AdminStmt) Restore(ctx *RestoreCtx) error {
}
case AdminReloadExprPushdownBlacklist:
ctx.WriteKeyWord("RELOAD EXPR_PUSHDOWN_BLACKLIST")
case AdminReloadOptRuleBlacklist:
ctx.WriteKeyWord("RELOAD OPT_RULE_BLACKLIST")
case AdminPluginEnable:
ctx.WriteKeyWord("PLUGINS ENABLE")
for i, v := range n.Plugins {
if i == 0 {
ctx.WritePlain(" ")
} else {
ctx.WritePlain(", ")
}
ctx.WritePlain(v)
}
case AdminPluginDisable:
ctx.WriteKeyWord("PLUGINS DISABLE")
for i, v := range n.Plugins {
if i == 0 {
ctx.WritePlain(" ")
} else {
ctx.WritePlain(", ")
}
ctx.WritePlain(v)
}
default:
return errors.New("Unsupported AdminStmt type")
}
......@@ -1585,51 +1612,17 @@ type PrivElem struct {
// Restore implements Node interface.
func (n *PrivElem) Restore(ctx *RestoreCtx) error {
switch n.Priv {
case 0:
if n.Priv == 0 {
ctx.WritePlain("/* UNSUPPORTED TYPE */")
case mysql.AllPriv:
} else if n.Priv == mysql.AllPriv {
ctx.WriteKeyWord("ALL")
case mysql.AlterPriv:
ctx.WriteKeyWord("ALTER")
case mysql.CreatePriv:
ctx.WriteKeyWord("CREATE")
case mysql.CreateUserPriv:
ctx.WriteKeyWord("CREATE USER")
case mysql.CreateRolePriv:
ctx.WriteKeyWord("CREATE ROLE")
case mysql.TriggerPriv:
ctx.WriteKeyWord("TRIGGER")
case mysql.DeletePriv:
ctx.WriteKeyWord("DELETE")
case mysql.DropPriv:
ctx.WriteKeyWord("DROP")
case mysql.ProcessPriv:
ctx.WriteKeyWord("PROCESS")
case mysql.ExecutePriv:
ctx.WriteKeyWord("EXECUTE")
case mysql.IndexPriv:
ctx.WriteKeyWord("INDEX")
case mysql.InsertPriv:
ctx.WriteKeyWord("INSERT")
case mysql.SelectPriv:
ctx.WriteKeyWord("SELECT")
case mysql.SuperPriv:
ctx.WriteKeyWord("SUPER")
case mysql.ShowDBPriv:
ctx.WriteKeyWord("SHOW DATABASES")
case mysql.UpdatePriv:
ctx.WriteKeyWord("UPDATE")
case mysql.GrantPriv:
ctx.WriteKeyWord("GRANT OPTION")
case mysql.ReferencesPriv:
ctx.WriteKeyWord("REFERENCES")
case mysql.CreateViewPriv:
ctx.WriteKeyWord("CREATE VIEW")
case mysql.ShowViewPriv:
ctx.WriteKeyWord("SHOW VIEW")
default:
return errors.New("Undefined privilege type")
} else {
str, ok := mysql.Priv2Str[n.Priv]
if ok {
ctx.WriteKeyWord(str)
} else {
return errors.New("Undefined privilege type")
}
}
if n.Cols != nil {
ctx.WritePlain(" (")
......@@ -2005,9 +1998,10 @@ type TableOptimizerHint struct {
func (n *TableOptimizerHint) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord(n.HintName.String())
ctx.WritePlain("(")
if n.HintName.L == "max_execution_time" {
switch n.HintName.L {
case "max_execution_time":
ctx.WritePlainf("%d", n.MaxExecutionTime)
} else {
case "tidb_hj", "tidb_smj", "tidb_inlj":
for i, table := range n.Tables {
if i != 0 {
ctx.WritePlain(", ")
......@@ -2029,6 +2023,10 @@ func (n *TableOptimizerHint) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}
type BinaryLiteral interface {
ToString() string
}
// NewDecimal creates a types.Decimal value, it's provided by parser driver.
var NewDecimal func(string) (interface{}, error)
......
......@@ -32,13 +32,38 @@ type AnalyzeTableStmt struct {
TableNames []*TableName
PartitionNames []model.CIStr
IndexNames []model.CIStr
MaxNumBuckets uint64
AnalyzeOpts []AnalyzeOpt
// IndexFlag is true when we only analyze indices for a table.
IndexFlag bool
Incremental bool
}
// AnalyzeOptType is the type for analyze options.
type AnalyzeOptionType int
// Analyze option types.
const (
AnalyzeOptNumBuckets = iota
AnalyzeOptNumTopN
AnalyzeOptCMSketchDepth
AnalyzeOptCMSketchWidth
)
// AnalyzeOptionString stores the string form of analyze options.
var AnalyzeOptionString = map[AnalyzeOptionType]string{
AnalyzeOptNumBuckets: "BUCKETS",
AnalyzeOptNumTopN: "TOPN",
AnalyzeOptCMSketchWidth: "CMSKETCH WIDTH",
AnalyzeOptCMSketchDepth: "CMSKETCH DEPTH",
}
// AnalyzeOpt stores the analyze option type and value.
type AnalyzeOpt struct {
Type AnalyzeOptionType
Value uint64
}
// Restore implements Node interface.
func (n *AnalyzeTableStmt) Restore(ctx *RestoreCtx) error {
if n.Incremental {
......@@ -74,10 +99,15 @@ func (n *AnalyzeTableStmt) Restore(ctx *RestoreCtx) error {
}
ctx.WriteName(index.O)
}
if n.MaxNumBuckets != 0 {
ctx.WriteKeyWord(" WITH ")
ctx.WritePlainf("%d", n.MaxNumBuckets)
ctx.WriteKeyWord(" BUCKETS")
if len(n.AnalyzeOpts) != 0 {
ctx.WriteKeyWord(" WITH")
for i, opt := range n.AnalyzeOpts {
if i != 0 {
ctx.WritePlain(",")
}
ctx.WritePlainf(" %d ", opt.Value)
ctx.WritePlain(AnalyzeOptionString[opt.Type])
}
}
return nil
}
......
......@@ -27,7 +27,9 @@ func IsReadOnly(node Node) bool {
node.Accept(&checker)
return checker.readOnly
case *ExplainStmt, *DoStmt:
case *ExplainStmt:
return !st.Analyze || IsReadOnly(st.Stmt)
case *DoStmt:
return true
default:
return false
......
......@@ -9,8 +9,8 @@ require (
github.com/cznic/y v0.0.0-20170802143616-045f81c6662a
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8
github.com/pingcap/errors v0.11.4
github.com/pingcap/tidb v0.0.0-20190321025159-e8299209340c
github.com/pingcap/tipb v0.0.0-20190107072121-abbec73437b7
github.com/pingcap/tidb v0.0.0-20190703092821-755875aacb5a
github.com/pingcap/tipb v0.0.0-20190428032612-535e1abaa330
github.com/sirupsen/logrus v1.3.0
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2
)
......@@ -211,9 +211,11 @@ func (s *Scanner) Lex(v *yySymType) int {
case quotedIdentifier:
tok = identifier
}
if tok == unicode.ReplacementChar && s.r.eof() {
return 0
if tok == unicode.ReplacementChar {
return invalid
}
return tok
}
......
......@@ -183,6 +183,7 @@ var tokenMap = map[string]int{
"CIPHER": cipher,
"CLEANUP": cleanup,
"CLIENT": client,
"CMSKETCH": cmSketch,
"COALESCE": coalesce,
"COLLATE": collate,
"COLLATION": collation,
......@@ -232,10 +233,12 @@ var tokenMap = map[string]int{
"DELAY_KEY_WRITE": delayKeyWrite,
"DELAYED": delayed,
"DELETE": deleteKwd,
"DEPTH": depth,
"DESC": desc,
"DESCRIBE": describe,
"DIRECTORY": directory,
"DISABLE": disable,
"DISK": disk,
"DISTINCT": distinct,
"DISTINCTROW": distinct,
"DIV": div,
......@@ -250,6 +253,7 @@ var tokenMap = map[string]int{
"ENABLE": enable,
"ENCLOSED": enclosed,
"END": end,
"ENFORCED": enforced,
"ENGINE": engine,
"ENGINES": engines,
"ENUM": enum,
......@@ -351,6 +355,7 @@ var tokenMap = map[string]int{
"LONGTEXT": longtextType,
"LOW_PRIORITY": lowPriority,
"MASTER": master,
"MATCH": match,
"MAX": max,
"MAX_CONNECTIONS_PER_HOUR": maxConnectionsPerHour,
"MAX_EXECUTION_TIME": maxExecutionTime,
......@@ -402,7 +407,9 @@ var tokenMap = map[string]int{
"OUTER": outer,
"PACK_KEYS": packKeys,
"PAGE": pageSym,
"PARTIAL": partial,
"PARTITION": partition,
"PARTITIONING": partitioning,
"PARTITIONS": partitions,
"PASSWORD": password,
"PESSIMISTIC": pessimistic,
......@@ -435,6 +442,7 @@ var tokenMap = map[string]int{
"REGEXP": regexpKwd,
"REGIONS": regions,
"RELOAD": reload,
"REMOVE": remove,
"RENAME": rename,
"REPEAT": repeat,
"REPEATABLE": repeatable,
......@@ -467,6 +475,7 @@ var tokenMap = map[string]int{
"SHARED": shared,
"SHOW": show,
"SIGNED": signed,
"SIMPLE": simple,
"SLAVE": slave,
"SLOW": slow,
"SMALLINT": smallIntType,
......@@ -490,7 +499,9 @@ var tokenMap = map[string]int{
"STATS_HEALTHY": statsHealthy,
"STATS_META": statsMeta,
"STATS_PERSISTENT": statsPersistent,
"STATS_SAMPLE_PAGES": statsSamplePages,
"STATUS": status,
"STORAGE": storage,
"SWAPS": swaps,
"SWITCHES": switchesSym,
"SYSTEM_TIME": systemTime,
......@@ -522,6 +533,8 @@ var tokenMap = map[string]int{
"TIDB_HJ": tidbHJ,
"TIDB_INLJ": tidbINLJ,
"TIDB_SMJ": tidbSMJ,
"TIDB_HASHAGG": tidbHASHAGG,
"TIDB_STREAMAGG": tidbSTREAMAGG,
"TIME": timeType,
"TIMESTAMP": timestampType,
"TIMESTAMPADD": timestampAdd,
......@@ -539,6 +552,7 @@ var tokenMap = map[string]int{
"TOKUDB_UNCOMPRESSED": tokudbUncompressed,
"TOKUDB_ZLIB": tokudbZlib,
"TOP": top,
"TOPN": topn,
"TRACE": trace,
"TRADITIONAL": traditional,
"TRAILING": trailing,
......@@ -579,6 +593,7 @@ var tokenMap = map[string]int{
"WEEK": week,
"WHEN": when,
"WHERE": where,
"WIDTH": width,
"WITH": with,
"WRITE": write,
"XOR": xor,
......@@ -589,6 +604,7 @@ var tokenMap = map[string]int{
"BINDING": binding,
"BINDINGS": bindings,
"EXPR_PUSHDOWN_BLACKLIST": exprPushdownBlacklist,
"OPT_RULE_BLACKLIST": optRuleBlacklist,
}
// See https://dev.mysql.com/doc/refman/5.7/en/function-resolution.html for details
......
......@@ -42,4 +42,6 @@ const (
FlagDividedByZeroAsWarning = 1 << 8
// FlagInUnionStmt indicates if this is a UNION statement.
FlagInUnionStmt = 1 << 9
// FlagInLoadDataStmt indicates if this is a LOAD DATA statement.
FlagInLoadDataStmt = 1 << 10
)
......@@ -233,6 +233,13 @@ const (
CreateRolePriv
// DropRolePriv is the privilege to drop a role.
DropRolePriv
CreateTMPTablePriv
LockTablesPriv
CreateRoutinePriv
AlterRoutinePriv
EventPriv
// AllPriv is the privilege for all actions.
AllPriv
)
......@@ -276,26 +283,60 @@ const PWDHashLen = 40
// Priv2UserCol is the privilege to mysql.user table column name.
var Priv2UserCol = map[PrivilegeType]string{
CreatePriv: "Create_priv",
SelectPriv: "Select_priv",
InsertPriv: "Insert_priv",
UpdatePriv: "Update_priv",
DeletePriv: "Delete_priv",
ShowDBPriv: "Show_db_priv",
SuperPriv: "Super_priv",
CreateUserPriv: "Create_user_priv",
TriggerPriv: "Trigger_priv",
DropPriv: "Drop_priv",
ProcessPriv: "Process_priv",
GrantPriv: "Grant_priv",
ReferencesPriv: "References_priv",
AlterPriv: "Alter_priv",
ExecutePriv: "Execute_priv",
IndexPriv: "Index_priv",
CreateViewPriv: "Create_view_priv",
ShowViewPriv: "Show_view_priv",
CreateRolePriv: "Create_role_priv",
DropRolePriv: "Drop_role_priv",
CreatePriv: "Create_priv",
SelectPriv: "Select_priv",
InsertPriv: "Insert_priv",
UpdatePriv: "Update_priv",
DeletePriv: "Delete_priv",
ShowDBPriv: "Show_db_priv",
SuperPriv: "Super_priv",
CreateUserPriv: "Create_user_priv",
TriggerPriv: "Trigger_priv",
DropPriv: "Drop_priv",
ProcessPriv: "Process_priv",
GrantPriv: "Grant_priv",
ReferencesPriv: "References_priv",
AlterPriv: "Alter_priv",
ExecutePriv: "Execute_priv",
IndexPriv: "Index_priv",
CreateViewPriv: "Create_view_priv",
ShowViewPriv: "Show_view_priv",
CreateRolePriv: "Create_role_priv",
DropRolePriv: "Drop_role_priv",
CreateTMPTablePriv: "Create_tmp_table_priv",
LockTablesPriv: "Lock_tables_priv",
CreateRoutinePriv: "Create_routine_priv",
AlterRoutinePriv: "Alter_routine_priv",
EventPriv: "Event_priv",
}
// Col2PrivType is the privilege tables column name to privilege type.
var Col2PrivType = map[string]PrivilegeType{
"Create_priv": CreatePriv,
"Select_priv": SelectPriv,
"Insert_priv": InsertPriv,
"Update_priv": UpdatePriv,
"Delete_priv": DeletePriv,
"Show_db_priv": ShowDBPriv,
"Super_priv": SuperPriv,
"Create_user_priv": CreateUserPriv,
"Trigger_priv": TriggerPriv,
"Drop_priv": DropPriv,
"Process_priv": ProcessPriv,
"Grant_priv": GrantPriv,
"References_priv": ReferencesPriv,
"Alter_priv": AlterPriv,
"Execute_priv": ExecutePriv,
"Index_priv": IndexPriv,
"Create_view_priv": CreateViewPriv,
"Show_view_priv": ShowViewPriv,
"Create_role_priv": CreateRolePriv,
"Drop_role_priv": DropRolePriv,
"Create_tmp_table_priv": CreateTMPTablePriv,
"Lock_tables_priv": LockTablesPriv,
"Create_routine_priv": CreateRoutinePriv,
"Alter_routine_priv": AlterRoutinePriv,
"Event_priv": EventPriv,
}
// Command2Str is the command information to command name.
......@@ -334,55 +375,33 @@ var Command2Str = map[byte]string{
ComResetConnection: "Reset connect",
}
// Col2PrivType is the privilege tables column name to privilege type.
var Col2PrivType = map[string]PrivilegeType{
"Create_priv": CreatePriv,
"Select_priv": SelectPriv,
"Insert_priv": InsertPriv,
"Update_priv": UpdatePriv,
"Delete_priv": DeletePriv,
"Show_db_priv": ShowDBPriv,
"Super_priv": SuperPriv,
"Create_user_priv": CreateUserPriv,
"Trigger_priv": TriggerPriv,
"Drop_priv": DropPriv,
"Process_priv": ProcessPriv,
"Grant_priv": GrantPriv,
"References_priv": ReferencesPriv,
"Alter_priv": AlterPriv,
"Execute_priv": ExecutePriv,
"Index_priv": IndexPriv,
"Create_view_priv": CreateViewPriv,
"Show_view_priv": ShowViewPriv,
"Create_role_priv": CreateRolePriv,
"Drop_role_priv": DropRolePriv,
}
// AllGlobalPrivs is all the privileges in global scope.
var AllGlobalPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, ProcessPriv, GrantPriv, ReferencesPriv, AlterPriv, ShowDBPriv, SuperPriv, ExecutePriv, IndexPriv, CreateUserPriv, TriggerPriv, CreateViewPriv, ShowViewPriv, CreateRolePriv, DropRolePriv}
// Priv2Str is the map for privilege to string.
var Priv2Str = map[PrivilegeType]string{
CreatePriv: "Create",
SelectPriv: "Select",
InsertPriv: "Insert",
UpdatePriv: "Update",
DeletePriv: "Delete",
ShowDBPriv: "Show Databases",
SuperPriv: "Super",
CreateUserPriv: "Create User",
TriggerPriv: "Trigger",
DropPriv: "Drop",
ProcessPriv: "Process",
GrantPriv: "Grant Option",
ReferencesPriv: "References",
AlterPriv: "Alter",
ExecutePriv: "Execute",
IndexPriv: "Index",
CreateViewPriv: "Create View",
ShowViewPriv: "Show View",
CreateRolePriv: "Create Role",
DropRolePriv: "Drop Role",
CreatePriv: "Create",
SelectPriv: "Select",
InsertPriv: "Insert",
UpdatePriv: "Update",
DeletePriv: "Delete",
ShowDBPriv: "Show Databases",
SuperPriv: "Super",
CreateUserPriv: "Create User",
TriggerPriv: "Trigger",
DropPriv: "Drop",
ProcessPriv: "Process",
GrantPriv: "Grant Option",
ReferencesPriv: "References",
AlterPriv: "Alter",
ExecutePriv: "Execute",
IndexPriv: "Index",
CreateViewPriv: "Create View",
ShowViewPriv: "Show View",
CreateRolePriv: "Create Role",
DropRolePriv: "Drop Role",
CreateTMPTablePriv: "CREATE TEMPORARY TABLES",
LockTablesPriv: "LOCK TABLES",
CreateRoutinePriv: "CREATE ROUTINE",
AlterRoutinePriv: "ALTER ROUTINE",
EventPriv: "EVENT",
}
// Priv2SetStr is the map for privilege to string.
......@@ -419,6 +438,9 @@ var SetStr2Priv = map[string]PrivilegeType{
"Show View": ShowViewPriv,
}
// AllGlobalPrivs is all the privileges in global scope.
var AllGlobalPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, ProcessPriv, GrantPriv, ReferencesPriv, AlterPriv, ShowDBPriv, SuperPriv, ExecutePriv, IndexPriv, CreateUserPriv, TriggerPriv, CreateViewPriv, ShowViewPriv, CreateRolePriv, DropRolePriv, CreateTMPTablePriv, LockTablesPriv, CreateRoutinePriv, AlterRoutinePriv, EventPriv}
// AllDBPrivs is all the privileges in database scope.
var AllDBPrivs = []PrivilegeType{SelectPriv, InsertPriv, UpdatePriv, DeletePriv, CreatePriv, DropPriv, GrantPriv, AlterPriv, ExecutePriv, IndexPriv, CreateViewPriv, ShowViewPriv}
......
......@@ -255,4 +255,5 @@ var MySQLState = map[uint16]string{
ErrInvalidJSONData: "22032",
ErrInvalidJSONPathWildcard: "42000",
ErrJSONUsedAsKey: "42000",
ErrInvalidJSONPathArrayCell: "42000",
}
......@@ -79,6 +79,7 @@ var defaultLengthAndDecimalForCast = map[byte]lengthAndDecimal{
TypeNewDecimal: {11, 0},
TypeDuration: {10, 0},
TypeLonglong: {22, 0},
TypeDouble: {22, -1},
TypeJSON: {4194304, 0}, // Flen differs.
}
......
{
mv go.mod1 go.mod
mv go.sum1 go.sum
GO111MODULE=on go test -race -covermode=atomic -coverprofile=coverage.txt ./...
GO111MODULE=on go test -p 1 -race -covermode=atomic -coverprofile=coverage.txt -coverpkg=./... ./...
} || {
mv go.mod go.mod1
mv go.sum go.sum1
......
......@@ -299,6 +299,8 @@ func (ft *FieldType) RestoreAsCastType(ctx *format.RestoreCtx) {
}
case mysql.TypeJSON:
ctx.WriteKeyWord("JSON")
case mysql.TypeDouble:
ctx.WriteKeyWord("DOUBLE")
}
}
......
......@@ -34,6 +34,8 @@ const (
codeWrongArgument = terror.ErrCode(mysql.ErrWrongArguments)
codeWrongFieldTerminators = terror.ErrCode(mysql.ErrWrongFieldTerminators)
codeTooBigDisplayWidth = terror.ErrCode(mysql.ErrTooBigDisplaywidth)
codeErrUnknownAlterLock = terror.ErrCode(mysql.ErrUnknownAlterLock)
codeErrUnknownAlterAlgorithm = terror.ErrCode(mysql.ErrUnknownAlterAlgorithm)
)
var (
......@@ -51,7 +53,10 @@ var (
ErrWrongFieldTerminators = terror.ClassParser.New(codeWrongFieldTerminators, mysql.MySQLErrName[mysql.ErrWrongFieldTerminators])
// ErrTooBigDisplayWidth returns for data display width exceed limit .
ErrTooBigDisplayWidth = terror.ClassParser.New(codeTooBigDisplayWidth, mysql.MySQLErrName[mysql.ErrTooBigDisplaywidth])
// ErrUnknownAlterLock returns for no alter lock type found error.
ErrUnknownAlterLock = terror.ClassParser.New(codeErrUnknownAlterLock, mysql.MySQLErrName[mysql.ErrUnknownAlterLock])
// ErrUnknownAlterAlgorithm returns for no alter algorithm found error.
ErrUnknownAlterAlgorithm = terror.ClassParser.New(codeErrUnknownAlterAlgorithm, mysql.MySQLErrName[mysql.ErrUnknownAlterAlgorithm])
// SpecFieldPattern special result field pattern
SpecFieldPattern = regexp.MustCompile(`(\/\*!(M?[0-9]{5,6})?|\*\/)`)
specCodePattern = regexp.MustCompile(`\/\*!(M?[0-9]{5,6})?([^*]|\*+[^*/])*\*+\/`)
......@@ -68,6 +73,8 @@ func init() {
codeWrongArgument: mysql.ErrWrongArguments,
codeWrongFieldTerminators: mysql.ErrWrongFieldTerminators,
codeTooBigDisplayWidth: mysql.ErrTooBigDisplaywidth,
codeErrUnknownAlterLock: mysql.ErrUnknownAlterLock,
codeErrUnknownAlterAlgorithm: mysql.ErrUnknownAlterAlgorithm,
}
terror.ErrClassToMySQLCodes[terror.ClassParser] = parserMySQLErrCodes
}
......
......@@ -21,6 +21,7 @@ import (
"time"
"github.com/pingcap/parser"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/util/execdetails"
"github.com/pingcap/tidb/util/memory"
......@@ -69,6 +70,11 @@ type StatementContext struct {
BatchCheck bool
InNullRejectCheck bool
AllowInvalidDate bool
// CastStrToIntStrict is used to control the way we cast float format string to int.
// If ConvertStrToIntStrict is false, we convert it to a valid float string first,
// then cast the float string to int string. Otherwise, we cast string to integer
// prefix in a strict way, only extract 0-9 and (+ or - in first bit).
CastStrToIntStrict bool
// mu struct holds variables that change during execution.
mu struct {
......@@ -119,8 +125,8 @@ type StatementContext struct {
RuntimeStatsColl *execdetails.RuntimeStatsColl
TableIDs []int64
IndexIDs []int64
NowTs time.Time
SysTs time.Time
nowTs time.Time // use this variable for now/current_timestamp calculation/cache for one stmt
stmtTimeCached bool
StmtType string
OriginalSQL string
digestMemo struct {
......@@ -131,6 +137,21 @@ type StatementContext struct {
Tables []TableEntry
}
// GetNowTsCached getter for nowTs, if not set get now time and cache it
func (sc *StatementContext) GetNowTsCached() time.Time {
if !sc.stmtTimeCached {
now := time.Now()
sc.nowTs = now
sc.stmtTimeCached = true
}
return sc.nowTs
}
// ResetNowTs resetter for nowTs, clear cached time flag
func (sc *StatementContext) ResetNowTs() {
sc.stmtTimeCached = false
}
// SQLDigest gets normalized and digest for provided sql.
// it will cache result after first calling.
func (sc *StatementContext) SQLDigest() (normalized, sqlDigest string) {
......@@ -345,14 +366,6 @@ func (sc *StatementContext) SetHistogramsNotLoad() {
sc.mu.Unlock()
}
// HistogramsNotLoad gets histogramsNotLoad.
func (sc *StatementContext) HistogramsNotLoad() bool {
sc.mu.Lock()
notLoad := sc.mu.histogramsNotLoad
sc.mu.Unlock()
return notLoad
}
// HandleTruncate ignores or returns the error based on the StatementContext state.
func (sc *StatementContext) HandleTruncate(err error) error {
// TODO: At present we have not checked whether the error can be ignored or treated as warning.
......@@ -446,6 +459,39 @@ func (sc *StatementContext) ShouldIgnoreOverflowError() bool {
return false
}
// PushDownFlags converts StatementContext to tipb.SelectRequest.Flags.
func (sc *StatementContext) PushDownFlags() uint64 {
var flags uint64
if sc.InInsertStmt {
flags |= model.FlagInInsertStmt
} else if sc.InUpdateStmt || sc.InDeleteStmt {
flags |= model.FlagInUpdateOrDeleteStmt
} else if sc.InSelectStmt {
flags |= model.FlagInSelectStmt
}
if sc.IgnoreTruncate {
flags |= model.FlagIgnoreTruncate
} else if sc.TruncateAsWarning {
flags |= model.FlagTruncateAsWarning
}
if sc.OverflowAsWarning {
flags |= model.FlagOverflowAsWarning
}
if sc.IgnoreZeroInDate {
flags |= model.FlagIgnoreZeroInDate
}
if sc.DividedByZeroAsWarning {
flags |= model.FlagDividedByZeroAsWarning
}
if sc.PadCharToFullLength {
flags |= model.FlagPadCharToFullLength
}
if sc.InLoadDataStmt {
flags |= model.FlagInLoadDataStmt
}
return flags
}
// CopTasksDetails returns some useful information of cop-tasks during execution.
func (sc *StatementContext) CopTasksDetails() *CopTasksDetails {
sc.mu.Lock()
......
......@@ -183,6 +183,11 @@ func NewBitLiteral(s string) (BitLiteral, error) {
return BitLiteral(b), nil
}
// ToString implement ast.BinaryLiteral interface
func (b BitLiteral) ToString() string {
return BinaryLiteral(b).ToString()
}
// ParseHexStr parses hexadecimal string literal.
// See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html
func ParseHexStr(s string) (BinaryLiteral, error) {
......@@ -225,3 +230,8 @@ func NewHexLiteral(s string) (HexLiteral, error) {
}
return HexLiteral(h), nil
}
// ToString implement ast.BinaryLiteral interface
func (b HexLiteral) ToString() string {
return BinaryLiteral(b).ToString()
}
......@@ -362,30 +362,63 @@ func NumberToDuration(number int64, fsp int) (Duration, error) {
// getValidIntPrefix gets prefix of the string which can be successfully parsed as int.
func getValidIntPrefix(sc *stmtctx.StatementContext, str string) (string, error) {
floatPrefix, err := getValidFloatPrefix(sc, str)
if err != nil {
return floatPrefix, errors.Trace(err)
if !sc.CastStrToIntStrict {
floatPrefix, err := getValidFloatPrefix(sc, str)
if err != nil {
return floatPrefix, errors.Trace(err)
}
return floatStrToIntStr(sc, floatPrefix, str)
}
validLen := 0
for i := 0; i < len(str); i++ {
c := str[i]
if (c == '+' || c == '-') && i == 0 {
continue
}
if c >= '0' && c <= '9' {
validLen = i + 1
continue
}
break
}
return floatStrToIntStr(sc, floatPrefix, str)
valid := str[:validLen]
if valid == "" {
valid = "0"
}
if validLen == 0 || validLen != len(str) {
return valid, errors.Trace(handleTruncateError(sc, ErrTruncatedWrongVal.GenWithStackByArgs("INTEGER", str)))
}
return valid, nil
}
// roundIntStr is to round int string base on the number following dot.
// roundIntStr is to round a **valid int string** base on the number following dot.
func roundIntStr(numNextDot byte, intStr string) string {
if numNextDot < '5' {
return intStr
}
retStr := []byte(intStr)
for i := len(intStr) - 1; i >= 0; i-- {
if retStr[i] != '9' {
retStr[i]++
idx := len(intStr) - 1
for ; idx >= 1; idx-- {
if retStr[idx] != '9' {
retStr[idx]++
break
}
if i == 0 {
retStr[i] = '1'
retStr[idx] = '0'
}
if idx == 0 {
if intStr[0] == '9' {
retStr[0] = '1'
retStr = append(retStr, '0')
} else if isDigit(intStr[0]) {
retStr[0]++
} else {
retStr[1] = '1'
retStr = append(retStr, '0')
break
}
retStr[i] = '0'
}
return string(retStr)
}
......@@ -394,6 +427,9 @@ func roundIntStr(numNextDot byte, intStr string) string {
// strconv.ParseInt, we can't parse float first then convert it to string because precision will
// be lost. For example, the string value "18446744073709551615" which is the max number of unsigned
// int will cause some precision to lose. intStr[0] may be a positive and negative sign like '+' or '-'.
//
// This func will find serious overflow such as the len of intStr > 20 (without prefix `+/-`)
// however, it will not check whether the intStr overflow BIGINT.
func floatStrToIntStr(sc *stmtctx.StatementContext, validFloat string, oriStr string) (intStr string, _ error) {
var dotIdx = -1
var eIdx = -1
......@@ -429,6 +465,7 @@ func floatStrToIntStr(sc *stmtctx.StatementContext, validFloat string, oriStr st
}
return intStr, nil
}
// intCnt and digits contain the prefix `+/-` if validFloat[0] is `+/-`
var intCnt int
digits := make([]byte, 0, len(validFloat))
if dotIdx == -1 {
......@@ -443,15 +480,18 @@ func floatStrToIntStr(sc *stmtctx.StatementContext, validFloat string, oriStr st
if err != nil {
return validFloat, errors.Trace(err)
}
if exp > 0 && int64(intCnt) > (math.MaxInt64-int64(exp)) {
// (exp + incCnt) overflows MaxInt64.
intCnt += exp
if exp >= 0 && (intCnt > 21 || intCnt < 0) {
// MaxInt64 has 19 decimal digits.
// MaxUint64 has 20 decimal digits.
// And the intCnt may contain the len of `+/-`,
// so I use 21 here as the early detection.
sc.AppendWarning(ErrOverflow.GenWithStackByArgs("BIGINT", oriStr))
return validFloat[:eIdx], nil
}
intCnt += exp
if intCnt <= 0 {
intStr = "0"
if intCnt == 0 && len(digits) > 0 {
if intCnt == 0 && len(digits) > 0 && isDigit(digits[0]) {
intStr = roundIntStr(digits[0], intStr)
}
return intStr, nil
......@@ -474,11 +514,6 @@ func floatStrToIntStr(sc *stmtctx.StatementContext, validFloat string, oriStr st
} else {
// convert scientific notation decimal number
extraZeroCount := intCnt - len(digits)
if extraZeroCount > 20 {
// Append overflow warning and return to avoid allocating too much memory.
sc.AppendWarning(ErrOverflow.GenWithStackByArgs("BIGINT", oriStr))
return validFloat[:eIdx], nil
}
intStr = string(digits) + strings.Repeat("0", extraZeroCount)
}
return intStr, nil
......@@ -525,10 +560,10 @@ func ConvertJSONToInt(sc *stmtctx.StatementContext, j json.BinaryJSON, unsigned
if !unsigned {
lBound := IntergerSignedLowerBound(mysql.TypeLonglong)
uBound := IntergerSignedUpperBound(mysql.TypeLonglong)
return ConvertFloatToInt(f, lBound, uBound, mysql.TypeDouble)
return ConvertFloatToInt(f, lBound, uBound, mysql.TypeLonglong)
}
bound := IntergerUnsignedUpperBound(mysql.TypeLonglong)
u, err := ConvertFloatToUint(sc, f, bound, mysql.TypeDouble)
u, err := ConvertFloatToUint(sc, f, bound, mysql.TypeLonglong)
return int64(u), errors.Trace(err)
case json.TypeCodeString:
str := string(hack.String(j.GetString()))
......@@ -552,8 +587,7 @@ func ConvertJSONToFloat(sc *stmtctx.StatementContext, j json.BinaryJSON) (float6
case json.TypeCodeInt64:
return float64(j.GetInt64()), nil
case json.TypeCodeUint64:
u, err := ConvertIntToUint(sc, j.GetInt64(), IntergerUnsignedUpperBound(mysql.TypeLonglong), mysql.TypeLonglong)
return float64(u), errors.Trace(err)
return float64(j.GetUint64()), nil
case json.TypeCodeFloat64:
return j.GetFloat64(), nil
case json.TypeCodeString:
......@@ -580,6 +614,10 @@ func ConvertJSONToDecimal(sc *stmtctx.StatementContext, j json.BinaryJSON) (*MyD
// getValidFloatPrefix gets prefix of string which can be successfully parsed as float.
func getValidFloatPrefix(sc *stmtctx.StatementContext, s string) (valid string, err error) {
if (sc.InDeleteStmt || sc.InSelectStmt || sc.InUpdateStmt) && s == "" {
return "0", nil
}
var (
sawDot bool
sawDigit bool
......@@ -620,7 +658,7 @@ func getValidFloatPrefix(sc *stmtctx.StatementContext, s string) (valid string,
valid = "0"
}
if validLen == 0 || validLen != len(s) {
err = errors.Trace(handleTruncateError(sc))
err = errors.Trace(handleTruncateError(sc, ErrTruncated))
}
return valid, err
}
......
......@@ -14,7 +14,6 @@
package types
import (
"context"
"fmt"
"math"
"sort"
......@@ -1245,7 +1244,7 @@ func (d *Datum) convertToMysqlEnum(sc *stmtctx.StatementContext, target *FieldTy
e, err = ParseEnumValue(target.Elems, uintDatum.GetUint64())
}
if err != nil {
logutil.Logger(context.Background()).Error("convert to MySQL enum failed", zap.Error(err))
logutil.BgLogger().Error("convert to MySQL enum failed", zap.Error(err))
err = errors.Trace(ErrTruncated)
}
ret.SetValue(e)
......@@ -1781,14 +1780,14 @@ func (ds *datumsSorter) Swap(i, j int) {
ds.datums[i], ds.datums[j] = ds.datums[j], ds.datums[i]
}
func handleTruncateError(sc *stmtctx.StatementContext) error {
func handleTruncateError(sc *stmtctx.StatementContext, err error) error {
if sc.IgnoreTruncate {
return nil
}
if !sc.TruncateAsWarning {
return ErrTruncated
return err
}
sc.AppendWarning(ErrTruncated)
sc.AppendWarning(err)
return nil
}
......
......@@ -86,9 +86,12 @@ func ParseFrac(s string, fsp int) (v int, overflow bool, err error) {
return
}
// alignFrac is used to generate alignment frac, like `100` -> `100000`
// alignFrac is used to generate alignment frac, like `100` -> `100000` ,`-100` -> `-100000`
func alignFrac(s string, fsp int) string {
sl := len(s)
if sl > 0 && s[0] == '-' {
sl = sl - 1
}
if sl < fsp {
return s + strings.Repeat("0", fsp-sl)
}
......
......@@ -369,6 +369,49 @@ func (bj BinaryJSON) Modify(pathExprList []PathExpression, values []BinaryJSON,
return bj, nil
}
// ArrayInsert insert a BinaryJSON into the given array cell.
// All path expressions cannot contain * or ** wildcard.
// If any error occurs, the input won't be changed.
func (bj BinaryJSON) ArrayInsert(pathExpr PathExpression, value BinaryJSON) (res BinaryJSON, err error) {
// Check the path is a index
if len(pathExpr.legs) < 1 {
return bj, ErrInvalidJSONPathArrayCell
}
parentPath, lastLeg := pathExpr.popOneLastLeg()
if lastLeg.typ != pathLegIndex {
return bj, ErrInvalidJSONPathArrayCell
}
// Find the target array
obj, exists := bj.Extract([]PathExpression{parentPath})
if !exists || obj.TypeCode != TypeCodeArray {
return bj, nil
}
idx := lastLeg.arrayIndex
count := obj.GetElemCount()
if idx >= count {
idx = count
}
// Insert into the array
newArray := make([]BinaryJSON, 0, count+1)
for i := 0; i < idx; i++ {
elem := obj.arrayGetElem(i)
newArray = append(newArray, elem)
}
newArray = append(newArray, value)
for i := idx; i < count; i++ {
elem := obj.arrayGetElem(i)
newArray = append(newArray, elem)
}
obj = buildBinaryArray(newArray)
bj, err = bj.Modify([]PathExpression{parentPath}, []BinaryJSON{obj}, ModifySet)
if err != nil {
return bj, err
}
return bj, nil
}
// Remove removes the elements indicated by pathExprList from JSON.
func (bj BinaryJSON) Remove(pathExprList []PathExpression) (BinaryJSON, error) {
for _, pathExpr := range pathExprList {
......
......@@ -216,6 +216,8 @@ var (
ErrInvalidJSONPathWildcard = terror.ClassJSON.New(mysql.ErrInvalidJSONPathWildcard, mysql.MySQLErrName[mysql.ErrInvalidJSONPathWildcard])
// ErrInvalidJSONContainsPathType means invalid JSON contains path type.
ErrInvalidJSONContainsPathType = terror.ClassJSON.New(mysql.ErrInvalidJSONContainsPathType, mysql.MySQLErrName[mysql.ErrInvalidJSONContainsPathType])
// ErrInvalidJSONPathArrayCell means invalid JSON path for an array cell.
ErrInvalidJSONPathArrayCell = terror.ClassJSON.New(mysql.ErrInvalidJSONPathArrayCell, mysql.MySQLErrName[mysql.ErrInvalidJSONPathArrayCell])
)
func init() {
......@@ -225,6 +227,7 @@ func init() {
mysql.ErrInvalidJSONData: mysql.ErrInvalidJSONData,
mysql.ErrInvalidJSONPathWildcard: mysql.ErrInvalidJSONPathWildcard,
mysql.ErrInvalidJSONContainsPathType: mysql.ErrInvalidJSONContainsPathType,
mysql.ErrInvalidJSONPathArrayCell: mysql.ErrInvalidJSONPathArrayCell,
}
}
......
......@@ -107,6 +107,14 @@ var (
zeroMyDecimal = MyDecimal{}
)
// get the zero of MyDecimal with the specified result fraction digits
func zeroMyDecimalWithFrac(frac int8) MyDecimal {
zero := MyDecimal{}
zero.digitsFrac = frac
zero.resultFrac = frac
return zero
}
// add adds a and b and carry, returns the sum and new carry.
func add(a, b, carry int32) (int32, int32) {
sum := a + b + carry
......@@ -1556,7 +1564,7 @@ func doSub(from1, from2, to *MyDecimal) (cmp int, err error) {
if to == nil {
return 0, nil
}
*to = zeroMyDecimal
*to = zeroMyDecimalWithFrac(to.resultFrac)
return 0, nil
}
}
......@@ -1911,7 +1919,7 @@ func DecimalMul(from1, from2, to *MyDecimal) error {
idx++
/* We got decimal zero */
if idx == end {
*to = zeroMyDecimal
*to = zeroMyDecimalWithFrac(to.resultFrac)
break
}
}
......@@ -2010,7 +2018,7 @@ func doDivMod(from1, from2, to, mod *MyDecimal, fracIncr int) error {
}
if prec1 <= 0 {
/* short-circuit everything: from1 == 0 */
*to = zeroMyDecimal
*to = zeroMyDecimalWithFrac(to.resultFrac)
return nil
}
prec1 -= countLeadingZeroes((prec1-1)%digitsPerWord, from1.wordBuf[idx1])
......
......@@ -70,8 +70,9 @@ func (t MysqlTime) Microsecond() int {
func (t MysqlTime) Weekday() gotime.Weekday {
// TODO: Consider time_zone variable.
t1, err := t.GoTime(gotime.Local)
// allow invalid dates
if err != nil {
return 0
return t1.Weekday()
}
return t1.Weekday()
}
......
......@@ -15,7 +15,6 @@ package types
import (
"bytes"
"context"
"fmt"
"math"
"regexp"
......@@ -305,7 +304,7 @@ func (t Time) ToNumber() *MyDecimal {
s, err := t.DateFormat(tfStr)
if err != nil {
logutil.Logger(context.Background()).Error("[fatal] never happen because we've control the format!")
logutil.BgLogger().Error("[fatal] never happen because we've control the format!")
}
if t.Fsp > 0 {
......@@ -1470,7 +1469,7 @@ func checkDateRange(t MysqlTime) error {
func checkMonthDay(year, month, day int, allowInvalidDate bool) error {
if month < 0 || month > 12 {
return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(month))
return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(fmt.Sprintf("%d-%d-%d", year, month, day)))
}
maxDay := 31
......@@ -1484,7 +1483,7 @@ func checkMonthDay(year, month, day int, allowInvalidDate bool) error {
}
if day < 0 || day > maxDay {
return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(day))
return errors.Trace(ErrIncorrectDatetimeValue.GenWithStackByArgs(fmt.Sprintf("%d-%d-%d", year, month, day)))
}
return nil
}
......
......@@ -330,6 +330,11 @@ func Logger(ctx context.Context) *zap.Logger {
return zaplog.L()
}
// BgLogger is alias of `logutil.BgLogger()`
func BgLogger() *zap.Logger {
return zaplog.L()
}
// WithConnID attaches connId to context.
func WithConnID(ctx context.Context, connID uint32) context.Context {
var logger *zap.Logger
......
......@@ -14,7 +14,7 @@
package memory
import (
"context"
"fmt"
"sync"
"github.com/pingcap/parser/mysql"
......@@ -29,12 +29,22 @@ type ActionOnExceed interface {
// Action will be called when memory usage exceeds memory quota by the
// corresponding Tracker.
Action(t *Tracker)
// SetLogHook binds a log hook which will be triggered and log an detailed
// message for the out-of-memory sql.
SetLogHook(hook func(uint64))
}
// LogOnExceed logs a warning only once when memory usage exceeds memory quota.
type LogOnExceed struct {
mutex sync.Mutex // For synchronization.
acted bool
mutex sync.Mutex // For synchronization.
acted bool
ConnID uint64
logHook func(uint64)
}
// SetLogHook sets a hook for LogOnExceed.
func (a *LogOnExceed) SetLogHook(hook func(uint64)) {
a.logHook = hook
}
// Action logs a warning only once when memory usage exceeds memory quota.
......@@ -43,16 +53,26 @@ func (a *LogOnExceed) Action(t *Tracker) {
defer a.mutex.Unlock()
if !a.acted {
a.acted = true
logutil.Logger(context.Background()).Warn("memory exceeds quota",
zap.Error(errMemExceedThreshold.GenWithStackByArgs(t.label, t.BytesConsumed(), t.bytesLimit, t.String())))
return
if a.logHook == nil {
logutil.BgLogger().Warn("memory exceeds quota",
zap.Error(errMemExceedThreshold.GenWithStackByArgs(t.label, t.BytesConsumed(), t.bytesLimit, t.String())))
return
}
a.logHook(a.ConnID)
}
}
// PanicOnExceed panics when memory usage exceeds memory quota.
type PanicOnExceed struct {
mutex sync.Mutex // For synchronization.
acted bool
mutex sync.Mutex // For synchronization.
acted bool
ConnID uint64
logHook func(uint64)
}
// SetLogHook sets a hook for PanicOnExceed.
func (a *PanicOnExceed) SetLogHook(hook func(uint64)) {
a.logHook = hook
}
// Action panics when memory usage exceeds memory quota.
......@@ -64,7 +84,10 @@ func (a *PanicOnExceed) Action(t *Tracker) {
}
a.acted = true
a.mutex.Unlock()
panic(PanicMemoryExceed + t.String())
if a.logHook != nil {
a.logHook(a.ConnID)
}
panic(PanicMemoryExceed + fmt.Sprintf("[conn_id=%d]", a.ConnID))
}
var (
......
......@@ -87,11 +87,6 @@ func (t *Tracker) AttachTo(parent *Tracker) {
t.parent.Consume(t.BytesConsumed())
}
// Detach detaches this Tracker from its parent.
func (t *Tracker) Detach() {
t.parent.remove(t)
}
func (t *Tracker) remove(oldChild *Tracker) {
t.mu.Lock()
defer t.mu.Unlock()
......@@ -144,17 +139,13 @@ func (t *Tracker) Consume(bytes int64) {
rootExceed = tracker
}
if tracker.parent == nil {
// since we only need a total memory usage during execution,
// we only record max consumed bytes in root(statement-level) for performance.
for {
maxNow := atomic.LoadInt64(&tracker.maxConsumed)
consumed := atomic.LoadInt64(&tracker.bytesConsumed)
if consumed > maxNow && !atomic.CompareAndSwapInt64(&tracker.maxConsumed, maxNow, consumed) {
continue
}
break
for {
maxNow := atomic.LoadInt64(&tracker.maxConsumed)
consumed := atomic.LoadInt64(&tracker.bytesConsumed)
if consumed > maxNow && !atomic.CompareAndSwapInt64(&tracker.maxConsumed, maxNow, consumed) {
continue
}
break
}
}
if rootExceed != nil {
......@@ -172,6 +163,21 @@ func (t *Tracker) MaxConsumed() int64 {
return atomic.LoadInt64(&t.maxConsumed)
}
// SearchTracker searches the specific tracker under this tracker.
func (t *Tracker) SearchTracker(label string) *Tracker {
if t.label.String() == label {
return t
}
t.mu.Lock()
defer t.mu.Unlock()
for _, child := range t.mu.children {
if result := child.SearchTracker(label); result != nil {
return result
}
}
return nil
}
// String returns the string representation of this Tracker tree.
func (t *Tracker) String() string {
buffer := bytes.NewBufferString("\n")
......
......@@ -117,118 +117,118 @@
"revisionTime": "2019-03-07T07:54:52Z"
},
{
"checksumSHA1": "gkdPCV8bVezIdBd/w2RiZf7eXTU=",
"checksumSHA1": "8XbJFHOYoZvqf3Fq+J4l90DiGlM=",
"path": "github.com/pingcap/parser",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "/HUw+IEQjCkicSG7qSMWqRlmvz0=",
"checksumSHA1": "a+3CnBMiJTPiAKhRzxW5ybMR6IY=",
"path": "github.com/pingcap/parser/ast",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "xiv40YqnvHcbIhaEzJqjh5K7ehM=",
"path": "github.com/pingcap/parser/auth",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "EvDXpplklIXmKqLclzWzaN/uHKQ=",
"path": "github.com/pingcap/parser/charset",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "Aao6Mul/qqogOwPwM2arBKZkYZs=",
"path": "github.com/pingcap/parser/format",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "CvZtQeDgNfQUrGDi5mrv5osJ5F0=",
"checksumSHA1": "f14oFKfX0pSkUM9w9m94eZG5vEw=",
"path": "github.com/pingcap/parser/model",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "02F5sAuKee53HMwsu6fx+iw5cnM=",
"checksumSHA1": "JcR/7pmocSZK4K6tDK2zO54DJWg=",
"path": "github.com/pingcap/parser/mysql",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "olapD16WCMBU9vrA5PtlERGFfXw=",
"path": "github.com/pingcap/parser/opcode",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "L6rzy3sJU1RPf7AkJN+0zcwW/YY=",
"path": "github.com/pingcap/parser/terror",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "EWbRvJs3Y1KLBaHnwaCHps3t0+4=",
"checksumSHA1": "nWkzWKjheFi0/Ov/0rhc4CUMZLo=",
"path": "github.com/pingcap/parser/types",
"revision": "3b36f86d9b7bba02fef99748e3a98069708a64f3",
"revisionTime": "2019-06-12T05:27:18Z"
"revision": "5238015a66f827e0d0d01e9a1dc19e4e3338c5bf",
"revisionTime": "2019-07-30T09:13:57Z"
},
{
"checksumSHA1": "irgF5OsNQZiD589px9hV3scdp8U=",
"checksumSHA1": "KHvXxhiZAHkE8APuMlaAXDOX6eU=",
"path": "github.com/pingcap/tidb/sessionctx/stmtctx",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "1INT6BSMg5WA9x4ftRegJBhDJQg=",
"checksumSHA1": "6pIJUxO/VoKsIdWibgApSW91MRg=",
"path": "github.com/pingcap/tidb/types",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "HYVqavXulc59n0RyI/D1jZVKon4=",
"checksumSHA1": "gKBD02jzm/d7gn2kX7pXLi+M2ZY=",
"path": "github.com/pingcap/tidb/types/json",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "45zWX5Q6D6aTEWtc4p/lbD9WD4o=",
"path": "github.com/pingcap/tidb/types/parser_driver",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "dI3bZpUsujM1shEDvORNQj5FCN0=",
"path": "github.com/pingcap/tidb/util/execdetails",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "RdbHgQWMHjRtKjqPcTX81k1V3sw=",
"path": "github.com/pingcap/tidb/util/hack",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "16Cv4I5dFUSCuz0AufzUilN4IOI=",
"checksumSHA1": "5DVxTRYAXrCkrtmTqi/fZfY/Zfk=",
"path": "github.com/pingcap/tidb/util/logutil",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "OveQu0ABBJmMEwmmthqSRQC2Ef0=",
"path": "github.com/pingcap/tidb/util/math",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "EoqVTAze03xNtGcKbsZT4eYx9bI=",
"checksumSHA1": "loL2JgZDLapEOgfM/XUJI5f0HVs=",
"path": "github.com/pingcap/tidb/util/memory",
"revision": "7d27fa63d349b9d266682a3fff6e732c156cf1db",
"revisionTime": "2019-06-12T12:43:29Z"
"revision": "13778fe51b713f005e1de848e7994f0a8031678f",
"revisionTime": "2019-07-31T03:50:10Z"
},
{
"checksumSHA1": "QPIBwDNUFF5Whrnd41S3mkKa4gQ=",
......@@ -485,68 +485,68 @@
{
"checksumSHA1": "aKn1oKcY74N8TRLm3Ayt7Q4bbI4=",
"path": "vitess.io/vitess/go/bytes2",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "bhE6CGQgZTIgLPp9lnvlKW/47xc=",
"path": "vitess.io/vitess/go/hack",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "RERqgxOX48XzRIoe5fQzvWSJV0Y=",
"checksumSHA1": "2m7CYdLr+epKNLqWaGHkinr3k7w=",
"path": "vitess.io/vitess/go/sqltypes",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "vAIRxI6MHsq3x1hLQwIyw5AvqtI=",
"path": "vitess.io/vitess/go/vt/log",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "/0K9CBbInkAhioqKX9ocBrJ6AKE=",
"path": "vitess.io/vitess/go/vt/proto/binlogdata",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "87Zndvk3Y+M+QxMx3uFa0iSbvWY=",
"path": "vitess.io/vitess/go/vt/proto/query",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "xpcb9NfXMEeHhEPStbJntIfa5GQ=",
"path": "vitess.io/vitess/go/vt/proto/topodata",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "Ie634JZ/Np9603mG+PQ0ZkUsaQI=",
"checksumSHA1": "Bv8lucvoH9AnJSYiWX8MIrJl4zY=",
"path": "vitess.io/vitess/go/vt/proto/vtgate",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "qz32abYdmm9NfKTc++K0l1EvXXM=",
"path": "vitess.io/vitess/go/vt/proto/vtrpc",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "/V79kL29yMBxAofQBL/XqxJv/GE=",
"checksumSHA1": "9Fy+Gm//g50wu30nICOF7HMq4po=",
"path": "vitess.io/vitess/go/vt/sqlparser",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
},
{
"checksumSHA1": "z9+F/lA1Xrl5S16LKssUH8VL6hs=",
"path": "vitess.io/vitess/go/vt/vterrors",
"revision": "22dbada8b16e2c969dd60c77f4e6a346c70d5952",
"revisionTime": "2019-06-11T03:26:25Z"
"revision": "f93c96c738d7d5bbbcdc03c828f8bf0a5ba16250",
"revisionTime": "2019-07-30T06:18:30Z"
}
],
"rootPath": "github.com/XiaoMi/soar"
......
......@@ -26,6 +26,9 @@ import (
"vitess.io/vitess/go/vt/vterrors"
)
// TODO(sougou): change these functions to be more permissive.
// Most string to number conversions should quietly convert to 0.
// numeric represents a numeric value extracted from
// a Value, used for arithmetic operations.
type numeric struct {
......@@ -35,6 +38,8 @@ type numeric struct {
fval float64
}
var zeroBytes = []byte("0")
// NullsafeAdd adds two Values in a null-safe manner. A null value
// is treated as 0. If both values are null, then a null is returned.
// If both values are not null, a numeric value is built
......@@ -48,10 +53,10 @@ type numeric struct {
// result is preserved.
func NullsafeAdd(v1, v2 Value, resultType querypb.Type) (Value, error) {
if v1.IsNull() {
return v2, nil
v1 = MakeTrusted(resultType, zeroBytes)
}
if v2.IsNull() {
return v1, nil
v2 = MakeTrusted(resultType, zeroBytes)
}
lv1, err := newNumeric(v1)
......
......@@ -219,9 +219,9 @@ func skipToEnd(yylex interface{}) {
%type <tableExprs> from_opt table_references
%type <tableExpr> table_reference table_factor join_table
%type <joinCondition> join_condition join_condition_opt on_expression_opt
%type <tableNames> table_name_list
%type <tableNames> table_name_list delete_table_list
%type <str> inner_join outer_join straight_join natural_join
%type <tableName> table_name into_table_name
%type <tableName> table_name into_table_name delete_table_name
%type <aliasedTableName> aliased_table_name
%type <indexHints> index_hint_list
%type <expr> where_expression_opt
......@@ -454,6 +454,10 @@ delete_statement:
{
$$ = &Delete{Comments: Comments($2), Targets: $3, TableExprs: $5, Where: NewWhere(WhereStr, $6)}
}
|DELETE comment_opt delete_table_list from_or_using table_references where_expression_opt
{
$$ = &Delete{Comments: Comments($2), Targets: $3, TableExprs: $5, Where: NewWhere(WhereStr, $6)}
}
from_or_using:
FROM {}
......@@ -469,6 +473,16 @@ table_name_list:
$$ = append($$, $3)
}
delete_table_list:
delete_table_name
{
$$ = TableNames{$1}
}
| delete_table_list ',' delete_table_name
{
$$ = append($$, $3)
}
opt_partition_clause:
{
$$ = nil
......@@ -2062,6 +2076,12 @@ table_name:
$$ = TableName{Qualifier: $1, Name: $3}
}
delete_table_name:
table_id '.' '*'
{
$$ = TableName{Name: $1}
}
index_hint_list:
{
$$ = nil
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册