diff --git a/cmd/explaintest/r/select.result b/cmd/explaintest/r/select.result index 1518289183fd0..d8d41aa80d7f7 100644 --- a/cmd/explaintest/r/select.result +++ b/cmd/explaintest/r/select.result @@ -137,7 +137,7 @@ select !(1 + 2); !(1 + 2) 0 select + - 1, --1, +-+-+1, + "123"; -+ - 1 --1 +-+-+1 + "123" ++ - 1 --1 +-+-+1 123 -1 1 1 123 select --------------------1, ++++++++++++++++++++1; --------------------1 ++++++++++++++++++++1 diff --git a/executor/executor_test.go b/executor/executor_test.go index 06002070ee828..5d709a37dfe56 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -2072,6 +2072,16 @@ func (s *testSuiteP2) TestColumnName(c *C) { // It's a compatibility issue. Should be empty instead. c.Assert(fields[0].ColumnAsName.L, Equals, "if(1,c,c)") rs.Close() + + // Test case for query a column wrapped with parentheses and unary plus. + // In this case, the column name should be its original name. + rs, err = tk.Exec("select (c), (+c), +(c), +(+(c)), ++c from t") + c.Check(err, IsNil) + fields = rs.Fields() + for i := 0; i < 5; i++ { + c.Check(fields[0].Column.Name.L, Equals, "c") + c.Check(fields[0].ColumnAsName.L, Equals, "c") + } } func (s *testSuiteP2) TestSelectVar(c *C) { diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 30ec613ada651..4f82462213e5e 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -557,10 +557,12 @@ func (b *planBuilder) buildSelection(p LogicalPlan, where ast.ExprNode, AggMappe } // buildProjectionFieldNameFromColumns builds the field name, table name and database name when field expression is a column reference. -func (b *planBuilder) buildProjectionFieldNameFromColumns(origField *ast.SelectField, colNameField *ast.ColumnNameExpr, c *expression.Column) (colName, origColName, tblName, origTblName, dbName model.CIStr) { - origColName, tblName, dbName = colNameField.Name.Name, colNameField.Name.Table, colNameField.Name.Schema - if origField.AsName.L != "" { - colName = origField.AsName +func (b *planBuilder) buildProjectionFieldNameFromColumns(field *ast.SelectField, c *expression.Column) (colName, origColName, tblName, origTblName, dbName model.CIStr) { + if astCol, ok := getInnerFromParenthesesAndUnaryPlus(field.Expr).(*ast.ColumnNameExpr); ok { + origColName, tblName, dbName = astCol.Name.Name, astCol.Name.Table, astCol.Name.Schema + } + if field.AsName.L != "" { + colName = field.AsName } else { colName = origColName } @@ -580,7 +582,7 @@ func (b *planBuilder) buildProjectionFieldNameFromExpressions(field *ast.SelectF return agg.Args[0].(*ast.ColumnNameExpr).Name.Name } - innerExpr := getInnerFromParentheses(field.Expr) + innerExpr := getInnerFromParenthesesAndUnaryPlus(field.Expr) valueExpr, isValueExpr := innerExpr.(*driver.ValueExpr) // Non-literal: Output as inputed, except that comments need to be removed. @@ -617,13 +619,13 @@ func (b *planBuilder) buildProjectionFieldNameFromExpressions(field *ast.SelectF // buildProjectionField builds the field object according to SelectField in projection. func (b *planBuilder) buildProjectionField(id, position int, field *ast.SelectField, expr expression.Expression) *expression.Column { var origTblName, tblName, origColName, colName, dbName model.CIStr - innerNode := getInnerFromParentheses(field.Expr) + innerNode := getInnerFromParenthesesAndUnaryPlus(field.Expr) col, isCol := expr.(*expression.Column) // Correlated column won't affect the final output names. So we can put it in any of the three logic block. // Don't put it into the first block just for simplifying the codes. - if colNameField, ok := innerNode.(*ast.ColumnNameExpr); ok && isCol { + if _, ok := innerNode.(*ast.ColumnNameExpr); ok && isCol { // Field is a column reference. - colName, origColName, tblName, origTblName, dbName = b.buildProjectionFieldNameFromColumns(field, colNameField, col) + colName, origColName, tblName, origTblName, dbName = b.buildProjectionFieldNameFromColumns(field, col) } else if field.AsName.L != "" { // Field has alias. colName = field.AsName @@ -2576,9 +2578,12 @@ func appendVisitInfo(vi []visitInfo, priv mysql.PrivilegeType, db, tbl, col stri }) } -func getInnerFromParentheses(expr ast.ExprNode) ast.ExprNode { +func getInnerFromParenthesesAndUnaryPlus(expr ast.ExprNode) ast.ExprNode { if pexpr, ok := expr.(*ast.ParenthesesExpr); ok { - return getInnerFromParentheses(pexpr.Expr) + return getInnerFromParenthesesAndUnaryPlus(pexpr.Expr) + } + if uexpr, ok := expr.(*ast.UnaryOperationExpr); ok && uexpr.Op == opcode.Plus { + return getInnerFromParenthesesAndUnaryPlus(uexpr.V) } return expr }