func (ts *testMemoryTableSuite) SetUpSuite(c *C) { driver := localstore.Driver{Driver: goleveldb.MemoryDriver{}} store, err := driver.Open("memory") c.Check(err, IsNil) ts.store = store ts.se, err = tidb.CreateSession(ts.store) c.Assert(err, IsNil) // create table tp1 := types.NewFieldType(mysql.TypeLong) col1 := &model.ColumnInfo{ ID: 1, Name: model.NewCIStr("a"), Offset: 0, FieldType: *tp1, } tp2 := types.NewFieldType(mysql.TypeVarchar) tp2.Flen = 255 col2 := &model.ColumnInfo{ ID: 2, Name: model.NewCIStr("b"), Offset: 1, FieldType: *tp2, } tblInfo := &model.TableInfo{ ID: 100, Name: model.NewCIStr("t"), Columns: []*model.ColumnInfo{col1, col2}, } alloc := autoid.NewMemoryAllocator(int64(10)) ts.tbl, _ = tables.MemoryTableFromMeta(alloc, tblInfo) }
func (s *testCastSuite) TestCast(c *C) { f := types.NewFieldType(mysql.TypeLonglong) expr := &FunctionCast{ Expr: Value{1}, Tp: f, } f.Flag |= mysql.UnsignedFlag c.Assert(len(expr.String()), Greater, 0) f.Flag = 0 c.Assert(len(expr.String()), Greater, 0) f.Tp = mysql.TypeDatetime c.Assert(len(expr.String()), Greater, 0) f.Tp = mysql.TypeLonglong _, err := expr.Clone() c.Assert(err, IsNil) c.Assert(expr.IsStatic(), IsTrue) v, err := expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, Equals, int64(1)) f.Flag |= mysql.UnsignedFlag v, err = expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, Equals, uint64(1)) f.Tp = mysql.TypeString f.Charset = charset.CharsetBin v, err = expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, DeepEquals, []byte("1")) expr.Expr = Value{nil} v, err = expr.Eval(nil, nil) c.Assert(err, IsNil) c.Assert(v, Equals, nil) expr.Expr = mockExpr{err: errors.New("must error")} _, err = expr.Clone() c.Assert(err, NotNil) _, err = expr.Eval(nil, nil) c.Assert(err, NotNil) // For String() f = types.NewFieldType(mysql.TypeLonglong) expr = &FunctionCast{ Expr: Value{1}, Tp: f, } str := expr.String() c.Assert(str, Equals, "CAST(1 AS SIGNED)") expr.IsConvert = true str = expr.String() c.Assert(str, Equals, "CONVERT(1, SIGNED)") }
func (b *planBuilder) buildExplain(explain *ast.ExplainStmt) Plan { if show, ok := explain.Stmt.(*ast.ShowStmt); ok { return b.buildShow(show) } targetPlan, err := Optimize(b.ctx, explain.Stmt, b.is) if err != nil { b.err = errors.Trace(err) return nil } p := &Explain{StmtPlan: targetPlan} addChild(p, targetPlan) schema := make(expression.Schema, 0, 3) schema = append(schema, &expression.Column{ ColName: model.NewCIStr("ID"), RetType: types.NewFieldType(mysql.TypeString), }) schema = append(schema, &expression.Column{ ColName: model.NewCIStr("Json"), RetType: types.NewFieldType(mysql.TypeString), }) schema = append(schema, &expression.Column{ ColName: model.NewCIStr("ParentID"), RetType: types.NewFieldType(mysql.TypeString), }) p.SetSchema(schema) return p }
func (v *typeInferrer) aggregateFunc(x *ast.AggregateFuncExpr) { name := strings.ToLower(x.F) switch name { case ast.AggFuncCount: ft := types.NewFieldType(mysql.TypeLonglong) ft.Flen = 21 ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin x.SetType(ft) case ast.AggFuncMax, ast.AggFuncMin: x.SetType(x.Args[0].GetType()) case ast.AggFuncSum, ast.AggFuncAvg: ft := types.NewFieldType(mysql.TypeNewDecimal) ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin x.SetType(ft) case ast.AggFuncGroupConcat: ft := types.NewFieldType(mysql.TypeVarString) ft.Charset = v.defaultCharset cln, err := charset.GetDefaultCollation(v.defaultCharset) if err != nil { v.err = err } ft.Collate = cln x.SetType(ft) } }
func (*testFieldSuite) TestField(c *C) { f := &field.Field{ Expr: expression.Value{Val: "c1+1"}, AsName: "a", } s := f.String() c.Assert(len(s), Greater, 0) ft := types.NewFieldType(mysql.TypeLong) ft.Flen = 20 ft.Flag |= mysql.UnsignedFlag | mysql.ZerofillFlag c.Assert(ft.String(), Equals, "int(20) UNSIGNED ZEROFILL") ft = types.NewFieldType(mysql.TypeFloat) ft.Flen = 20 ft.Decimal = 10 c.Assert(ft.String(), Equals, "float(20,10)") ft = types.NewFieldType(mysql.TypeTimestamp) ft.Decimal = 8 c.Assert(ft.String(), Equals, "timestamp(8)") ft = types.NewFieldType(mysql.TypeVarchar) ft.Flag |= mysql.BinaryFlag ft.Charset = "utf8" ft.Collate = "utf8_unicode_gi" c.Assert(ft.String(), Equals, "varchar BINARY CHARACTER SET utf8 COLLATE utf8_unicode_gi") }
func (p *physicalTableSource) addAggregation(agg *PhysicalAggregation) expression.Schema { if p.client == nil { return nil } for _, f := range agg.AggFuncs { pb := aggFuncToPBExpr(p.client, f) if pb == nil { p.clear() return nil } p.AggFuncs = append(p.AggFuncs, pb) } for _, item := range agg.GroupByItems { pb := groupByItemToPB(p.client, item) if pb == nil { p.clear() return nil } p.GbyItems = append(p.GbyItems, pb) } p.Aggregated = true gk := types.NewFieldType(mysql.TypeBlob) gk.Charset = charset.CharsetBin gk.Collate = charset.CollationBin p.AggFields = append(p.AggFields, gk) var schema expression.Schema cursor := 0 schema = append(schema, &expression.Column{Index: cursor, ColName: model.NewCIStr(fmt.Sprint(agg.GroupByItems))}) agg.GroupByItems = []expression.Expression{schema[cursor]} newAggFuncs := make([]expression.AggregationFunction, len(agg.AggFuncs)) for i, aggFun := range agg.AggFuncs { fun := expression.NewAggFunction(aggFun.GetName(), nil, false) var args []expression.Expression colName := model.NewCIStr(fmt.Sprint(aggFun.GetArgs())) if needCount(fun) { cursor++ schema = append(schema, &expression.Column{Index: cursor, ColName: colName}) args = append(args, schema[cursor]) ft := types.NewFieldType(mysql.TypeLonglong) ft.Flen = 21 ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin p.AggFields = append(p.AggFields, ft) } if needValue(fun) { cursor++ schema = append(schema, &expression.Column{Index: cursor, ColName: colName}) args = append(args, schema[cursor]) p.AggFields = append(p.AggFields, agg.schema[i].GetType()) } fun.SetArgs(args) fun.SetMode(expression.FinalMode) newAggFuncs[i] = fun } agg.AggFuncs = newAggFuncs return schema }
func (s *testDDLSuite) TestAlterSpecification(c *C) { tbl := []*AlterSpecification{ { Action: AlterTableOpt, }, { Action: AlterDropColumn, Name: "c1", }, {Action: AlterDropPrimaryKey}, {Action: AlterDropForeignKey, Name: "c"}, {Action: AlterDropIndex, Name: "index_c"}, {Action: AlterAddConstr, Constraint: nil}, {Action: AlterAddConstr, Constraint: &coldef.TableConstraint{ Tp: coldef.ConstrPrimaryKey, Keys: []*coldef.IndexColName{ { ColumnName: "a", Length: 10, }, }, }}, {Action: AlterAddColumn, Column: &coldef.ColumnDef{ Name: "c", Tp: types.NewFieldType(mysql.TypeLong), }, Position: &ColumnPosition{}}, {Action: AlterAddColumn, Column: &coldef.ColumnDef{ Name: "c", Tp: types.NewFieldType(mysql.TypeLong), }, Position: &ColumnPosition{Type: ColumnPositionFirst}}, {Action: AlterAddColumn, Column: &coldef.ColumnDef{ Name: "c", Tp: types.NewFieldType(mysql.TypeLong), }, Position: &ColumnPosition{Type: ColumnPositionAfter, RelativeColumn: "c"}}, // Invalid action returns empty string {Action: -1}, } for _, spec := range tbl { c.Assert(len(spec.String()), GreaterEqual, 0) } }
func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) { var ( tp *types.FieldType chs = charset.CharsetBin ) switch x.FnName.L { case "abs", "ifnull", "nullif": tp = x.Args[0].GetType() case "pow", "power", "rand": tp = types.NewFieldType(mysql.TypeDouble) case "curdate", "current_date", "date": tp = types.NewFieldType(mysql.TypeDate) case "curtime", "current_time": tp = types.NewFieldType(mysql.TypeDuration) tp.Decimal = v.getFsp(x) case "current_timestamp": tp = types.NewFieldType(mysql.TypeDatetime) case "microsecond", "second", "minute", "hour", "day", "week", "month", "year", "dayofweek", "dayofmonth", "dayofyear", "weekday", "weekofyear", "yearweek", "found_rows", "length": tp = types.NewFieldType(mysql.TypeLonglong) case "now", "sysdate": tp = types.NewFieldType(mysql.TypeDatetime) tp.Decimal = v.getFsp(x) case "dayname", "version", "database", "user", "current_user", "concat", "concat_ws", "left", "lower", "repeat", "replace", "upper": tp = types.NewFieldType(mysql.TypeVarString) chs = v.defaultCharset case "connection_id": tp = types.NewFieldType(mysql.TypeLonglong) tp.Flag |= mysql.UnsignedFlag case "if": // TODO: fix this // See: https://dev.mysql.com/doc/refman/5.5/en/control-flow-functions.html#function_if // The default return type of IF() (which may matter when it is stored into a temporary table) is calculated as follows. // Expression Return Value // expr2 or expr3 returns a string string // expr2 or expr3 returns a floating-point value floating-point // expr2 or expr3 returns an integer integer tp = x.Args[1].GetType() default: tp = types.NewFieldType(mysql.TypeUnspecified) } // If charset is unspecified. if len(tp.Charset) == 0 { tp.Charset = chs cln := charset.CollationBin if chs != charset.CharsetBin { var err error cln, err = charset.GetDefaultCollation(chs) if err != nil { v.err = err } } tp.Collate = cln } x.SetType(tp) }
// NewValueExpr creates a ValueExpr with value, and sets default field type. func NewValueExpr(value interface{}) *ValueExpr { ve := &ValueExpr{} ve.Data = types.RawData(value) // TODO: make it more precise. switch value.(type) { case nil: ve.Type = types.NewFieldType(mysql.TypeNull) case bool, int64: ve.Type = types.NewFieldType(mysql.TypeLonglong) case uint64: ve.Type = types.NewFieldType(mysql.TypeLonglong) ve.Type.Flag |= mysql.UnsignedFlag case string, UnquoteString: ve.Type = types.NewFieldType(mysql.TypeVarchar) ve.Type.Charset = mysql.DefaultCharset ve.Type.Collate = mysql.DefaultCollationName case float64: ve.Type = types.NewFieldType(mysql.TypeDouble) case []byte: ve.Type = types.NewFieldType(mysql.TypeBlob) ve.Type.Charset = "binary" ve.Type.Collate = "binary" case mysql.Bit: ve.Type = types.NewFieldType(mysql.TypeBit) case mysql.Hex: ve.Type = types.NewFieldType(mysql.TypeVarchar) ve.Type.Charset = "binary" ve.Type.Collate = "binary" case *types.DataItem: ve.Type = value.(*types.DataItem).Type default: panic(fmt.Sprintf("illegal literal value type:%T", value)) } return ve }
func (b *planBuilder) buildApply(p, inner LogicalPlan, schema expression.Schema, checker *ApplyConditionChecker) LogicalPlan { ap := &Apply{ InnerPlan: inner, OuterSchema: schema, Checker: checker, baseLogicalPlan: newBaseLogicalPlan(App, b.allocator), } ap.initID() addChild(ap, p) innerSchema := inner.GetSchema().DeepCopy() if checker == nil { for _, col := range innerSchema { col.IsAggOrSubq = true } ap.SetSchema(append(p.GetSchema().DeepCopy(), innerSchema...)) } else { ap.SetSchema(append(p.GetSchema().DeepCopy(), &expression.Column{ FromID: ap.id, ColName: model.NewCIStr("exists_row"), RetType: types.NewFieldType(mysql.TypeTiny), IsAggOrSubq: true, })) } ap.correlated = p.IsCorrelated() return ap }
func (s *testEvaluatorSuite) TestCast(c *C) { defer testleak.AfterTest(c)() f := types.NewFieldType(mysql.TypeLonglong) expr := &ast.FuncCastExpr{ Expr: ast.NewValueExpr(1), Tp: f, } ast.SetFlag(expr) v, err := Eval(s.ctx, expr) c.Assert(err, IsNil) c.Assert(v, testutil.DatumEquals, types.NewDatum(int64(1))) f.Flag |= mysql.UnsignedFlag v, err = Eval(s.ctx, expr) c.Assert(err, IsNil) c.Assert(v, testutil.DatumEquals, types.NewDatum(uint64(1))) f.Tp = mysql.TypeString f.Charset = charset.CharsetBin v, err = Eval(s.ctx, expr) c.Assert(err, IsNil) c.Assert(v, testutil.DatumEquals, types.NewDatum([]byte("1"))) f.Tp = mysql.TypeString f.Charset = "utf8" v, err = Eval(s.ctx, expr) c.Assert(err, IsNil) c.Assert(v, testutil.DatumEquals, types.NewDatum("1")) expr.Expr = ast.NewValueExpr(nil) v, err = Eval(s.ctx, expr) c.Assert(err, IsNil) c.Assert(v.Kind(), Equals, types.KindNull) }
// tryToPushDownAgg tries to push down an aggregate function into a join path. If all aggFuncs are first row, we won't // process it temporarily. If not, We will add additional group by columns and first row functions. We make a new aggregation // operator. func (a *aggPushDownSolver) tryToPushDownAgg(aggFuncs []expression.AggregationFunction, gbyCols []*expression.Column, join *Join, childIdx int) LogicalPlan { child := join.GetChildByIndex(childIdx).(LogicalPlan) if a.allFirstRow(aggFuncs) { return child } agg := a.makeNewAgg(aggFuncs, gbyCols) child.SetParents(agg) agg.SetChildren(child) agg.correlated = agg.correlated || child.IsCorrelated() // If agg has no group-by item, it will return a default value, which may cause some bugs. // So here we add a group-by item forcely. if len(agg.GroupByItems) == 0 { agg.GroupByItems = []expression.Expression{&expression.Constant{ Value: types.NewDatum(0), RetType: types.NewFieldType(mysql.TypeLong)}} } if (childIdx == 0 && join.JoinType == RightOuterJoin) || (childIdx == 1 && join.JoinType == LeftOuterJoin) { var existsDefaultValues bool join.DefaultValues, existsDefaultValues = a.getDefaultValues(agg) if !existsDefaultValues { return child } } return agg }
// GetType implements AggregationFunction interface. func (af *avgFunction) GetType() *types.FieldType { ft := types.NewFieldType(mysql.TypeNewDecimal) ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin ft.Decimal = af.Args[0].GetType().Decimal return ft }
// GetType implements AggregationFunction interface. func (cf *countFunction) GetType() *types.FieldType { ft := types.NewFieldType(mysql.TypeLonglong) ft.Flen = 21 ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin return ft }
func (b *planBuilder) buildExists(p LogicalPlan) LogicalPlan { out: for { switch p.(type) { // This can be removed when in exists clause, // e.g. exists(select count(*) from t order by a) is equal to exists t. case *Trim, *Projection, *Sort, *Aggregation: p = p.GetChildByIndex(0).(LogicalPlan) p.SetParents() default: break out } } exists := &Exists{baseLogicalPlan: newBaseLogicalPlan(Ext, b.allocator)} exists.self = exists exists.initID() addChild(exists, p) newCol := &expression.Column{ FromID: exists.id, RetType: types.NewFieldType(mysql.TypeTiny), ColName: model.NewCIStr("exists_col")} exists.SetSchema([]*expression.Column{newCol}) exists.correlated = p.IsCorrelated() return exists }
// buildApply builds apply plan with outerPlan and innerPlan. Everytime we fetch a record from outerPlan and apply it to // innerPlan. This way is the so-called correlated execution. func (b *planBuilder) buildApply(outerPlan, innerPlan LogicalPlan, checker *ApplyConditionChecker) LogicalPlan { ap := &Apply{ Checker: checker, baseLogicalPlan: newBaseLogicalPlan(App, b.allocator), } ap.self = ap ap.initIDAndContext(b.ctx) addChild(ap, outerPlan) addChild(ap, innerPlan) corColumns := innerPlan.extractCorrelatedCols() ap.correlated = outerPlan.IsCorrelated() for _, corCol := range corColumns { // If the outer column can't be resolved from this outer schema, it should be resolved by outer schema. if idx := outerPlan.GetSchema().GetIndex(&corCol.Column); idx == -1 { ap.correlated = true break } } innerSchema := innerPlan.GetSchema().Clone() if checker == nil { for _, col := range innerSchema { col.IsAggOrSubq = true } ap.SetSchema(append(outerPlan.GetSchema().Clone(), innerSchema...)) } else { ap.SetSchema(append(outerPlan.GetSchema().Clone(), &expression.Column{ FromID: ap.id, ColName: model.NewCIStr("exists_row"), RetType: types.NewFieldType(mysql.TypeTiny), IsAggOrSubq: true, })) } return ap }
func (b *planBuilder) buildExplain(explain *ast.ExplainStmt) Plan { if show, ok := explain.Stmt.(*ast.ShowStmt); ok { return b.buildShow(show) } targetPlan := b.build(explain.Stmt) if b.err != nil { return nil } if logic, ok := targetPlan.(LogicalPlan); ok { var err error _, logic, err = logic.PredicatePushDown(nil) if err != nil { b.err = errors.Trace(err) return nil } _, err = logic.PruneColumnsAndResolveIndices(logic.GetSchema()) if err != nil { b.err = errors.Trace(err) return nil } _, res, _, err := logic.convert2PhysicalPlan(nil) if err != nil { b.err = errors.Trace(err) return nil } targetPlan = res.p.PushLimit(nil) } p := &Explain{StmtPlan: targetPlan} addChild(p, targetPlan) col := &expression.Column{ RetType: types.NewFieldType(mysql.TypeString), } p.SetSchema([]*expression.Column{col, col}) return p }
func (v *typeInferrer) aggregateFunc(x *ast.AggregateFuncExpr) { name := strings.ToLower(x.F) switch name { case "count": ft := types.NewFieldType(mysql.TypeLonglong) ft.Flen = 21 ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin x.SetType(ft) case "sum": ft := types.NewFieldType(mysql.TypeNewDecimal) ft.Charset = charset.CharsetBin ft.Collate = charset.CollationBin x.SetType(ft) } }
// See http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_unhex func builtinUnHex(args []types.Datum, ctx context.Context) (d types.Datum, err error) { switch args[0].Kind() { case types.KindNull: return d, nil case types.KindString: x, err := args[0].ToString() if err != nil { return d, errors.Trace(err) } bytes, err := hex.DecodeString(x) if err != nil { return d, nil } d.SetString(string(bytes)) return d, nil case types.KindInt64, types.KindUint64, types.KindMysqlHex, types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: x, _ := args[0].Cast(ctx.GetSessionVars().StmtCtx, types.NewFieldType(mysql.TypeString)) if x.IsNull() { return d, nil } bytes, err := hex.DecodeString(x.GetString()) if err != nil { return d, nil } d.SetString(string(bytes)) return d, nil default: return d, errors.Errorf("Unhex invalid args, need int or string but get %T", args[0].GetValue()) } }
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_extract func builtinExtract(args []types.Datum, _ context.Context) (d types.Datum, err error) { unit := args[0].GetString() vd := args[1] if vd.Kind() == types.KindNull { d.SetNull() return d, nil } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp val, err := vd.ConvertTo(f) if err != nil { d.SetNull() return d, errors.Trace(err) } if val.Kind() == types.KindNull { d.SetNull() return d, nil } if val.Kind() != types.KindMysqlTime { err = errors.Errorf("need time type, but got %T", val) d.SetNull() return d, err } t := val.GetMysqlTime() n, err1 := mysql.ExtractTimeNum(unit, t) if err1 != nil { d.SetNull() return d, errors.Trace(err1) } d.SetInt64(n) return d, nil }
func (e *Evaluator) funcExtract(v *ast.FuncExtractExpr) bool { val := v.Date.GetValue() if val == nil { v.SetValue(nil) return true } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp var err error val, err = types.Convert(val, f) if err != nil { e.err = errors.Trace(err) return false } if val == nil { v.SetValue(nil) return true } t, ok := val.(mysql.Time) if !ok { e.err = ErrInvalidOperation.Gen("need time type, but got %T", val) return false } n, err1 := mysql.ExtractTimeNum(v.Unit, t) if err1 != nil { e.err = errors.Trace(err1) return false } v.SetValue(n) return true }
func (s *testEvaluatorSuite) TestCast(c *C) { f := types.NewFieldType(mysql.TypeLonglong) expr := &ast.FuncCastExpr{ Expr: ast.NewValueExpr(1), Tp: f, } ctx := mock.NewContext() v, err := Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, Equals, int64(1)) f.Flag |= mysql.UnsignedFlag v, err = Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, Equals, uint64(1)) f.Tp = mysql.TypeString f.Charset = charset.CharsetBin v, err = Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, DeepEquals, []byte("1")) f.Tp = mysql.TypeString f.Charset = "utf8" v, err = Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, DeepEquals, "1") expr.Expr = ast.NewValueExpr(nil) v, err = Eval(ctx, expr) c.Assert(err, IsNil) c.Assert(v, IsNil) }
// regexp expression expects the target expression and pattern to be a string, if it's not, we add a cast function. func (v *typeInferrer) handleRegexpExpr(x *ast.PatternRegexpExpr) { x.SetType(types.NewFieldType(mysql.TypeLonglong)) x.Type.Charset = charset.CharsetBin x.Type.Collate = charset.CollationBin x.Expr = v.addCastToString(x.Expr) x.Pattern = v.addCastToString(x.Pattern) }
// Eval implements the Expression Eval interface. func (e *Extract) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) { v, err := e.Date.Eval(ctx, args) if v == nil || err != nil { return nil, errors.Trace(err) } f := types.NewFieldType(mysql.TypeDatetime) f.Decimal = mysql.MaxFsp v, err = types.Convert(v, f) if v == nil || err != nil { return nil, errors.Trace(err) } t, ok := v.(mysql.Time) if !ok { return nil, errors.Errorf("need time type, but got %T", v) } n, err1 := extractTime(e.Unit, t) if err1 != nil { return nil, errors.Trace(err1) } return n, nil }
func (b *planBuilder) buildSemiJoin(outerPlan, innerPlan LogicalPlan, onCondition []expression.Expression, asScalar bool, not bool) LogicalPlan { joinPlan := &Join{baseLogicalPlan: newBaseLogicalPlan(Jn, b.allocator)} joinPlan.initID() joinPlan.correlated = outerPlan.IsCorrelated() || innerPlan.IsCorrelated() for _, expr := range onCondition { joinPlan.correlated = joinPlan.correlated || tryDecorrelated(expr, outerPlan) } eqCond, leftCond, rightCond, otherCond := extractOnCondition(onCondition, outerPlan, innerPlan) joinPlan.EqualConditions = eqCond joinPlan.LeftConditions = leftCond joinPlan.RightConditions = rightCond joinPlan.OtherConditions = otherCond if asScalar { joinPlan.SetSchema(append(outerPlan.GetSchema().DeepCopy(), &expression.Column{ FromID: joinPlan.id, ColName: model.NewCIStr(fmt.Sprintf("%s_aux_0", joinPlan.id)), RetType: types.NewFieldType(mysql.TypeTiny), IsAggOrSubq: true, })) joinPlan.JoinType = SemiJoinWithAux } else { joinPlan.SetSchema(outerPlan.GetSchema().DeepCopy()) joinPlan.JoinType = SemiJoin } joinPlan.anti = not joinPlan.SetChildren(outerPlan, innerPlan) outerPlan.SetParents(joinPlan) innerPlan.SetParents(joinPlan) return joinPlan }
func (b *executorBuilder) buildSemiJoin(v *plan.PhysicalHashSemiJoin) Executor { var leftHashKey, rightHashKey []*expression.Column var targetTypes []*types.FieldType for _, eqCond := range v.EqualConditions { ln, _ := eqCond.Args[0].(*expression.Column) rn, _ := eqCond.Args[1].(*expression.Column) leftHashKey = append(leftHashKey, ln) rightHashKey = append(rightHashKey, rn) targetTypes = append(targetTypes, types.NewFieldType(types.MergeFieldType(ln.GetType().Tp, rn.GetType().Tp))) } e := &HashSemiJoinExec{ schema: v.GetSchema(), otherFilter: expression.ComposeCNFCondition(v.OtherConditions), bigFilter: expression.ComposeCNFCondition(v.LeftConditions), smallFilter: expression.ComposeCNFCondition(v.RightConditions), bigExec: b.build(v.GetChildByIndex(0)), smallExec: b.build(v.GetChildByIndex(1)), prepared: false, ctx: b.ctx, bigHashKey: leftHashKey, smallHashKey: rightHashKey, withAux: v.WithAux, anti: v.Anti, targetTypes: targetTypes, } return e }
// Eval implements the Expression Eval interface. func (c *Conversion) Eval(ctx context.Context, args map[interface{}]interface{}) (v interface{}, err error) { Val, err := c.Val.Eval(ctx, args) if err != nil { return } ft := types.NewFieldType(c.Tp) return types.Convert(Val, ft) }
func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) { var ( tp *types.FieldType chs = charset.CharsetBin ) switch x.FnName.L { case "abs", "ifnull", "nullif": tp = x.Args[0].GetType() case "pow", "power", "rand": tp = types.NewFieldType(mysql.TypeDouble) case "curdate", "current_date", "date": tp = types.NewFieldType(mysql.TypeDate) case "curtime", "current_time": tp = types.NewFieldType(mysql.TypeDuration) tp.Decimal = v.getFsp(x) case "current_timestamp": tp = types.NewFieldType(mysql.TypeDatetime) case "microsecond", "second", "minute", "hour", "day", "week", "month", "year", "dayofweek", "dayofmonth", "dayofyear", "weekday", "weekofyear", "yearweek", "found_rows", "length": tp = types.NewFieldType(mysql.TypeLonglong) case "now", "sysdate": tp = types.NewFieldType(mysql.TypeDatetime) tp.Decimal = v.getFsp(x) case "dayname", "version", "database", "user", "current_user", "concat", "concat_ws", "left", "lower", "repeat", "replace", "upper": tp = types.NewFieldType(mysql.TypeVarString) chs = v.defaultCharset case "connection_id": tp = types.NewFieldType(mysql.TypeLonglong) tp.Flag |= mysql.UnsignedFlag case "if": tp = x.Args[1].GetType() default: tp = types.NewFieldType(mysql.TypeUnspecified) } // If charset is unspecified. if len(tp.Charset) == 0 { tp.Charset = chs cln := charset.CollationBin if chs != charset.CharsetBin { var err error cln, err = charset.GetDefaultCollation(chs) if err != nil { v.err = err } } tp.Collate = cln } x.SetType(tp) }
func getRowArg(e expression.Expression, idx int) expression.Expression { if f, ok := e.(*expression.ScalarFunction); ok { return f.Args[idx] } c, _ := e.(*expression.Constant) d := c.Value.GetRow()[idx] return &expression.Constant{Value: d, RetType: types.NewFieldType(d.Kind())} }
func (b *planBuilder) buildExists(p Plan) Plan { exists := &Exists{} exists.id = b.allocID(exists) addChild(exists, p) newCol := &expression.Column{FromID: exists.id, RetType: types.NewFieldType(mysql.TypeTiny), ColName: model.NewCIStr("exists_col")} exists.SetSchema([]*expression.Column{newCol}) exists.correlated = p.IsCorrelated() return exists }