зеркало из https://github.com/github/vitess-gh.git
v3: handle ORDER BY NULL
ORDER BY NULL is a special-case construct that serves as hint to the optimizer that the client is not expecting the result in any particular order. So, it's safe to push it down to all routes without regard to relational rules.
This commit is contained in:
Родитель
630d76b100
Коммит
5a44ded295
|
@ -208,6 +208,21 @@
|
|||
}
|
||||
}
|
||||
|
||||
# ORDER BY NULL
|
||||
"select col from user order by null"
|
||||
{
|
||||
"Original": "select col from user order by null",
|
||||
"Instructions": {
|
||||
"Opcode": "SelectScatter",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"Query": "select col from user order by null",
|
||||
"FieldQuery": "select col from user where 1 != 1"
|
||||
}
|
||||
}
|
||||
|
||||
# ORDER BY for join
|
||||
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by a asc, user.col2 desc, music.col3 asc"
|
||||
{
|
||||
|
@ -250,6 +265,48 @@
|
|||
}
|
||||
}
|
||||
|
||||
# ORDER BY NULL for join
|
||||
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by null"
|
||||
{
|
||||
"Original": "select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by null",
|
||||
"Instructions": {
|
||||
"Opcode": "Join",
|
||||
"Left": {
|
||||
"Opcode": "SelectEqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"Query": "select user.col1 as a, user.col2, user.id from user where user.id = 1 order by null",
|
||||
"FieldQuery": "select user.col1 as a, user.col2, user.id from user where 1 != 1",
|
||||
"Vindex": "user_index",
|
||||
"Values": 1
|
||||
},
|
||||
"Right": {
|
||||
"Opcode": "SelectEqualUnique",
|
||||
"Keyspace": {
|
||||
"Name": "user",
|
||||
"Sharded": true
|
||||
},
|
||||
"Query": "select music.col3 from music where music.id = :user_id order by null",
|
||||
"FieldQuery": "select music.col3 from music where 1 != 1",
|
||||
"Vindex": "music_user_map",
|
||||
"Values": ":user_id",
|
||||
"JoinVars": {
|
||||
"user_id": {}
|
||||
}
|
||||
},
|
||||
"Cols": [
|
||||
-1,
|
||||
-2,
|
||||
1
|
||||
],
|
||||
"Vars": {
|
||||
"user_id": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ORDER BY for join, using column numbers
|
||||
"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by 1 asc, 2 desc, 3 asc"
|
||||
{
|
||||
|
|
|
@ -1594,6 +1594,10 @@ const (
|
|||
|
||||
// Format formats the node.
|
||||
func (node *Order) Format(buf *TrackedBuffer) {
|
||||
if node, ok := node.Expr.(*NullVal); ok {
|
||||
buf.Myprintf("%v", node)
|
||||
return
|
||||
}
|
||||
buf.Myprintf("%v %s", node.Expr, node.Direction)
|
||||
}
|
||||
|
||||
|
|
|
@ -397,6 +397,8 @@ func TestValid(t *testing.T) {
|
|||
input: "select /* order by asc */ 1 from t order by a asc",
|
||||
}, {
|
||||
input: "select /* order by desc */ 1 from t order by a desc",
|
||||
}, {
|
||||
input: "select /* order by null */ 1 from t order by null",
|
||||
}, {
|
||||
input: "select /* limit a */ 1 from t limit a",
|
||||
}, {
|
||||
|
|
|
@ -50,6 +50,10 @@ type builder interface {
|
|||
// column. The function must return a colsym for the expression
|
||||
// and the column number of the result.
|
||||
PushSelect(expr *sqlparser.NonStarExpr, rb *route) (colsym *colsym, colnum int, err error)
|
||||
// PushOrderByNull pushes the special case ORDER By NULL to
|
||||
// all routes. It's safe to push down this clause because it's
|
||||
// just on optimization hint.
|
||||
PushOrderByNull()
|
||||
// PushMisc pushes miscelleaneous constructs to all the routes.
|
||||
// This should not propagate to subqueries.
|
||||
PushMisc(sel *sqlparser.Select)
|
||||
|
|
|
@ -140,6 +140,12 @@ func (jb *join) PushSelect(expr *sqlparser.NonStarExpr, rb *route) (colsym *cols
|
|||
return colsym, len(jb.Colsyms) - 1, nil
|
||||
}
|
||||
|
||||
// PushOrderByNull pushes misc constructs to the underlying routes.
|
||||
func (jb *join) PushOrderByNull() {
|
||||
jb.Left.PushOrderByNull()
|
||||
jb.Right.PushOrderByNull()
|
||||
}
|
||||
|
||||
// PushMisc pushes misc constructs to the underlying routes.
|
||||
func (jb *join) PushMisc(sel *sqlparser.Select) {
|
||||
jb.Left.PushMisc(sel)
|
||||
|
|
|
@ -73,8 +73,15 @@ func pushOrderBy(orderBy sqlparser.OrderBy, bldr builder) error {
|
|||
s := bldr.Symtab().SetState(symtabOrderBy)
|
||||
defer bldr.Symtab().SetState(s)
|
||||
|
||||
if orderBy == nil {
|
||||
switch len(orderBy) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
// Special handling for ORDER BY NULL. Push it everywhere.
|
||||
if _, ok := orderBy[0].Expr.(*sqlparser.NullVal); ok {
|
||||
bldr.PushOrderByNull()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
routeNumber := 0
|
||||
for _, order := range orderBy {
|
||||
|
|
|
@ -386,6 +386,11 @@ func (rb *route) SetLimit(limit *sqlparser.Limit) {
|
|||
rb.Select.Limit = limit
|
||||
}
|
||||
|
||||
// PushOrderByNull updates the comments & 'for update' sections of the route.
|
||||
func (rb *route) PushOrderByNull() {
|
||||
rb.Select.OrderBy = sqlparser.OrderBy{&sqlparser.Order{Expr: &sqlparser.NullVal{}}}
|
||||
}
|
||||
|
||||
// PushMisc updates the comments & 'for update' sections of the route.
|
||||
func (rb *route) PushMisc(sel *sqlparser.Select) {
|
||||
rb.Select.Comments = sel.Comments
|
||||
|
|
Загрузка…
Ссылка в новой задаче