// The current transaction might have been committed/rolled back when this returns. func (e *Executor) execStmt( stmt parser.Statement, planMaker *planner, autoCommit bool, ) (Result, error) { var result Result plan, err := planMaker.makePlan(stmt, autoCommit) if err != nil { return result, err } defer plan.Close() distSQLMode := testDistSQL if planMaker.session.DistSQLMode != distSQLDisabled { distSQLMode = planMaker.session.DistSQLMode } if distSQLMode != distSQLDisabled { if err := hackPlanToUseDistSQL(plan, distSQLMode); err != nil { return result, err } } if err := plan.Start(); err != nil { return result, err } result.PGTag = stmt.StatementTag() result.Type = stmt.StatementType() switch result.Type { case parser.RowsAffected: count, err := countRowsAffected(plan) if err != nil { return result, err } result.RowsAffected += count case parser.Rows: result.Columns = plan.Columns() for _, c := range result.Columns { if err := checkResultType(c.Typ); err != nil { return result, err } } result.Rows = NewRowContainer(planMaker.session.makeBoundAccount(), result.Columns, 0) next, err := plan.Next() for ; next; next, err = plan.Next() { // The plan.Values DTuple needs to be copied on each iteration. values := plan.Values() for _, val := range values { if err := checkResultType(val.ResolvedType()); err != nil { return result, err } } if _, err := result.Rows.AddRow(values); err != nil { return result, err } } if err != nil { return result, err } } return result, nil }
// The current transaction might have been committed/rolled back when this returns. func (e *Executor) execStmt( stmt parser.Statement, planMaker *planner, autoCommit bool, ) (Result, error) { var result Result plan, err := planMaker.makePlan(stmt, autoCommit) if err != nil { return result, err } defer plan.Close() distSQLMode := testDistSQL if planMaker.session.DistSQLMode != distSQLDisabled { distSQLMode = planMaker.session.DistSQLMode } if distSQLMode != distSQLDisabled { if err := hackPlanToUseDistSQL(plan, distSQLMode); err != nil { return result, err } } if err := plan.Start(); err != nil { return result, err } result.PGTag = stmt.StatementTag() result.Type = stmt.StatementType() switch result.Type { case parser.RowsAffected: count, err := countRowsAffected(plan) if err != nil { return result, err } result.RowsAffected += count case parser.Rows: result.Columns = plan.Columns() for _, c := range result.Columns { if err := checkResultType(c.Typ); err != nil { return result, err } } result.Rows = planMaker.NewRowContainer( planMaker.session.makeBoundAccount(), result.Columns, 0) // valuesAlloc is used to allocate the backing storage for the // result row slices in chunks. var valuesAlloc []parser.Datum const maxChunkSize = 64 // Arbitrary, could use tuning. chunkSize := 4 // Arbitrary as well. next, err := plan.Next() for ; next; next, err = plan.Next() { // The plan.Values DTuple needs to be copied on each iteration. values := plan.Values() n := len(values) if len(valuesAlloc) < n { valuesAlloc = make(parser.DTuple, len(result.Columns)*chunkSize) if chunkSize < maxChunkSize { chunkSize *= 2 } } row := valuesAlloc[:0:n] valuesAlloc = valuesAlloc[n:] for _, val := range values { if err := checkResultType(val.ResolvedType()); err != nil { return result, err } row = append(row, val) } if err := result.Rows.AddRow(row); err != nil { return result, err } } if err != nil { return result, err } } return result, nil }