Beispiel #1
0
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)
	}
}
Beispiel #2
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)
}
Beispiel #3
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":
		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)
}
Beispiel #4
0
func (e *SetExecutor) setCharset(cs, co string) error {
	var err error
	if len(co) == 0 {
		co, err = charset.GetDefaultCollation(cs)
		if err != nil {
			return errors.Trace(err)
		}
	}
	sessionVars := e.ctx.GetSessionVars()
	for _, v := range variable.SetNamesVariables {
		sessionVars.Systems[v] = cs
	}
	sessionVars.Systems[variable.CollationConnection] = co
	return nil
}
Beispiel #5
0
// Exec implements the stmt.Statement Exec interface.
// SET NAMES sets the three session system variables character_set_client, character_set_connection,
// and character_set_results to the given character set. Setting character_set_connection to charset_name
// also sets collation_connection to the default collation for charset_name.
// The optional COLLATE clause may be used to specify a collation explicitly.
func (s *SetCharsetStmt) Exec(ctx context.Context) (_ rset.Recordset, err error) {
	log.Debug("Set charset to ", s.Charset)
	collation := s.Collate
	if len(collation) == 0 {
		collation, err = charset.GetDefaultCollation(s.Charset)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	sessionVars := variable.GetSessionVars(ctx)
	for _, v := range variable.SetNamesVariables {
		sessionVars.Systems[v] = s.Charset
	}
	sessionVars.Systems[variable.CollationConnection] = collation
	return nil, nil
}
Beispiel #6
0
func (e *SimpleExec) executeSetCharset(s *ast.SetCharsetStmt) error {
	collation := s.Collate
	if len(collation) == 0 {
		var err error
		collation, err = charset.GetDefaultCollation(s.Charset)
		if err != nil {
			return errors.Trace(err)
		}
	}
	sessionVars := variable.GetSessionVars(e.ctx)
	for _, v := range variable.SetNamesVariables {
		sessionVars.Systems[v] = s.Charset
	}
	sessionVars.Systems[variable.CollationConnection] = collation
	return nil
}
Beispiel #7
0
func (e *SimpleExec) setCharset(cs, co string) error {
	var err error
	if len(co) == 0 {
		co, err = charset.GetDefaultCollation(cs)
		if err != nil {
			return errors.Trace(err)
		}
	}
	sessionVars := variable.GetSessionVars(e.ctx)
	for _, v := range variable.SetNamesVariables {
		err = sessionVars.SetSystemVar(v, types.NewStringDatum(cs))
		if err != nil {
			return errors.Trace(err)
		}
	}
	err = sessionVars.SetSystemVar(variable.CollationConnection, types.NewStringDatum(co))
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Beispiel #8
0
func (e *SimpleExec) executeSetCharset(s *ast.SetCharsetStmt) error {
	collation := s.Collate
	var err error
	if len(collation) == 0 {
		collation, err = charset.GetDefaultCollation(s.Charset)
		if err != nil {
			return errors.Trace(err)
		}
	}
	sessionVars := variable.GetSessionVars(e.ctx)
	for _, v := range variable.SetNamesVariables {
		err = sessionVars.SetSystemVar(v, types.NewStringDatum(s.Charset))
		if err != nil {
			return errors.Trace(err)
		}
	}
	err = sessionVars.SetSystemVar(variable.CollationConnection, types.NewStringDatum(collation))
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}
Beispiel #9
0
func (v *typeInferrer) Leave(in ast.Node) (out ast.Node, ok bool) {
	switch x := in.(type) {
	case *ast.AggregateFuncExpr:
		v.aggregateFunc(x)
	case *ast.BetweenExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.BinaryOperationExpr:
		v.binaryOperation(x)
	case *ast.CaseExpr:
		v.handleCaseExpr(x)
	case *ast.ColumnNameExpr:
		x.SetType(&x.Refer.Column.FieldType)
	case *ast.CompareSubqueryExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.ExistsSubqueryExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.FuncCallExpr:
		v.handleFuncCallExpr(x)
	case *ast.FuncCastExpr:
		x.SetType(x.Tp)
		if len(x.Type.Charset) == 0 {
			x.Type.Charset, x.Type.Collate = types.DefaultCharsetForType(x.Type.Tp)
		}
	case *ast.IsNullExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.IsTruthExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.ParamMarkerExpr:
		x.SetType(types.DefaultTypeForValue(x.GetValue()))
	case *ast.ParenthesesExpr:
		x.SetType(x.Expr.GetType())
	case *ast.PatternInExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.PatternLikeExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.PatternRegexpExpr:
		x.SetType(types.NewFieldType(mysql.TypeLonglong))
		x.Type.Charset = charset.CharsetBin
		x.Type.Collate = charset.CollationBin
	case *ast.SelectStmt:
		v.selectStmt(x)
	case *ast.UnaryOperationExpr:
		v.unaryOperation(x)
	case *ast.ValueExpr:
		v.handleValueExpr(x)
	case *ast.VariableExpr:
		x.SetType(types.NewFieldType(mysql.TypeVarString))
		x.Type.Charset = v.defaultCharset
		cln, err := charset.GetDefaultCollation(v.defaultCharset)
		if err != nil {
			v.err = err
		}
		x.Type.Collate = cln
		// TODO: handle all expression types.
	}
	return in, true
}
Beispiel #10
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()
		// TODO: We should cover all types.
		if x.FnName.L == "abs" && tp.Tp == mysql.TypeDatetime {
			tp = types.NewFieldType(mysql.TypeDouble)
		}
	case "greatest":
		for _, arg := range x.Args {
			InferType(v.sc, arg)
		}
		if len(x.Args) > 0 {
			tp = x.Args[0].GetType()
			for i := 1; i < len(x.Args); i++ {
				mergeArithType(tp.Tp, x.Args[i].GetType().Tp)
			}
		}
	case "ceil", "ceiling":
		t := x.Args[0].GetType().Tp
		if t == mysql.TypeNull || t == mysql.TypeFloat || t == mysql.TypeDouble || t == mysql.TypeVarchar ||
			t == mysql.TypeTinyBlob || t == mysql.TypeMediumBlob || t == mysql.TypeLongBlob ||
			t == mysql.TypeBlob || t == mysql.TypeVarString || t == mysql.TypeString {
			tp = types.NewFieldType(mysql.TypeDouble)
		} else {
			tp = types.NewFieldType(mysql.TypeLonglong)
		}
	case "ln", "log", "log2", "log10":
		tp = types.NewFieldType(mysql.TypeDouble)
	case "pow", "power", "rand":
		tp = types.NewFieldType(mysql.TypeDouble)
	case "curdate", "current_date", "date":
		tp = types.NewFieldType(mysql.TypeDate)
	case "curtime", "current_time", "timediff":
		tp = types.NewFieldType(mysql.TypeDuration)
		tp.Decimal = v.getFsp(x)
	case "current_timestamp", "date_arith":
		tp = types.NewFieldType(mysql.TypeDatetime)
	case "microsecond", "second", "minute", "hour", "day", "week", "month", "year",
		"dayofweek", "dayofmonth", "dayofyear", "weekday", "weekofyear", "yearweek",
		"found_rows", "length", "extract", "locate":
		tp = types.NewFieldType(mysql.TypeLonglong)
	case "now", "sysdate":
		tp = types.NewFieldType(mysql.TypeDatetime)
		tp.Decimal = v.getFsp(x)
	case "from_unixtime":
		if len(x.Args) == 1 {
			tp = types.NewFieldType(mysql.TypeDatetime)
		} else {
			tp = types.NewFieldType(mysql.TypeVarString)
			chs = v.defaultCharset
		}
	case "str_to_date":
		tp = types.NewFieldType(mysql.TypeDatetime)
	case "dayname", "version", "database", "user", "current_user", "schema",
		"concat", "concat_ws", "left", "lcase", "lower", "repeat",
		"replace", "ucase", "upper", "convert", "substring",
		"substring_index", "trim", "ltrim", "rtrim", "reverse", "hex", "unhex", "date_format":
		tp = types.NewFieldType(mysql.TypeVarString)
		chs = v.defaultCharset
	case "strcmp", "isnull":
		tp = types.NewFieldType(mysql.TypeLonglong)
	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()
	case "get_lock", "release_lock":
		tp = types.NewFieldType(mysql.TypeLonglong)
	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)
}