// updateStmtCounts updates metrics for the number of times the different types of SQL // statements have been received by this node. func (e *Executor) updateStmtCounts(stmt parser.Statement) { e.QueryCount.Inc(1) switch stmt.(type) { case *parser.BeginTransaction: e.TxnBeginCount.Inc(1) case *parser.Select: e.SelectCount.Inc(1) case *parser.Update: e.UpdateCount.Inc(1) case *parser.Insert: e.InsertCount.Inc(1) case *parser.Delete: e.DeleteCount.Inc(1) case *parser.CommitTransaction: e.TxnCommitCount.Inc(1) case *parser.RollbackTransaction: e.TxnRollbackCount.Inc(1) default: if stmt.StatementType() == parser.DDL { e.DdlCount.Inc(1) } else { e.MiscCount.Inc(1) } } }
// 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 }
// newPlan constructs a planNode from a statement. This is used // recursively by the various node constructors. func (p *planner) newPlan( stmt parser.Statement, desiredTypes []parser.Type, autoCommit bool, ) (planNode, error) { tracing.AnnotateTrace() // This will set the system DB trigger for transactions containing // DDL statements that have no effect, such as // `BEGIN; INSERT INTO ...; CREATE TABLE IF NOT EXISTS ...; COMMIT;` // where the table already exists. This will generate some false // refreshes, but that's expected to be quite rare in practice. if stmt.StatementType() == parser.DDL { p.txn.SetSystemConfigTrigger() } switch n := stmt.(type) { case *parser.AlterTable: return p.AlterTable(n) case *parser.BeginTransaction: return p.BeginTransaction(n) case CopyDataBlock: return p.CopyData(n, autoCommit) case *parser.CopyFrom: return p.CopyFrom(n, autoCommit) case *parser.CreateDatabase: return p.CreateDatabase(n) case *parser.CreateIndex: return p.CreateIndex(n) case *parser.CreateTable: return p.CreateTable(n) case *parser.CreateUser: return p.CreateUser(n) case *parser.CreateView: return p.CreateView(n) case *parser.Delete: return p.Delete(n, desiredTypes, autoCommit) case *parser.DropDatabase: return p.DropDatabase(n) case *parser.DropIndex: return p.DropIndex(n) case *parser.DropTable: return p.DropTable(n) case *parser.DropView: return p.DropView(n) case *parser.Explain: return p.Explain(n, autoCommit) case *parser.Grant: return p.Grant(n) case *parser.Help: return p.Help(n) case *parser.Insert: return p.Insert(n, desiredTypes, autoCommit) case *parser.ParenSelect: return p.newPlan(n.Select, desiredTypes, autoCommit) case *parser.RenameColumn: return p.RenameColumn(n) case *parser.RenameDatabase: return p.RenameDatabase(n) case *parser.RenameIndex: return p.RenameIndex(n) case *parser.RenameTable: return p.RenameTable(n) case *parser.Revoke: return p.Revoke(n) case *parser.Select: return p.Select(n, desiredTypes, autoCommit) case *parser.SelectClause: return p.SelectClause(n, nil, nil, desiredTypes, publicColumns) case *parser.Set: return p.Set(n) case *parser.SetTimeZone: return p.SetTimeZone(n) case *parser.SetTransaction: return p.SetTransaction(n) case *parser.SetDefaultIsolation: return p.SetDefaultIsolation(n) case *parser.Show: return p.Show(n) case *parser.ShowColumns: return p.ShowColumns(n) case *parser.ShowConstraints: return p.ShowConstraints(n) case *parser.ShowCreateTable: return p.ShowCreateTable(n) case *parser.ShowCreateView: return p.ShowCreateView(n) case *parser.ShowDatabases: return p.ShowDatabases(n) case *parser.ShowGrants: return p.ShowGrants(n) case *parser.ShowIndex: return p.ShowIndex(n) case *parser.ShowTables: return p.ShowTables(n) case *parser.ShowUsers: return p.ShowUsers(n) case *parser.Split: return p.Split(n) case *parser.Truncate: return p.Truncate(n) case *parser.UnionClause: return p.UnionClause(n, desiredTypes, autoCommit) case *parser.Update: return p.Update(n, desiredTypes, autoCommit) case *parser.ValuesClause: return p.ValuesClause(n, desiredTypes) default: return nil, errors.Errorf("unknown statement type: %T", stmt) } }
// newPlan constructs a planNode from a statement. This is used // recursively by the various node constructors. func (p *planner) newPlan( stmt parser.Statement, desiredTypes []parser.Type, autoCommit bool, ) (planNode, error) { tracing.AnnotateTrace() // This will set the system DB trigger for transactions containing // DDL statements that have no effect, such as // `BEGIN; INSERT INTO ...; CREATE TABLE IF NOT EXISTS ...; COMMIT;` // where the table already exists. This will generate some false // refreshes, but that's expected to be quite rare in practice. if stmt.StatementType() == parser.DDL { p.txn.SetSystemConfigTrigger() } // TODO(dan): This iteration makes the plan dispatch no longer constant // time. We could fix that with a map of `reflect.Type` but including // reflection in such a primary codepath is unfortunate. Instead, the // upcoming IR work will provide unique numeric type tags, which will // elegantly solve this. for _, planHook := range planHooks { if fn, header, err := planHook(p.ctx(), stmt, p.execCfg); err != nil { return nil, err } else if fn != nil { return &hookFnNode{f: fn, header: header}, nil } } switch n := stmt.(type) { case *parser.AlterTable: return p.AlterTable(n) case *parser.BeginTransaction: return p.BeginTransaction(n) case CopyDataBlock: return p.CopyData(n, autoCommit) case *parser.CopyFrom: return p.CopyFrom(n, autoCommit) case *parser.CreateDatabase: return p.CreateDatabase(n) case *parser.CreateIndex: return p.CreateIndex(n) case *parser.CreateTable: return p.CreateTable(n) case *parser.CreateUser: return p.CreateUser(n) case *parser.CreateView: return p.CreateView(n) case *parser.Delete: return p.Delete(n, desiredTypes, autoCommit) case *parser.DropDatabase: return p.DropDatabase(n) case *parser.DropIndex: return p.DropIndex(n) case *parser.DropTable: return p.DropTable(n) case *parser.DropView: return p.DropView(n) case *parser.Explain: return p.Explain(n, autoCommit) case *parser.Grant: return p.Grant(n) case *parser.Help: return p.Help(n) case *parser.Insert: return p.Insert(n, desiredTypes, autoCommit) case *parser.ParenSelect: return p.newPlan(n.Select, desiredTypes, autoCommit) case *parser.RenameColumn: return p.RenameColumn(n) case *parser.RenameDatabase: return p.RenameDatabase(n) case *parser.RenameIndex: return p.RenameIndex(n) case *parser.RenameTable: return p.RenameTable(n) case *parser.Revoke: return p.Revoke(n) case *parser.Select: return p.Select(n, desiredTypes, autoCommit) case *parser.SelectClause: return p.SelectClause(n, nil, nil, desiredTypes, publicColumns) case *parser.Set: return p.Set(n) case *parser.SetTimeZone: return p.SetTimeZone(n) case *parser.SetTransaction: return p.SetTransaction(n) case *parser.SetDefaultIsolation: return p.SetDefaultIsolation(n) case *parser.Show: return p.Show(n) case *parser.ShowColumns: return p.ShowColumns(n) case *parser.ShowConstraints: return p.ShowConstraints(n) case *parser.ShowCreateTable: return p.ShowCreateTable(n) case *parser.ShowCreateView: return p.ShowCreateView(n) case *parser.ShowDatabases: return p.ShowDatabases(n) case *parser.ShowGrants: return p.ShowGrants(n) case *parser.ShowIndex: return p.ShowIndex(n) case *parser.ShowTables: return p.ShowTables(n) case *parser.ShowUsers: return p.ShowUsers(n) case *parser.Split: return p.Split(n) case *parser.Truncate: return p.Truncate(n) case *parser.UnionClause: return p.UnionClause(n, desiredTypes, autoCommit) case *parser.Update: return p.Update(n, desiredTypes, autoCommit) case *parser.ValuesClause: return p.ValuesClause(n, desiredTypes) default: return nil, errors.Errorf("unknown statement type: %T", stmt) } }