Example #1
0
// SetSystemVar sets system variable and updates SessionVars states.
func SetSystemVar(vars *variable.SessionVars, name string, value types.Datum) error {
	name = strings.ToLower(name)
	if value.IsNull() {
		if name != variable.CharacterSetResults {
			return variable.ErrCantSetToNull
		}
		delete(vars.Systems, name)
		return nil
	}
	sVal, err := value.ToString()
	if err != nil {
		return errors.Trace(err)
	}
	switch name {
	case variable.SQLModeVar:
		sVal = strings.ToUpper(sVal)
		if strings.Contains(sVal, "STRICT_TRANS_TABLES") || strings.Contains(sVal, "STRICT_ALL_TABLES") {
			vars.StrictSQLMode = true
		} else {
			vars.StrictSQLMode = false
		}
	case variable.TiDBSnapshot:
		err = setSnapshotTS(vars, sVal)
		if err != nil {
			return errors.Trace(err)
		}
	case variable.AutocommitVar:
		isAutocommit := strings.EqualFold(sVal, "ON") || sVal == "1"
		vars.SetStatusFlag(mysql.ServerStatusAutocommit, isAutocommit)
	case variable.TiDBSkipConstraintCheck:
		vars.SkipConstraintCheck = (sVal == "1")
	}
	vars.Systems[name] = sVal
	return nil
}
Example #2
0
// SetSystemVar sets a system variable.
func (s *SessionVars) SetSystemVar(key string, value types.Datum) error {
	key = strings.ToLower(key)
	if value.IsNull() {
		if key != characterSetResults {
			return errCantSetToNull
		}
		delete(s.systems, key)
		return nil
	}
	sVal, err := value.ToString()
	if err != nil {
		return errors.Trace(err)
	}
	if key == sqlMode {
		sVal = strings.ToUpper(sVal)
		if strings.Contains(sVal, "STRICT_TRANS_TABLES") || strings.Contains(sVal, "STRICT_ALL_TABLES") {
			s.StrictSQLMode = true
		} else {
			s.StrictSQLMode = false
		}
	} else if key == TiDBSnapshot {
		err = s.setSnapshotTS(sVal)
		if err != nil {
			return errors.Trace(err)
		}
	}
	s.systems[key] = sVal
	return nil
}
Example #3
0
func unflatten(datum types.Datum, tp *types.FieldType) (types.Datum, error) {
	if datum.IsNull() {
		return datum, nil
	}
	switch tp.Tp {
	case mysql.TypeFloat:
		datum.SetFloat32(float32(datum.GetFloat64()))
		return datum, nil
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong,
		mysql.TypeDouble, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob,
		mysql.TypeVarchar, mysql.TypeString:
		return datum, nil
	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
		var t mysql.Time
		t.Type = tp.Tp
		t.Fsp = tp.Decimal
		err := t.Unmarshal(datum.GetBytes())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(t)
		return datum, nil
	case mysql.TypeDuration:
		dur := mysql.Duration{Duration: time.Duration(datum.GetInt64())}
		datum.SetValue(dur)
		return datum, nil
	case mysql.TypeNewDecimal, mysql.TypeDecimal:
		dec, err := mysql.ParseDecimal(datum.GetString())
		if err != nil {
			return datum, errors.Trace(err)
		}
		if tp.Decimal >= 0 {
			dec = dec.Truncate(int32(tp.Decimal))
		}
		datum.SetValue(dec)
		return datum, nil
	case mysql.TypeEnum:
		enum, err := mysql.ParseEnumValue(tp.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(enum)
		return datum, nil
	case mysql.TypeSet:
		set, err := mysql.ParseSetValue(tp.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(set)
		return datum, nil
	case mysql.TypeBit:
		bit := mysql.Bit{Value: datum.GetUint64(), Width: tp.Flen}
		datum.SetValue(bit)
		return datum, nil
	}
	log.Error(tp.Tp, datum)
	return datum, nil
}
Example #4
0
func (r *rangeBuilder) buildFormBinOp(expr *expression.ScalarFunction) []rangePoint {
	// This has been checked that the binary operation is comparison operation, and one of
	// the operand is column name expression.
	var value types.Datum
	var op string
	if v, ok := expr.Args[0].(*expression.Constant); ok {
		value = v.Value
		switch expr.FuncName.L {
		case ast.GE:
			op = ast.LE
		case ast.GT:
			op = ast.LT
		case ast.LT:
			op = ast.GT
		case ast.LE:
			op = ast.GE
		default:
			op = expr.FuncName.L
		}
	} else {
		value = expr.Args[1].(*expression.Constant).Value
		op = expr.FuncName.L
	}
	if value.IsNull() {
		return nil
	}

	switch op {
	case ast.EQ:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case ast.NE:
		startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint1 := rangePoint{value: value, excl: true}
		startPoint2 := rangePoint{value: value, start: true, excl: true}
		endPoint2 := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
	case ast.LT:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value, excl: true}
		return []rangePoint{startPoint, endPoint}
	case ast.LE:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case ast.GT:
		startPoint := rangePoint{value: value, start: true, excl: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	case ast.GE:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	}
	return nil
}
Example #5
0
func (n *finalAggregater) updateSum(val types.Datum, count uint64) error {
	ctx := n.getContext()
	if val.IsNull() {
		return nil
	}
	var err error
	ctx.Value, err = types.CalculateSum(ctx.Value, val.GetValue())
	if err != nil {
		return errors.Trace(err)
	}
	ctx.Count += int64(count)
	return nil
}
Example #6
0
// Unflatten converts a raw datum to a column datum.
func Unflatten(datum types.Datum, ft *types.FieldType, inIndex bool) (types.Datum, error) {
	if datum.IsNull() {
		return datum, nil
	}
	switch ft.Tp {
	case mysql.TypeFloat:
		datum.SetFloat32(float32(datum.GetFloat64()))
		return datum, nil
	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeYear, mysql.TypeInt24,
		mysql.TypeLong, mysql.TypeLonglong, mysql.TypeDouble, mysql.TypeTinyBlob,
		mysql.TypeMediumBlob, mysql.TypeBlob, mysql.TypeLongBlob, mysql.TypeVarchar,
		mysql.TypeString:
		return datum, nil
	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
		var t types.Time
		t.Type = ft.Tp
		t.Fsp = ft.Decimal
		var err error
		err = t.FromPackedUint(datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetMysqlTime(t)
		return datum, nil
	case mysql.TypeDuration:
		dur := types.Duration{Duration: time.Duration(datum.GetInt64())}
		datum.SetValue(dur)
		return datum, nil
	case mysql.TypeEnum:
		enum, err := types.ParseEnumValue(ft.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(enum)
		return datum, nil
	case mysql.TypeSet:
		set, err := types.ParseSetValue(ft.Elems, datum.GetUint64())
		if err != nil {
			return datum, errors.Trace(err)
		}
		datum.SetValue(set)
		return datum, nil
	case mysql.TypeBit:
		bit := types.Bit{Value: datum.GetUint64(), Width: ft.Flen}
		datum.SetValue(bit)
		return datum, nil
	}
	return datum, nil
}
Example #7
0
func abbrDayOfMonth(arg types.Datum, ctx context.Context) (types.Datum, error) {
	day, err := builtinDayOfMonth([]types.Datum{arg}, ctx)
	if err != nil || arg.IsNull() {
		return types.Datum{}, errors.Trace(err)
	}
	var str string
	switch day.GetInt64() {
	case 1, 21, 31:
		str = "st"
	case 2, 22:
		str = "nd"
	case 3, 23:
		str = "rd"
	default:
		str = "th"
	}

	d := types.NewStringDatum(fmt.Sprintf("%d%s", day.GetInt64(), str))
	return d, nil
}
Example #8
0
func (n *finalAggregater) updateMaxMin(val types.Datum, max bool) error {
	ctx := n.getContext()
	if val.IsNull() {
		return nil
	}
	if ctx.Value.IsNull() {
		ctx.Value = val
		return nil
	}
	c, err := ctx.Value.CompareDatum(val)
	if err != nil {
		return errors.Trace(err)
	}
	if max {
		if c == -1 {
			ctx.Value = val
		}
	} else if c == 1 {
		ctx.Value = val
	}
	return nil
}
Example #9
0
func updateRecord(ctx context.Context, h int64, oldData, newData []types.Datum, assignFlag []bool, t table.Table, offset int, onDuplicateUpdate bool) error {
	cols := t.Cols()
	touched := make(map[int]bool, len(cols))
	assignExists := false
	sc := ctx.GetSessionVars().StmtCtx
	var newHandle types.Datum
	for i, hasSetExpr := range assignFlag {
		if !hasSetExpr {
			if onDuplicateUpdate {
				newData[i] = oldData[i]
			}
			continue
		}
		if i < offset || i >= offset+len(cols) {
			// The assign expression is for another table, not this.
			continue
		}

		colIndex := i - offset
		col := cols[colIndex]
		if col.IsPKHandleColumn(t.Meta()) {
			newHandle = newData[i]
		}
		if mysql.HasAutoIncrementFlag(col.Flag) {
			if newData[i].IsNull() {
				return errors.Errorf("Column '%v' cannot be null", col.Name.O)
			}
			val, err := newData[i].ToInt64(sc)
			if err != nil {
				return errors.Trace(err)
			}
			t.RebaseAutoID(val, true)
		}

		touched[colIndex] = true
		assignExists = true
	}

	// If no assign list for this table, no need to update.
	if !assignExists {
		return nil
	}

	// Check whether new value is valid.
	if err := table.CastValues(ctx, newData, cols, false); err != nil {
		return errors.Trace(err)
	}

	if err := table.CheckNotNull(cols, newData); err != nil {
		return errors.Trace(err)
	}

	// If row is not changed, we should do nothing.
	rowChanged := false
	for i := range oldData {
		if !touched[i] {
			continue
		}

		n, err := newData[i].CompareDatum(sc, oldData[i])
		if err != nil {
			return errors.Trace(err)
		}
		if n != 0 {
			rowChanged = true
			break
		}
	}
	if !rowChanged {
		// See https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html  CLIENT_FOUND_ROWS
		if ctx.GetSessionVars().ClientCapability&mysql.ClientFoundRows > 0 {
			sc.AddAffectedRows(1)
		}
		return nil
	}

	var err error
	if !newHandle.IsNull() {
		err = t.RemoveRecord(ctx, h, oldData)
		if err != nil {
			return errors.Trace(err)
		}
		_, err = t.AddRecord(ctx, newData)
	} else {
		// Update record to new value and update index.
		err = t.UpdateRecord(ctx, h, oldData, newData, touched)
	}
	if err != nil {
		return errors.Trace(err)
	}
	dirtyDB := getDirtyDB(ctx)
	tid := t.Meta().ID
	dirtyDB.deleteRow(tid, h)
	dirtyDB.addRow(tid, h, newData)

	// Record affected rows.
	if !onDuplicateUpdate {
		sc.AddAffectedRows(1)
	} else {
		sc.AddAffectedRows(2)
	}
	return nil
}
Example #10
0
// CheckNotNull checks if nil value set to a column with NotNull flag is set.
func (c *Column) CheckNotNull(data types.Datum) error {
	if mysql.HasNotNullFlag(c.Flag) && data.IsNull() {
		return errColumnCantNull.Gen("Column %s can't be null.", c.Name)
	}
	return nil
}
Example #11
0
func (er *expressionRewriter) rewriteVariable(v *ast.VariableExpr) bool {
	stkLen := len(er.ctxStack)
	name := strings.ToLower(v.Name)
	sessionVars := variable.GetSessionVars(er.b.ctx)
	globalVars := variable.GetGlobalVarAccessor(er.b.ctx)
	if !v.IsSystem {
		var d types.Datum
		var err error
		if v.Value != nil {
			d, err = er.ctxStack[stkLen-1].Eval(nil, er.b.ctx)
			if err != nil {
				er.err = errors.Trace(err)
				return false
			}
			er.ctxStack = er.ctxStack[:stkLen-1]
		}
		if !d.IsNull() {
			strVal, err := d.ToString()
			if err != nil {
				er.err = errors.Trace(err)
				return false
			}
			sessionVars.Users[name] = strings.ToLower(strVal)
			er.ctxStack = append(er.ctxStack, datumToConstant(d, mysql.TypeString))
		} else if value, ok := sessionVars.Users[name]; ok {
			er.ctxStack = append(er.ctxStack, datumToConstant(types.NewStringDatum(value), mysql.TypeString))
		} else {
			// select null user vars is permitted.
			er.ctxStack = append(er.ctxStack, &expression.Constant{RetType: types.NewFieldType(mysql.TypeNull)})
		}
		return true
	}

	sysVar, ok := variable.SysVars[name]
	if !ok {
		// select null sys vars is not permitted
		er.err = variable.UnknownSystemVar.Gen("Unknown system variable '%s'", name)
		return false
	}
	if sysVar.Scope == variable.ScopeNone {
		er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(sysVar.Value), mysql.TypeString))
		return true
	}

	if v.IsGlobal {
		value, err := globalVars.GetGlobalSysVar(er.b.ctx, name)
		if err != nil {
			er.err = errors.Trace(err)
			return false
		}
		er.ctxStack = append(er.ctxStack, datumToConstant(types.NewDatum(value), mysql.TypeString))
		return true
	}
	d := sessionVars.GetSystemVar(name)
	if d.IsNull() {
		if sysVar.Scope&variable.ScopeGlobal == 0 {
			d.SetString(sysVar.Value)
		} else {
			// Get global system variable and fill it in session.
			globalVal, err := globalVars.GetGlobalSysVar(er.b.ctx, name)
			if err != nil {
				er.err = errors.Trace(err)
				return false
			}
			d.SetString(globalVal)
			err = sessionVars.SetSystemVar(name, d)
			if err != nil {
				er.err = errors.Trace(err)
				return false
			}
		}
	}
	er.ctxStack = append(er.ctxStack, datumToConstant(d, mysql.TypeString))
	return true
}
Example #12
0
File: range.go Project: yubobo/tidb
func (r *rangeBuilder) buildFromBinop(x *ast.BinaryOperationExpr) []rangePoint {
	if x.Op == opcode.OrOr {
		return r.union(r.build(x.L), r.build(x.R))
	} else if x.Op == opcode.AndAnd {
		return r.intersection(r.build(x.L), r.build(x.R))
	}
	// This has been checked that the binary operation is comparison operation, and one of
	// the operand is column name expression.
	var value types.Datum
	var op opcode.Op
	if _, ok := x.L.(*ast.ValueExpr); ok {
		value = types.NewDatum(x.L.GetValue())
		switch x.Op {
		case opcode.GE:
			op = opcode.LE
		case opcode.GT:
			op = opcode.LT
		case opcode.LT:
			op = opcode.GT
		case opcode.LE:
			op = opcode.GE
		default:
			op = x.Op
		}
	} else {
		value = types.NewDatum(x.R.GetValue())
		op = x.Op
	}
	if value.IsNull() {
		return nil
	}
	switch op {
	case opcode.EQ:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case opcode.NE:
		startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint1 := rangePoint{value: value, excl: true}
		startPoint2 := rangePoint{value: value, start: true, excl: true}
		endPoint2 := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
	case opcode.LT:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value, excl: true}
		return []rangePoint{startPoint, endPoint}
	case opcode.LE:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case opcode.GT:
		startPoint := rangePoint{value: value, start: true, excl: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	case opcode.GE:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	}
	return nil
}
Example #13
0
func convertDateFormat(ctx context.Context, arg types.Datum, b byte) (types.Datum, error) {
	var d types.Datum
	var err error

	switch b {
	case 'b':
		d, err = builtinMonthName([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(d.GetString()[:3])
		}
	case 'M':
		d, err = builtinMonthName([]types.Datum{arg}, ctx)
	case 'm':
		d, err = builtinMonth([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'c':
		d, err = builtinMonth([]types.Datum{arg}, ctx)
	case 'D':
		d, err = abbrDayOfMonth(arg, ctx)
	case 'd':
		d, err = builtinDayOfMonth([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'e':
		d, err = builtinDayOfMonth([]types.Datum{arg}, ctx)
	case 'j':
		d, err = builtinDayOfYear([]types.Datum{arg}, ctx)
		if err == nil {
			d.SetString(fmt.Sprintf("%03d", d.GetInt64()))
		}
	case 'H', 'k':
		d, err = builtinHour([]types.Datum{arg}, ctx)
		if err == nil && b == 'H' && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'h', 'I', 'l':
		d, err = builtinHour([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			if d.GetInt64() > 12 {
				d.SetInt64(d.GetInt64() - 12)
			} else if d.GetInt64() == 0 {
				d.SetInt64(12)
			}
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'i':
		d, err = builtinMinute([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'p':
		d, err = builtinHour([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			if d.GetInt64() < 12 {
				d.SetString("AM")
				break
			}
			d.SetString("PM")
		}
	case 'r':
		d, err = to12Hour(arg, ctx)
	case 'T':
		d, err = builtinTime([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			duration := types.Duration{
				Duration: d.GetMysqlDuration().Duration,
				Fsp:      0}
			d.SetMysqlDuration(duration)
		}
	case 'S', 's':
		d, err = builtinSecond([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'f':
		d, err = builtinMicroSecond([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%06d", d.GetInt64()))
		}
	case 'U':
		d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(0)}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'u':
		d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(1)}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'V':
		d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(2)}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'v':
		d, err = builtinWeek([]types.Datum{arg, types.NewIntDatum(3)}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%02d", d.GetInt64()))
		}
	case 'a':
		d, err = builtinDayName([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(d.GetString()[:3])
		}
	case 'W':
		d, err = builtinDayName([]types.Datum{arg}, ctx)
	case 'w':
		d, err = builtinDayOfWeek([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetInt64(d.GetInt64() - 1)
		}
	case 'X':
		d, err = builtinYearWeek([]types.Datum{arg, types.NewIntDatum(2)}, ctx)
		if err == nil && !d.IsNull() {
			if d.GetInt64() == math.MaxUint32 {
				break
			}
			str := fmt.Sprintf("%04d", d.GetInt64())
			d.SetString(fmt.Sprintf("%04s", str[:4]))
		}
	case 'x':
		d, err = builtinYearWeek([]types.Datum{arg, types.NewIntDatum(3)}, ctx)
		if err == nil && !d.IsNull() {
			if d.GetInt64() == math.MaxUint32 {
				break
			}
			str := fmt.Sprintf("%04d", d.GetInt64())
			d.SetString(fmt.Sprintf("%04s", str[:4]))
		}
	case 'Y':
		d, err = builtinYear([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			d.SetString(fmt.Sprintf("%04d", d.GetInt64()))
		}
	case 'y':
		d, err = builtinYear([]types.Datum{arg}, ctx)
		if err == nil && !d.IsNull() {
			str := fmt.Sprintf("%04d", d.GetInt64())
			d.SetString(fmt.Sprintf("%02s", str[2:]))
		}
	default:
		d.SetString(string(b))
	}

	if err == nil && !d.IsNull() {
		d.SetString(fmt.Sprintf("%v", d.GetValue()))
	}
	return d, errors.Trace(err)
}
Example #14
0
func (r *rangeBuilder) buildFromScalarFunc(expr *expression.ScalarFunction) []rangePoint {
	// TODO: It only implements the binary operation range building. And it needs to implement other scalar functions.
	if len(expr.Args) != 2 {
		return nil
	}

	if expr.FuncName.L == ast.OrOr {
		return r.union(r.newBuild(expr.Args[0]), r.newBuild(expr.Args[1]))
	}
	if expr.FuncName.L == ast.AndAnd {
		return r.intersection(r.newBuild(expr.Args[0]), r.newBuild(expr.Args[1]))
	}

	// This has been checked that the binary operation is comparison operation, and one of
	// the operand is column name expression.
	var value types.Datum
	var op string
	if v, ok := expr.Args[0].(*expression.Constant); ok {
		value = v.Value
		switch expr.FuncName.L {
		case ast.GE:
			op = ast.LE
		case ast.GT:
			op = ast.LT
		case ast.LT:
			op = ast.GT
		case ast.LE:
			op = ast.GE
		default:
			op = expr.FuncName.L
		}
	} else {
		value = expr.Args[1].(*expression.Constant).Value
		op = expr.FuncName.L
	}
	if value.IsNull() {
		return nil
	}

	switch op {
	case ast.EQ:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case ast.NE:
		startPoint1 := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint1 := rangePoint{value: value, excl: true}
		startPoint2 := rangePoint{value: value, start: true, excl: true}
		endPoint2 := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint1, endPoint1, startPoint2, endPoint2}
	case ast.LT:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value, excl: true}
		return []rangePoint{startPoint, endPoint}
	case ast.LE:
		startPoint := rangePoint{value: types.MinNotNullDatum(), start: true}
		endPoint := rangePoint{value: value}
		return []rangePoint{startPoint, endPoint}
	case ast.GT:
		startPoint := rangePoint{value: value, start: true, excl: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	case ast.GE:
		startPoint := rangePoint{value: value, start: true}
		endPoint := rangePoint{value: types.MaxValueDatum()}
		return []rangePoint{startPoint, endPoint}
	}
	return nil
}