(ctx context.Context, session *Session)
| 611 | } |
| 612 | |
| 613 | func (s *ExplainAnalyzeStatement) Execute(ctx context.Context, session *Session) (*Result, error) { |
| 614 | stmt := spanner.NewStatement(s.Query) |
| 615 | |
| 616 | iter, roTxn := session.RunQueryWithStats(ctx, stmt) |
| 617 | |
| 618 | // consume iter |
| 619 | err := iter.Do(func(*spanner.Row) error { |
| 620 | return nil |
| 621 | }) |
| 622 | if err != nil { |
| 623 | return nil, err |
| 624 | } |
| 625 | |
| 626 | queryStats := parseQueryStats(iter.QueryStats) |
| 627 | rowsReturned, err := strconv.Atoi(queryStats.RowsReturned) |
| 628 | if err != nil { |
| 629 | return nil, fmt.Errorf("rowsReturned is invalid: %v", err) |
| 630 | } |
| 631 | |
| 632 | // Cloud Spanner Emulator doesn't set query plan nodes to the result. |
| 633 | // See: https://github.com/GoogleCloudPlatform/cloud-spanner-emulator/blob/77188b228e7757cd56ecffb5bc3ee85dce5d6ae1/frontend/handlers/queries.cc#L224-L230 |
| 634 | if iter.QueryPlan == nil { |
| 635 | return nil, errors.New("EXPLAIN ANALYZE statement is not supported for Cloud Spanner Emulator.") |
| 636 | } |
| 637 | |
| 638 | rows, predicates, err := processPlanWithStats(iter.QueryPlan) |
| 639 | if err != nil { |
| 640 | return nil, err |
| 641 | } |
| 642 | |
| 643 | // ReadOnlyTransaction.Timestamp() is invalid until read. |
| 644 | var timestamp time.Time |
| 645 | if roTxn != nil { |
| 646 | timestamp, _ = roTxn.Timestamp() |
| 647 | } |
| 648 | |
| 649 | result := &Result{ |
| 650 | ColumnNames: explainAnalyzeColumnNames, |
| 651 | ForceVerbose: true, |
| 652 | AffectedRows: rowsReturned, |
| 653 | Stats: queryStats, |
| 654 | Timestamp: timestamp, |
| 655 | Rows: rows, |
| 656 | Predicates: predicates, |
| 657 | } |
| 658 | return result, nil |
| 659 | } |
| 660 | |
| 661 | func processPlanWithStats(plan *pb.QueryPlan) (rows []Row, predicates []string, err error) { |
| 662 | return processPlanImpl(plan, true) |
nothing calls this directly
no test coverage detected