github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/executor/executor_xapi.go (about) 1 // Copyright 2016 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package executor 15 16 import ( 17 "math" 18 "sort" 19 "sync" 20 "time" 21 22 "github.com/insionng/yougam/libraries/golang/protobuf/proto" 23 "github.com/insionng/yougam/libraries/juju/errors" 24 "github.com/insionng/yougam/libraries/ngaut/log" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/context" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/evaluator" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 31 "github.com/insionng/yougam/libraries/pingcap/tidb/optimizer/plan" 32 "github.com/insionng/yougam/libraries/pingcap/tidb/parser/opcode" 33 "github.com/insionng/yougam/libraries/pingcap/tidb/table" 34 "github.com/insionng/yougam/libraries/pingcap/tidb/util/codec" 35 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 36 "github.com/insionng/yougam/libraries/pingcap/tidb/xapi" 37 "github.com/insionng/yougam/libraries/pingcap/tidb/xapi/tablecodec" 38 "github.com/insionng/yougam/libraries/pingcap/tipb/go-tipb" 39 ) 40 41 // XSelectTableExec represents XAPI select executor. 42 type XSelectTableExec struct { 43 table table.Table 44 tablePlan *plan.TableScan 45 where *tipb.Expr 46 ctx context.Context 47 result *xapi.SelectResult 48 subResult *xapi.SubResult 49 supportDesc bool 50 allFiltersPushed bool 51 } 52 53 // Next implements Executor Next interface. 54 func (e *XSelectTableExec) Next() (*Row, error) { 55 if e.result == nil { 56 err := e.doRequest() 57 if err != nil { 58 return nil, errors.Trace(err) 59 } 60 } 61 for { 62 if e.subResult == nil { 63 var err error 64 startTs := time.Now() 65 e.subResult, err = e.result.Next() 66 if err != nil { 67 return nil, errors.Trace(err) 68 } 69 if e.subResult == nil { 70 return nil, nil 71 } 72 log.Debugf("[TIME_TABLE_SCAN] %v", time.Now().Sub(startTs)) 73 } 74 h, rowData, err := e.subResult.Next() 75 if err != nil { 76 return nil, errors.Trace(err) 77 } 78 if rowData == nil { 79 e.subResult = nil 80 continue 81 } 82 fullRowData := make([]types.Datum, len(e.tablePlan.Fields())) 83 var j int 84 for i, field := range e.tablePlan.Fields() { 85 if field.Referenced { 86 fullRowData[i] = rowData[j] 87 field.Expr.SetDatum(rowData[j]) 88 j++ 89 } 90 } 91 return resultRowToRow(e.table, h, fullRowData, e.tablePlan.TableAsName), nil 92 } 93 } 94 95 // Fields implements Executor Fields interface. 96 func (e *XSelectTableExec) Fields() []*ast.ResultField { 97 return e.tablePlan.Fields() 98 } 99 100 // Close implements Executor Close interface. 101 func (e *XSelectTableExec) Close() error { 102 if e.result != nil { 103 e.result.Close() 104 } 105 return nil 106 } 107 108 func resultRowToRow(t table.Table, h int64, data []types.Datum, tableAsName *model.CIStr) *Row { 109 entry := &RowKeyEntry{ 110 Handle: h, 111 Tbl: t, 112 TableAsName: tableAsName, 113 } 114 return &Row{Data: data, RowKeys: []*RowKeyEntry{entry}} 115 } 116 117 func (e *XSelectTableExec) doRequest() error { 118 txn, err := e.ctx.GetTxn(false) 119 if err != nil { 120 return errors.Trace(err) 121 } 122 selReq := new(tipb.SelectRequest) 123 startTs := txn.StartTS() 124 selReq.StartTs = &startTs 125 selReq.Fields = resultFieldsToPBExpression(e.tablePlan.Fields()) 126 selReq.Where = e.where 127 selReq.Ranges = tableRangesToPBRanges(e.tablePlan.Ranges) 128 if e.supportDesc { 129 if e.tablePlan.Desc { 130 selReq.OrderBy = append(selReq.OrderBy, &tipb.ByItem{Desc: &e.tablePlan.Desc}) 131 } 132 // Limit can be pushed only if desc is supported. 133 if e.allFiltersPushed { 134 selReq.Limit = e.tablePlan.LimitCount 135 } 136 } 137 columns := make([]*model.ColumnInfo, 0, len(e.tablePlan.Fields())) 138 for _, v := range e.tablePlan.Fields() { 139 if v.Referenced { 140 columns = append(columns, v.Column) 141 } 142 } 143 selReq.TableInfo = &tipb.TableInfo{ 144 TableId: proto.Int64(e.table.Meta().ID), 145 } 146 selReq.TableInfo.Columns = tablecodec.ColumnsToProto(columns, e.table.Meta().PKIsHandle) 147 e.result, err = xapi.Select(txn.GetClient(), selReq, 1) 148 if err != nil { 149 return errors.Trace(err) 150 } 151 return nil 152 } 153 154 // XSelectIndexExec represents XAPI select index executor. 155 type XSelectIndexExec struct { 156 table table.Table 157 indexPlan *plan.IndexScan 158 ctx context.Context 159 where *tipb.Expr 160 supportDesc bool 161 162 tasks []*lookupTableTask 163 taskCursor int 164 indexOrder map[int64]int 165 166 mu sync.Mutex 167 } 168 169 // BaseLookupTableTaskSize represents base number of handles for a lookupTableTask. 170 var BaseLookupTableTaskSize = 1024 171 172 // MaxLookupTableTaskSize represents max number of handles for a lookupTableTask. 173 var MaxLookupTableTaskSize = 1024 174 175 const ( 176 taskNew int = iota 177 taskRunning 178 taskDone 179 ) 180 181 type lookupTableTask struct { 182 handles []int64 183 rows []*Row 184 cursor int 185 status int 186 done bool 187 doneCh chan error 188 } 189 190 // Fields implements Executor Fields interface. 191 func (e *XSelectIndexExec) Fields() []*ast.ResultField { 192 return e.indexPlan.Fields() 193 } 194 195 // Next implements Executor Next interface. 196 func (e *XSelectIndexExec) Next() (*Row, error) { 197 if e.tasks == nil { 198 startTs := time.Now() 199 handles, err := e.fetchHandles() 200 if err != nil { 201 return nil, errors.Trace(err) 202 } 203 log.Debugf("[TIME_INDEX_SCAN] time: %v handles: %d", time.Now().Sub(startTs), len(handles)) 204 e.buildTableTasks(handles) 205 limitCount := int64(-1) 206 if e.indexPlan.LimitCount != nil { 207 limitCount = *e.indexPlan.LimitCount 208 } 209 concurrency := 2 210 if e.indexPlan.NoLimit { 211 concurrency = len(e.tasks) 212 } else if limitCount > int64(BaseLookupTableTaskSize) { 213 concurrency = int(limitCount/int64(BaseLookupTableTaskSize) + 1) 214 } 215 log.Debugf("[TIME_INDEX_TABLE_CONCURRENT_SCAN] start %d workers", concurrency) 216 e.runTableTasks(concurrency) 217 } 218 for { 219 if e.taskCursor >= len(e.tasks) { 220 return nil, nil 221 } 222 task := e.tasks[e.taskCursor] 223 if !task.done { 224 startTs := time.Now() 225 err := <-task.doneCh 226 if err != nil { 227 return nil, errors.Trace(err) 228 } 229 task.done = true 230 log.Debugf("[TIME_INDEX_TABLE_SCAN] time: %v handles: %d", time.Now().Sub(startTs), len(task.handles)) 231 } 232 if task.cursor < len(task.rows) { 233 row := task.rows[task.cursor] 234 for i, field := range e.indexPlan.Fields() { 235 field.Expr.SetDatum(row.Data[i]) 236 } 237 task.cursor++ 238 return row, nil 239 } 240 e.taskCursor++ 241 } 242 } 243 244 func (e *XSelectIndexExec) pickAndExecTask() { 245 for { 246 // Pick a new task. 247 e.mu.Lock() 248 var task *lookupTableTask 249 for _, t := range e.tasks { 250 if t.status == taskNew { 251 task = t 252 task.status = taskRunning 253 break 254 } 255 } 256 e.mu.Unlock() 257 if task == nil { 258 // No more task to run. 259 break 260 } 261 // Execute the picked task. 262 err := e.executeTask(task) 263 e.mu.Lock() 264 task.status = taskDone 265 e.mu.Unlock() 266 task.doneCh <- err 267 } 268 } 269 270 func (e *XSelectIndexExec) runTableTasks(n int) { 271 for i := 0; i < n && i < len(e.tasks); i++ { 272 go e.pickAndExecTask() 273 } 274 } 275 276 func (e *XSelectIndexExec) executeTask(task *lookupTableTask) error { 277 sort.Sort(int64Slice(task.handles)) 278 tblResult, err := e.doTableRequest(task.handles) 279 if err != nil { 280 return errors.Trace(err) 281 } 282 task.rows, err = e.extractRowsFromTableResult(e.table, tblResult) 283 if err != nil { 284 return errors.Trace(err) 285 } 286 if !e.indexPlan.OutOfOrder { 287 // Restore the index order. 288 sorter := &rowsSorter{order: e.indexOrder, rows: task.rows} 289 if e.indexPlan.Desc && !e.supportDesc { 290 sort.Sort(sort.Reverse(sorter)) 291 } else { 292 sort.Sort(sorter) 293 } 294 } 295 return nil 296 } 297 298 // Close implements Executor Close interface. 299 func (e *XSelectIndexExec) Close() error { 300 return nil 301 } 302 303 // fetchHandle fetches all handles from the index. 304 // This should be optimized to fetch handles in batch. 305 func (e *XSelectIndexExec) fetchHandles() ([]int64, error) { 306 idxResult, err := e.doIndexRequest() 307 if err != nil { 308 return nil, errors.Trace(err) 309 } 310 handles, err := extractHandlesFromIndexResult(idxResult) 311 if err != nil { 312 return nil, errors.Trace(err) 313 } 314 if !e.indexPlan.OutOfOrder { 315 // Save the index order. 316 e.indexOrder = make(map[int64]int) 317 for i, h := range handles { 318 e.indexOrder[h] = i 319 } 320 } 321 return handles, nil 322 } 323 324 func (e *XSelectIndexExec) buildTableTasks(handles []int64) { 325 // Build tasks with increasing batch size. 326 var taskSizes []int 327 total := len(handles) 328 batchSize := BaseLookupTableTaskSize 329 for total > 0 { 330 if batchSize > total { 331 batchSize = total 332 } 333 taskSizes = append(taskSizes, batchSize) 334 total -= batchSize 335 if batchSize < MaxLookupTableTaskSize { 336 batchSize *= 2 337 } 338 } 339 if e.indexPlan.Desc && !e.supportDesc { 340 // Reverse tasks sizes. 341 for i := 0; i < len(taskSizes)/2; i++ { 342 j := len(taskSizes) - i - 1 343 taskSizes[i], taskSizes[j] = taskSizes[j], taskSizes[i] 344 } 345 } 346 e.tasks = make([]*lookupTableTask, len(taskSizes)) 347 for i, size := range taskSizes { 348 task := &lookupTableTask{ 349 handles: handles[:size], 350 } 351 task.doneCh = make(chan error, 1) 352 handles = handles[size:] 353 e.tasks[i] = task 354 } 355 if e.indexPlan.Desc && !e.supportDesc { 356 // Reverse tasks order. 357 for i := 0; i < len(e.tasks)/2; i++ { 358 j := len(e.tasks) - i - 1 359 e.tasks[i], e.tasks[j] = e.tasks[j], e.tasks[i] 360 } 361 } 362 } 363 364 type rowsSorter struct { 365 order map[int64]int 366 rows []*Row 367 } 368 369 func (s *rowsSorter) Less(i, j int) bool { 370 x := s.order[s.rows[i].RowKeys[0].Handle] 371 y := s.order[s.rows[j].RowKeys[0].Handle] 372 return x < y 373 } 374 375 func (s *rowsSorter) Len() int { 376 return len(s.rows) 377 } 378 379 func (s *rowsSorter) Swap(i, j int) { 380 s.rows[i], s.rows[j] = s.rows[j], s.rows[i] 381 } 382 383 func (e *XSelectIndexExec) doIndexRequest() (*xapi.SelectResult, error) { 384 txn, err := e.ctx.GetTxn(false) 385 if err != nil { 386 return nil, errors.Trace(err) 387 } 388 selIdxReq := new(tipb.SelectRequest) 389 startTs := txn.StartTS() 390 selIdxReq.StartTs = &startTs 391 selIdxReq.IndexInfo = tablecodec.IndexToProto(e.table.Meta(), e.indexPlan.Index) 392 if len(e.indexPlan.FilterConditions) == 0 { 393 // Push limit to index request only if there is not filter conditions. 394 selIdxReq.Limit = e.indexPlan.LimitCount 395 } 396 if e.indexPlan.Desc { 397 selIdxReq.OrderBy = append(selIdxReq.OrderBy, &tipb.ByItem{Desc: &e.indexPlan.Desc}) 398 } 399 fieldTypes := make([]*types.FieldType, len(e.indexPlan.Index.Columns)) 400 for i, v := range e.indexPlan.Index.Columns { 401 fieldTypes[i] = &(e.table.Cols()[v.Offset].FieldType) 402 } 403 selIdxReq.Ranges, err = indexRangesToPBRanges(e.indexPlan.Ranges, fieldTypes) 404 if err != nil { 405 return nil, errors.Trace(err) 406 } 407 concurrency := 1 408 if e.indexPlan.OutOfOrder { 409 concurrency = 10 410 } 411 return xapi.Select(txn.GetClient(), selIdxReq, concurrency) 412 } 413 414 func (e *XSelectIndexExec) doTableRequest(handles []int64) (*xapi.SelectResult, error) { 415 txn, err := e.ctx.GetTxn(false) 416 if err != nil { 417 return nil, errors.Trace(err) 418 } 419 // The handles are not in original index order, so we can't push limit here. 420 selTableReq := new(tipb.SelectRequest) 421 startTs := txn.StartTS() 422 selTableReq.StartTs = &startTs 423 columns := make([]*model.ColumnInfo, 0, len(e.indexPlan.Fields())) 424 for _, v := range e.indexPlan.Fields() { 425 if v.Referenced { 426 columns = append(columns, v.Column) 427 } 428 } 429 selTableReq.TableInfo = &tipb.TableInfo{ 430 TableId: proto.Int64(e.table.Meta().ID), 431 } 432 selTableReq.TableInfo.Columns = tablecodec.ColumnsToProto(columns, e.table.Meta().PKIsHandle) 433 selTableReq.Fields = resultFieldsToPBExpression(e.indexPlan.Fields()) 434 for _, h := range handles { 435 if h == math.MaxInt64 { 436 // We can't convert MaxInt64 into an left closed, right open range. 437 continue 438 } 439 pbRange := new(tipb.KeyRange) 440 pbRange.Low = codec.EncodeInt(nil, h) 441 pbRange.High = kv.Key(pbRange.Low).PrefixNext() 442 selTableReq.Ranges = append(selTableReq.Ranges, pbRange) 443 } 444 selTableReq.Where = e.where 445 return xapi.Select(txn.GetClient(), selTableReq, 10) 446 } 447 448 // conditionsToPBExpr tries to convert filter conditions to a tipb.Expr. 449 // not supported conditions will be returned in remained. 450 func (b *executorBuilder) conditionsToPBExpr(client kv.Client, exprs []ast.ExprNode, tn *ast.TableName) (pbexpr *tipb.Expr, 451 remained []ast.ExprNode) { 452 for _, expr := range exprs { 453 v := b.exprToPBExpr(client, expr, tn) 454 if v == nil { 455 remained = append(remained, expr) 456 } else { 457 if pbexpr == nil { 458 pbexpr = v 459 } else { 460 // merge multiple converted pb expression into an AND expression. 461 pbexpr = &tipb.Expr{Tp: tipb.ExprType_And.Enum(), Children: []*tipb.Expr{pbexpr, v}} 462 } 463 } 464 } 465 return 466 } 467 468 func resultFieldsToPBExpression(fields []*ast.ResultField) []*tipb.Expr { 469 return nil 470 } 471 472 func tableRangesToPBRanges(tableRanges []plan.TableRange) []*tipb.KeyRange { 473 hrs := make([]*tipb.KeyRange, 0, len(tableRanges)) 474 for _, tableRange := range tableRanges { 475 pbRange := new(tipb.KeyRange) 476 pbRange.Low = codec.EncodeInt(nil, tableRange.LowVal) 477 hi := tableRange.HighVal 478 if hi != math.MaxInt64 { 479 hi++ 480 } 481 pbRange.High = codec.EncodeInt(nil, hi) 482 hrs = append(hrs, pbRange) 483 } 484 return hrs 485 } 486 487 func indexRangesToPBRanges(ranges []*plan.IndexRange, fieldTypes []*types.FieldType) ([]*tipb.KeyRange, error) { 488 keyRanges := make([]*tipb.KeyRange, 0, len(ranges)) 489 for _, ran := range ranges { 490 err := convertIndexRangeTypes(ran, fieldTypes) 491 if err != nil { 492 return nil, errors.Trace(err) 493 } 494 low, err := codec.EncodeKey(nil, ran.LowVal...) 495 if err != nil { 496 return nil, errors.Trace(err) 497 } 498 if ran.LowExclude { 499 low = []byte(kv.Key(low).PrefixNext()) 500 } 501 high, err := codec.EncodeKey(nil, ran.HighVal...) 502 if err != nil { 503 return nil, errors.Trace(err) 504 } 505 if !ran.HighExclude { 506 high = []byte(kv.Key(high).PrefixNext()) 507 } 508 keyRanges = append(keyRanges, &tipb.KeyRange{Low: low, High: high}) 509 } 510 return keyRanges, nil 511 } 512 513 func convertIndexRangeTypes(ran *plan.IndexRange, fieldTypes []*types.FieldType) error { 514 for i := range ran.LowVal { 515 if ran.LowVal[i].Kind() == types.KindMinNotNull { 516 ran.LowVal[i].SetBytes([]byte{}) 517 continue 518 } 519 converted, err := ran.LowVal[i].ConvertTo(fieldTypes[i]) 520 if err != nil { 521 return errors.Trace(err) 522 } 523 cmp, err := converted.CompareDatum(ran.LowVal[i]) 524 if err != nil { 525 return errors.Trace(err) 526 } 527 ran.LowVal[i] = converted 528 if cmp == 0 { 529 continue 530 } 531 if cmp < 0 && !ran.LowExclude { 532 // For int column a, a >= 1.1 is converted to a > 1. 533 ran.LowExclude = true 534 } else if cmp > 0 && ran.LowExclude { 535 // For int column a, a > 1.9 is converted to a >= 2. 536 ran.LowExclude = false 537 } 538 // The converted value has changed, the other column values doesn't matter. 539 // For equal condition, converted value changed means there will be no match. 540 // For non equal condition, this column would be the last one to build the range. 541 // Break here to prevent the rest columns modify LowExclude again. 542 break 543 } 544 for i := range ran.HighVal { 545 if ran.HighVal[i].Kind() == types.KindMaxValue { 546 continue 547 } 548 converted, err := ran.HighVal[i].ConvertTo(fieldTypes[i]) 549 if err != nil { 550 return errors.Trace(err) 551 } 552 cmp, err := converted.CompareDatum(ran.HighVal[i]) 553 if err != nil { 554 return errors.Trace(err) 555 } 556 ran.HighVal[i] = converted 557 if cmp == 0 { 558 continue 559 } 560 // For int column a, a < 1.1 is converted to a <= 1. 561 if cmp < 0 && ran.HighExclude { 562 ran.HighExclude = false 563 } 564 // For int column a, a <= 1.9 is converted to a < 2. 565 if cmp > 0 && !ran.HighExclude { 566 ran.HighExclude = true 567 } 568 break 569 } 570 return nil 571 } 572 573 func extractHandlesFromIndexResult(idxResult *xapi.SelectResult) ([]int64, error) { 574 var handles []int64 575 for { 576 subResult, err := idxResult.Next() 577 if err != nil { 578 return nil, errors.Trace(err) 579 } 580 if subResult == nil { 581 break 582 } 583 subHandles, err := extractHandlesFromIndexSubResult(subResult) 584 if err != nil { 585 return nil, errors.Trace(err) 586 } 587 handles = append(handles, subHandles...) 588 } 589 return handles, nil 590 } 591 592 func extractHandlesFromIndexSubResult(subResult *xapi.SubResult) ([]int64, error) { 593 var handles []int64 594 for { 595 h, data, err := subResult.Next() 596 if err != nil { 597 return nil, errors.Trace(err) 598 } 599 if data == nil { 600 break 601 } 602 handles = append(handles, h) 603 } 604 return handles, nil 605 } 606 607 func (e *XSelectIndexExec) extractRowsFromTableResult(t table.Table, tblResult *xapi.SelectResult) ([]*Row, error) { 608 var rows []*Row 609 for { 610 subResult, err := tblResult.Next() 611 if err != nil { 612 return nil, errors.Trace(err) 613 } 614 if subResult == nil { 615 break 616 } 617 subRows, err := e.extractRowsFromSubResult(t, subResult) 618 if err != nil { 619 return nil, errors.Trace(err) 620 } 621 rows = append(rows, subRows...) 622 } 623 return rows, nil 624 } 625 626 func (e *XSelectIndexExec) extractRowsFromSubResult(t table.Table, subResult *xapi.SubResult) ([]*Row, error) { 627 var rows []*Row 628 for { 629 h, rowData, err := subResult.Next() 630 if err != nil { 631 return nil, errors.Trace(err) 632 } 633 if rowData == nil { 634 break 635 } 636 fullRowData := make([]types.Datum, len(e.indexPlan.Fields())) 637 var j int 638 for i, field := range e.indexPlan.Fields() { 639 if field.Referenced { 640 fullRowData[i] = rowData[j] 641 j++ 642 } 643 } 644 row := resultRowToRow(t, h, fullRowData, e.indexPlan.TableAsName) 645 rows = append(rows, row) 646 } 647 return rows, nil 648 } 649 650 type int64Slice []int64 651 652 func (p int64Slice) Len() int { return len(p) } 653 func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } 654 func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 655 656 // exprToPBExpr converts an ast.ExprNode to a tipb.Expr, if not supported, nil will be returned. 657 func (b *executorBuilder) exprToPBExpr(client kv.Client, expr ast.ExprNode, tn *ast.TableName) *tipb.Expr { 658 switch x := expr.(type) { 659 case *ast.ValueExpr, *ast.ParamMarkerExpr: 660 return b.datumToPBExpr(client, *expr.GetDatum()) 661 case *ast.ColumnNameExpr: 662 return b.columnNameToPBExpr(client, x, tn) 663 case *ast.BinaryOperationExpr: 664 return b.binopToPBExpr(client, x, tn) 665 case *ast.ParenthesesExpr: 666 return b.exprToPBExpr(client, x.Expr, tn) 667 case *ast.PatternLikeExpr: 668 return b.likeToPBExpr(client, x, tn) 669 case *ast.UnaryOperationExpr: 670 return b.unaryToPBExpr(client, x, tn) 671 case *ast.PatternInExpr: 672 return b.patternInToPBExpr(client, x, tn) 673 case *ast.SubqueryExpr: 674 return b.subqueryToPBExpr(client, x) 675 default: 676 return nil 677 } 678 } 679 680 func (b *executorBuilder) columnNameToPBExpr(client kv.Client, column *ast.ColumnNameExpr, tn *ast.TableName) *tipb.Expr { 681 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_ColumnRef)) { 682 return nil 683 } 684 // Zero Column ID is not a column from table, can not support for now. 685 if column.Refer.Column.ID == 0 { 686 return nil 687 } 688 switch column.Refer.Expr.GetType().Tp { 689 case mysql.TypeBit, mysql.TypeSet, mysql.TypeEnum, mysql.TypeDecimal, mysql.TypeNewDecimal, mysql.TypeGeometry, 690 mysql.TypeDate, mysql.TypeNewDate, mysql.TypeDatetime, mysql.TypeDuration, mysql.TypeTimestamp, mysql.TypeYear: 691 return nil 692 } 693 matched := false 694 for _, f := range tn.GetResultFields() { 695 if f.TableName == column.Refer.TableName && f.Column.ID == column.Refer.Column.ID { 696 matched = true 697 break 698 } 699 } 700 if matched { 701 pbExpr := new(tipb.Expr) 702 pbExpr.Tp = tipb.ExprType_ColumnRef.Enum() 703 pbExpr.Val = codec.EncodeInt(nil, column.Refer.Column.ID) 704 return pbExpr 705 } 706 // If the column ID is in fields, it means the column is from an outer table, 707 // its value is available to use. 708 return b.datumToPBExpr(client, *column.Refer.Expr.GetDatum()) 709 } 710 711 func (b *executorBuilder) datumToPBExpr(client kv.Client, d types.Datum) *tipb.Expr { 712 var tp tipb.ExprType 713 var val []byte 714 switch d.Kind() { 715 case types.KindNull: 716 tp = tipb.ExprType_Null 717 case types.KindInt64: 718 tp = tipb.ExprType_Int64 719 val = codec.EncodeInt(nil, d.GetInt64()) 720 case types.KindUint64: 721 tp = tipb.ExprType_Uint64 722 val = codec.EncodeUint(nil, d.GetUint64()) 723 case types.KindString: 724 tp = tipb.ExprType_String 725 val = d.GetBytes() 726 case types.KindBytes: 727 tp = tipb.ExprType_Bytes 728 val = d.GetBytes() 729 case types.KindFloat32: 730 tp = tipb.ExprType_Float32 731 val = codec.EncodeFloat(nil, d.GetFloat64()) 732 case types.KindFloat64: 733 tp = tipb.ExprType_Float64 734 val = codec.EncodeFloat(nil, d.GetFloat64()) 735 default: 736 return nil 737 } 738 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tp)) { 739 return nil 740 } 741 return &tipb.Expr{Tp: tp.Enum(), Val: val} 742 } 743 744 func (b *executorBuilder) binopToPBExpr(client kv.Client, expr *ast.BinaryOperationExpr, tn *ast.TableName) *tipb.Expr { 745 var tp tipb.ExprType 746 switch expr.Op { 747 case opcode.LT: 748 tp = tipb.ExprType_LT 749 case opcode.LE: 750 tp = tipb.ExprType_LE 751 case opcode.EQ: 752 tp = tipb.ExprType_EQ 753 case opcode.NE: 754 tp = tipb.ExprType_NE 755 case opcode.GE: 756 tp = tipb.ExprType_GE 757 case opcode.GT: 758 tp = tipb.ExprType_GT 759 case opcode.NullEQ: 760 tp = tipb.ExprType_NullEQ 761 case opcode.AndAnd: 762 tp = tipb.ExprType_And 763 case opcode.OrOr: 764 tp = tipb.ExprType_Or 765 default: 766 return nil 767 } 768 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tp)) { 769 return nil 770 } 771 leftExpr := b.exprToPBExpr(client, expr.L, tn) 772 if leftExpr == nil { 773 return nil 774 } 775 rightExpr := b.exprToPBExpr(client, expr.R, tn) 776 if rightExpr == nil { 777 return nil 778 } 779 return &tipb.Expr{Tp: tp.Enum(), Children: []*tipb.Expr{leftExpr, rightExpr}} 780 } 781 782 // Only patterns like 'abc', '%abc', 'abc%', '%abc%' can be converted to *tipb.Expr for now. 783 func (b *executorBuilder) likeToPBExpr(client kv.Client, expr *ast.PatternLikeExpr, tn *ast.TableName) *tipb.Expr { 784 if expr.Escape != '\\' { 785 return nil 786 } 787 patternDatum := expr.Pattern.GetDatum() 788 if patternDatum.Kind() != types.KindString { 789 return nil 790 } 791 patternStr := patternDatum.GetString() 792 for i, r := range patternStr { 793 switch r { 794 case '\\', '_': 795 return nil 796 case '%': 797 if i != 0 && i != len(patternStr)-1 { 798 return nil 799 } 800 } 801 } 802 patternExpr := b.exprToPBExpr(client, expr.Pattern, tn) 803 if patternExpr == nil { 804 return nil 805 } 806 targetExpr := b.exprToPBExpr(client, expr.Expr, tn) 807 if targetExpr == nil { 808 return nil 809 } 810 likeExpr := &tipb.Expr{Tp: tipb.ExprType_Like.Enum(), Children: []*tipb.Expr{targetExpr, patternExpr}} 811 if !expr.Not { 812 return likeExpr 813 } 814 return &tipb.Expr{Tp: tipb.ExprType_Not.Enum(), Children: []*tipb.Expr{likeExpr}} 815 } 816 817 func (b *executorBuilder) unaryToPBExpr(client kv.Client, expr *ast.UnaryOperationExpr, tn *ast.TableName) *tipb.Expr { 818 switch expr.Op { 819 case opcode.Not: 820 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_Not)) { 821 return nil 822 } 823 default: 824 return nil 825 } 826 child := b.exprToPBExpr(client, expr.V, tn) 827 if child == nil { 828 return nil 829 } 830 return &tipb.Expr{Tp: tipb.ExprType_Not.Enum(), Children: []*tipb.Expr{child}} 831 } 832 833 func (b *executorBuilder) subqueryToPBExpr(client kv.Client, expr *ast.SubqueryExpr) *tipb.Expr { 834 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_ValueList)) { 835 return nil 836 } 837 if expr.Correlated || len(expr.Query.GetResultFields()) != 1 { 838 // We only push down evaluated non-correlated subquery which has only one field. 839 return nil 840 } 841 err := evaluator.EvalSubquery(b.ctx, expr) 842 if err != nil { 843 b.err = errors.Trace(err) 844 return nil 845 } 846 if expr.Datum.Kind() != types.KindRow { 847 // Do not push down datum kind is not row. 848 return nil 849 } 850 return b.datumsToValueList(expr.Datum.GetRow()) 851 } 852 853 func (b *executorBuilder) patternInToPBExpr(client kv.Client, expr *ast.PatternInExpr, tn *ast.TableName) *tipb.Expr { 854 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_In)) { 855 return nil 856 } 857 pbExpr := b.exprToPBExpr(client, expr.Expr, tn) 858 if pbExpr == nil { 859 return nil 860 } 861 var listExpr *tipb.Expr 862 if expr.Sel != nil { 863 listExpr = b.exprToPBExpr(client, expr.Sel, tn) 864 } else { 865 listExpr = b.exprListToPBExpr(client, expr.List, tn) 866 } 867 if listExpr == nil { 868 return nil 869 } 870 inExpr := &tipb.Expr{Tp: tipb.ExprType_In.Enum(), Children: []*tipb.Expr{pbExpr, listExpr}} 871 if !expr.Not { 872 return inExpr 873 } 874 return &tipb.Expr{Tp: tipb.ExprType_Not.Enum(), Children: []*tipb.Expr{inExpr}} 875 } 876 877 func (b *executorBuilder) exprListToPBExpr(client kv.Client, list []ast.ExprNode, tn *ast.TableName) *tipb.Expr { 878 if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_ValueList)) { 879 return nil 880 } 881 // Only list of *ast.ValueExpr can be push down. 882 datums := make([]types.Datum, 0, len(list)) 883 for _, v := range list { 884 x, ok := v.(*ast.ValueExpr) 885 if !ok { 886 return nil 887 } 888 if b.datumToPBExpr(client, x.Datum) == nil { 889 return nil 890 } 891 datums = append(datums, x.Datum) 892 } 893 return b.datumsToValueList(datums) 894 } 895 896 func (b *executorBuilder) datumsToValueList(datums []types.Datum) *tipb.Expr { 897 // Don't push value list that has different datum kind. 898 prevKind := types.KindNull 899 for _, d := range datums { 900 if prevKind == types.KindNull { 901 prevKind = d.Kind() 902 } 903 if d.Kind() != types.KindNull && d.Kind() != prevKind { 904 return nil 905 } 906 } 907 err := types.SortDatums(datums) 908 if err != nil { 909 b.err = errors.Trace(err) 910 return nil 911 } 912 val, err := codec.EncodeValue(nil, datums...) 913 if err != nil { 914 b.err = errors.Trace(err) 915 return nil 916 } 917 return &tipb.Expr{Tp: tipb.ExprType_ValueList.Enum(), Val: val} 918 }