diff --git a/cmd/explaintest/r/ddl.result b/cmd/explaintest/r/ddl.result new file mode 100644 index 0000000000000..a7d8cfcd6d401 --- /dev/null +++ b/cmd/explaintest/r/ddl.result @@ -0,0 +1,8 @@ +create view sql_mode_view as select @@sql_mode; +Error 1351: View's SELECT contains a variable or parameter +create view sql_mode_view as select @@global.sql_mode; +Error 1351: View's SELECT contains a variable or parameter +create view sql_mode_view as select @a; +Error 1351: View's SELECT contains a variable or parameter +create view sql_mode_view as select 1 where @a = 4; +Error 1351: View's SELECT contains a variable or parameter diff --git a/cmd/explaintest/t/ddl.test b/cmd/explaintest/t/ddl.test new file mode 100644 index 0000000000000..cbee0fb3d5183 --- /dev/null +++ b/cmd/explaintest/t/ddl.test @@ -0,0 +1,9 @@ +# issue 53176 +-- error 1351 +create view sql_mode_view as select @@sql_mode; +-- error 1351 +create view sql_mode_view as select @@global.sql_mode; +-- error 1351 +create view sql_mode_view as select @a; +-- error 1351 +create view sql_mode_view as select 1 where @a = 4; diff --git a/errors.toml b/errors.toml index ed5b374dc7c84..1bb74ab68e6c5 100644 --- a/errors.toml +++ b/errors.toml @@ -856,6 +856,11 @@ error = ''' View's SELECT contains a '%s' clause ''' +["ddl:1351"] +error = ''' +View's SELECT contains a variable or parameter +''' + ["ddl:1353"] error = ''' In definition of view, derived table or common table expression, SELECT list and column names list have different column counts diff --git a/executor/ddl_test.go b/executor/ddl_test.go index bba2e2610c279..8762c4511bb95 100644 --- a/executor/ddl_test.go +++ b/executor/ddl_test.go @@ -232,9 +232,8 @@ func TestCreateView(t *testing.T) { // drop multiple views in a statement tk.MustExec("drop view v1,v2,v3,v4,v5,v6") // view with variable - tk.MustExec("create view v1 (c,d) as select a,b+@@global.max_user_connections from t1") - tk.MustGetErrMsg("create view v1 (c,d) as select a,b from t1 where a = @@global.max_user_connections", "[schema:1050]Table 'test.v1' already exists") - tk.MustExec("drop view v1") + tk.MustGetErrMsg("create view v1 (c,d) as select a,b+@@global.max_user_connections from t1", "[ddl:1351]View's SELECT contains a variable or parameter") + tk.MustGetErrMsg("create view v1 (c,d) as select a,b from t1 where a = @@global.max_user_connections", "[ddl:1351]View's SELECT contains a variable or parameter") // view with different col counts tk.MustGetErrCode("create view v1 (c,d,e) as select a,b from t1 ", errno.ErrViewWrongList) tk.MustGetErrCode("create view v1 (c) as select a,b from t1 ", errno.ErrViewWrongList) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 5c97007f47de5..1156dd9ab9ddb 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -4443,6 +4443,32 @@ func convertValueListToData(valueList []ast.ExprNode, handleColInfos []*model.Co return data, nil } +type userVariableChecker struct { + hasUserVariables bool +} + +func (e *userVariableChecker) Enter(in ast.Node) (ast.Node, bool) { + if _, ok := in.(*ast.VariableExpr); ok { + e.hasUserVariables = true + return in, true + } + return in, false +} + +func (*userVariableChecker) Leave(in ast.Node) (ast.Node, bool) { + return in, true +} + +// Check for UserVariables +func checkForUserVariables(in ast.Node) error { + v := &userVariableChecker{hasUserVariables: false} + _, ok := in.Accept(v) + if !ok || v.hasUserVariables { + return dbterror.ErrViewSelectVariable + } + return nil +} + func (b *PlanBuilder) buildDDL(ctx context.Context, node ast.DDLNode) (Plan, error) { var authErr error switch v := node.(type) { @@ -4582,6 +4608,10 @@ func (b *PlanBuilder) buildDDL(ctx context.Context, node ast.DDLNode) (Plan, err v.ReferTable.Name.L, "", authErr) } case *ast.CreateViewStmt: + err := checkForUserVariables(v.Select) + if err != nil { + return nil, err + } b.isCreateView = true b.capFlag |= canExpandAST | renameView b.renamingViewName = v.ViewName.Schema.L + "." + v.ViewName.Name.L diff --git a/util/dbterror/ddl_terror.go b/util/dbterror/ddl_terror.go index 1db0630977945..026b4701c6947 100644 --- a/util/dbterror/ddl_terror.go +++ b/util/dbterror/ddl_terror.go @@ -222,6 +222,8 @@ var ( ErrErrorOnRename = ClassDDL.NewStd(mysql.ErrErrorOnRename) // ErrViewSelectClause returns error for create view with select into clause ErrViewSelectClause = ClassDDL.NewStd(mysql.ErrViewSelectClause) + // ErrViewSelectVariable returns error for create view with select into clause + ErrViewSelectVariable = ClassDDL.NewStd(mysql.ErrViewSelectVariable) // ErrNotAllowedTypeInPartition returns not allowed type error when creating table partition with unsupported expression type. ErrNotAllowedTypeInPartition = ClassDDL.NewStd(mysql.ErrFieldTypeNotAllowedAsPartitionField)