diff --git a/engine.go b/engine.go index 9a11b5067d..97eb28772a 100644 --- a/engine.go +++ b/engine.go @@ -209,7 +209,7 @@ func (e *Engine) AnalyzeQuery( ctx *sql.Context, query string, ) (sql.Node, error) { - binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.Parser) + binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.EventScheduler, e.Parser) parsed, _, _, qFlags, err := binder.Parse(query, nil, false) if err != nil { return nil, err @@ -237,7 +237,7 @@ func (e *Engine) PrepareParsedQuery( statementKey, query string, stmt sqlparser.Statement, ) (sql.Node, error) { - binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.Parser) + binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.EventScheduler, e.Parser) node, _, err := binder.BindOnly(stmt, query, nil) if err != nil { @@ -517,7 +517,7 @@ func (e *Engine) BoundQueryPlan(ctx *sql.Context, query string, parsed sqlparser query = sql.RemoveSpaceAndDelimiter(query, ';') - binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.Parser) + binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.EventScheduler, e.Parser) binder.SetBindings(bindings) // Begin a transaction if necessary (no-op if one is in flight) @@ -571,7 +571,7 @@ func (e *Engine) preparedStatement(ctx *sql.Context, query string, parsed sqlpar preparedAst, preparedDataFound = e.PreparedDataCache.GetCachedStmt(ctx.Session.ID(), query) } - binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.Parser) + binder := planbuilder.New(ctx, e.Analyzer.Catalog, e.EventScheduler, e.Parser) if preparedDataFound { parsed = preparedAst binder.SetBindings(bindings) @@ -804,6 +804,10 @@ func (e *Engine) EngineAnalyzer() *analyzer.Analyzer { return e.Analyzer } +func (e *Engine) EngineEventScheduler() sql.EventScheduler { + return e.EventScheduler +} + // InitializeEventScheduler initializes the EventScheduler for the engine with the given sql.Context // getter function, |ctxGetterFunc, the EventScheduler |status|, and the |period| for the event scheduler // to check for events to execute. If |period| is less than 1, then it is ignored and the default period @@ -814,8 +818,6 @@ func (e *Engine) InitializeEventScheduler(ctxGetterFunc func() (*sql.Context, fu if err != nil { return err } - - e.Analyzer.EventScheduler = e.EventScheduler return nil } diff --git a/enginetest/engine_only_test.go b/enginetest/engine_only_test.go index f8b709d9ad..5727e5677c 100644 --- a/enginetest/engine_only_test.go +++ b/enginetest/engine_only_test.go @@ -442,7 +442,7 @@ func TestAnalyzer_Exp(t *testing.T) { require.NoError(t, err) ctx := enginetest.NewContext(harness) - b := planbuilder.New(ctx, e.EngineAnalyzer().Catalog, sql.NewMysqlParser()) + b := planbuilder.New(ctx, e.EngineAnalyzer().Catalog, e.EngineEventScheduler(), nil) parsed, _, _, _, err := b.Parse(tt.query, nil, false) require.NoError(t, err) diff --git a/enginetest/enginetests.go b/enginetest/enginetests.go index 43ee224bc7..9c842e9918 100644 --- a/enginetest/enginetests.go +++ b/enginetest/enginetests.go @@ -583,7 +583,6 @@ func TestQueryPlan(t *testing.T, harness Harness, e QueryEngine, tt queries.Quer func TestQueryPlanWithName(t *testing.T, name string, harness Harness, e QueryEngine, query, expectedPlan string, options sql.DescribeOptions) { t.Run(name, func(t *testing.T) { ctx := NewContext(harness) - parsed, qFlags, err := planbuilder.Parse(ctx, e.EngineAnalyzer().Catalog, query) require.NoError(t, err) diff --git a/enginetest/evaluation.go b/enginetest/evaluation.go index 8e0994079a..ef6b7d8d25 100644 --- a/enginetest/evaluation.go +++ b/enginetest/evaluation.go @@ -526,7 +526,7 @@ func injectBindVarsAndPrepare( } } - b := planbuilder.New(ctx, e.EngineAnalyzer().Catalog, sql.NewMysqlParser()) + b := planbuilder.New(ctx, e.EngineAnalyzer().Catalog, e.EngineEventScheduler(), nil) b.SetParserOptions(sql.LoadSqlMode(ctx).ParserOptions()) resPlan, _, err := b.BindOnly(parsed, q, nil) if err != nil { diff --git a/enginetest/plangen/cmd/plangen/main.go b/enginetest/plangen/cmd/plangen/main.go index 79c18dafb3..66534683b2 100644 --- a/enginetest/plangen/cmd/plangen/main.go +++ b/enginetest/plangen/cmd/plangen/main.go @@ -165,7 +165,7 @@ func generatePlansForSuite(spec PlanSpec, w *bytes.Buffer) error { if !tt.Skip { ctx := enginetest.NewContext(harness) - binder := planbuilder.New(ctx, engine.EngineAnalyzer().Catalog, sql.NewMysqlParser()) + binder := planbuilder.New(ctx, engine.EngineAnalyzer().Catalog, engine.EngineEventScheduler(), nil) parsed, _, _, qFlags, err := binder.Parse(tt.Query, nil, false) if err != nil { exit(fmt.Errorf("%w\nfailed to parse query: %s", err, tt.Query)) diff --git a/enginetest/query_engine.go b/enginetest/query_engine.go index a04d6254c8..207a95e2cc 100755 --- a/enginetest/query_engine.go +++ b/enginetest/query_engine.go @@ -28,6 +28,7 @@ type QueryEngine interface { Query(ctx *sql.Context, query string) (sql.Schema, sql.RowIter, *sql.QueryFlags, error) // TODO: get rid of this, should not be exposed to engine tests EngineAnalyzer() *analyzer.Analyzer + EngineEventScheduler() sql.EventScheduler // TODO: get rid of this, should not be exposed to engine tests EnginePreparedDataCache() *sqle.PreparedDataCache QueryWithBindings(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]sqlparser.Expr, qFlags *sql.QueryFlags) (sql.Schema, sql.RowIter, *sql.QueryFlags, error) diff --git a/enginetest/server_engine.go b/enginetest/server_engine.go index da7f22e03a..e77fdb02b0 100644 --- a/enginetest/server_engine.go +++ b/enginetest/server_engine.go @@ -150,6 +150,10 @@ func (s *ServerQueryEngine) EngineAnalyzer() *analyzer.Analyzer { return s.engine.Analyzer } +func (s *ServerQueryEngine) EngineEventScheduler() sql.EventScheduler { + return s.engine.EventScheduler +} + func (s *ServerQueryEngine) EnginePreparedDataCache() *sqle.PreparedDataCache { return s.engine.PreparedDataCache } @@ -632,7 +636,7 @@ func convertGoSqlType(columnType *gosql.ColumnType) (sql.Type, error) { // It cannot sort user-defined binding variables (e.g. :var, :foo) func prepareBindingArgs(ctx *sql.Context, bindings map[string]sqlparser.Expr) ([]any, error) { // NOTE: using binder with nil catalog and parser since we're only using it to convert SQLVal. - binder := planbuilder.New(ctx, nil, nil) + binder := planbuilder.New(ctx, nil, nil, nil) numBindVars := len(bindings) args := make([]any, numBindVars) for i := 0; i < numBindVars; i++ { diff --git a/eventscheduler/event_scheduler.go b/eventscheduler/event_scheduler.go index da1e0b082f..b3d95b3897 100644 --- a/eventscheduler/event_scheduler.go +++ b/eventscheduler/event_scheduler.go @@ -91,6 +91,9 @@ func InitEventScheduler( // Close closes the EventScheduler. func (es *EventScheduler) Close() { + if es == nil { + return + } es.status = SchedulerOff es.executor.shutdown() } @@ -99,6 +102,9 @@ func (es *EventScheduler) Close() { // This function requires valid analyzer and sql context to evaluate all events in all databases // to load enabled events to the EventScheduler. func (es *EventScheduler) TurnOnEventScheduler(a *analyzer.Analyzer) error { + if es == nil { + return nil + } if es.status == SchedulerDisabled { return ErrEventSchedulerDisabled } else if es.status == SchedulerOn { @@ -120,6 +126,9 @@ func (es *EventScheduler) TurnOnEventScheduler(a *analyzer.Analyzer) error { // TurnOffEventScheduler is called when user sets --event-scheduler system variable to OFF or 0. func (es *EventScheduler) TurnOffEventScheduler() error { + if es == nil { + return nil + } if es.status == SchedulerDisabled { return ErrEventSchedulerDisabled } else if es.status == SchedulerOff { @@ -135,6 +144,9 @@ func (es *EventScheduler) TurnOffEventScheduler() error { // loadEventsAndStartEventExecutor evaluates all events in all databases and evaluates the enabled events // with valid schedule to load into the eventExecutor. Then, it starts the eventExecutor. func (es *EventScheduler) loadEventsAndStartEventExecutor(ctx *sql.Context, a *analyzer.Analyzer) error { + if es == nil { + return nil + } es.executor.catalog = a.Catalog es.executor.loadAllEvents(ctx) go es.executor.start() @@ -144,6 +156,9 @@ func (es *EventScheduler) loadEventsAndStartEventExecutor(ctx *sql.Context, a *a // AddEvent implements sql.EventScheduler interface. // This function is called when there is an event created at runtime. func (es *EventScheduler) AddEvent(ctx *sql.Context, edb sql.EventDatabase, details sql.EventDefinition) { + if es == nil { + return + } if es.status == SchedulerDisabled || es.status == SchedulerOff { return } @@ -153,6 +168,9 @@ func (es *EventScheduler) AddEvent(ctx *sql.Context, edb sql.EventDatabase, deta // UpdateEvent implements sql.EventScheduler interface. // This function is called when there is an event altered at runtime. func (es *EventScheduler) UpdateEvent(ctx *sql.Context, edb sql.EventDatabase, orgEventName string, details sql.EventDefinition) { + if es == nil { + return + } if es.status == SchedulerDisabled || es.status == SchedulerOff { return } @@ -163,6 +181,9 @@ func (es *EventScheduler) UpdateEvent(ctx *sql.Context, edb sql.EventDatabase, o // This function is called when there is an event dropped at runtime. This function // removes the given event if it exists in the enabled events list of the EventScheduler. func (es *EventScheduler) RemoveEvent(dbName, eventName string) { + if es == nil { + return + } if es.status == SchedulerDisabled || es.status == SchedulerOff { return } @@ -173,6 +194,9 @@ func (es *EventScheduler) RemoveEvent(dbName, eventName string) { // This function is called when there is a database dropped at runtime. This function // removes all events of given database that exist in the enabled events list of the EventScheduler. func (es *EventScheduler) RemoveSchemaEvents(dbName string) { + if es == nil { + return + } if es.status == SchedulerDisabled || es.status == SchedulerOff { return } diff --git a/sql/analyzer/analyzer.go b/sql/analyzer/analyzer.go index 6cf28e49b9..b7e698fdf7 100644 --- a/sql/analyzer/analyzer.go +++ b/sql/analyzer/analyzer.go @@ -286,9 +286,6 @@ type Analyzer struct { Coster memo.Coster // ExecBuilder converts a sql.Node tree into an executable iterator. ExecBuilder sql.NodeExecBuilder - // EventScheduler is used to communiate with the event scheduler - // for any EVENT related statements. It can be nil if EventScheduler is not defined. - EventScheduler sql.EventScheduler } // NewDefault creates a default Analyzer instance with all default Rules and configuration. diff --git a/sql/analyzer/apply_event_scheduler_notifier.go b/sql/analyzer/apply_event_scheduler_notifier.go deleted file mode 100644 index b0094209fd..0000000000 --- a/sql/analyzer/apply_event_scheduler_notifier.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2023 Dolthub, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package analyzer - -import ( - "github.com/dolthub/go-mysql-server/sql" - "github.com/dolthub/go-mysql-server/sql/plan" - "github.com/dolthub/go-mysql-server/sql/transform" -) - -// applyEventScheduler configures AddEvent, UpdateEvent and RemoveEvent nodes with the -// EventScheduler that the Analyzer holds. -func applyEventScheduler(_ *sql.Context, a *Analyzer, n sql.Node, _ *plan.Scope, _ RuleSelector, qFlags *sql.QueryFlags) (sql.Node, transform.TreeIdentity, error) { - return transform.Node(n, func(n sql.Node) (sql.Node, transform.TreeIdentity, error) { - switch nn := n.(type) { - case sql.EventSchedulerStatement: - return nn.WithEventScheduler(a.EventScheduler), transform.NewTree, nil - default: - return n, transform.SameTree, nil - } - }) -} diff --git a/sql/analyzer/optimization_rules_test.go b/sql/analyzer/optimization_rules_test.go index f36ee26fb7..dc256f330e 100644 --- a/sql/analyzer/optimization_rules_test.go +++ b/sql/analyzer/optimization_rules_test.go @@ -218,7 +218,7 @@ func TestPushNotFilters(t *testing.T) { ctx := sql.NewContext(context.Background(), sql.WithSession(sess)) ctx.SetCurrentDatabase("mydb") - b := planbuilder.New(ctx, cat, sql.NewMysqlParser()) + b := planbuilder.New(ctx, cat, nil, nil) for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { diff --git a/sql/analyzer/rule_ids.go b/sql/analyzer/rule_ids.go index e22ce39f2b..7ff2e8a848 100644 --- a/sql/analyzer/rule_ids.go +++ b/sql/analyzer/rule_ids.go @@ -26,7 +26,6 @@ const ( validateReadOnlyTransactionId // validateReadOnlyTransaction validateDatabaseSetId // validateDatabaseSet validatePrivilegesId // validatePrivileges - applyEventSchedulerId // applyEventScheduler // default flattenTableAliasesId // flattenTableAliases diff --git a/sql/analyzer/ruleid_string.go b/sql/analyzer/ruleid_string.go index 267ed23631..d334ecce2d 100755 --- a/sql/analyzer/ruleid_string.go +++ b/sql/analyzer/ruleid_string.go @@ -28,62 +28,61 @@ func _() { _ = x[validateReadOnlyTransactionId-17] _ = x[validateDatabaseSetId-18] _ = x[validatePrivilegesId-19] - _ = x[applyEventSchedulerId-20] - _ = x[flattenTableAliasesId-21] - _ = x[pushdownSubqueryAliasFiltersId-22] - _ = x[validateCheckConstraintId-23] - _ = x[replaceCountStarId-24] - _ = x[replaceCrossJoinsId-25] - _ = x[moveJoinCondsToFilterId-26] - _ = x[simplifyFiltersId-27] - _ = x[pushNotFiltersId-28] - _ = x[hoistOutOfScopeFiltersId-29] - _ = x[unnestInSubqueriesId-30] - _ = x[unnestExistsSubqueriesId-31] - _ = x[finalizeSubqueriesId-32] - _ = x[finalizeUnionsId-33] - _ = x[loadTriggersId-34] - _ = x[processTruncateId-35] - _ = x[resolveAlterColumnId-36] - _ = x[stripTableNameInDefaultsId-37] - _ = x[optimizeJoinsId-38] - _ = x[pushFiltersId-39] - _ = x[applyIndexesFromOuterScopeId-40] - _ = x[pruneTablesId-41] - _ = x[assignExecIndexesId-42] - _ = x[inlineSubqueryAliasRefsId-43] - _ = x[eraseProjectionId-44] - _ = x[flattenDistinctId-45] - _ = x[replaceAggId-46] - _ = x[replaceIdxSortId-47] - _ = x[insertTopNId-48] - _ = x[replaceIdxOrderByDistanceId-49] - _ = x[applyHashInId-50] - _ = x[resolveInsertRowsId-51] - _ = x[applyTriggersId-52] - _ = x[applyProceduresId-53] - _ = x[assignRoutinesId-54] - _ = x[modifyUpdateExprsForJoinId-55] - _ = x[applyForeignKeysId-56] - _ = x[validateResolvedId-57] - _ = x[validateOrderById-58] - _ = x[validateGroupById-59] - _ = x[validateSchemaSourceId-60] - _ = x[validateIndexCreationId-61] - _ = x[ValidateOperandsId-62] - _ = x[validateIntervalUsageId-63] - _ = x[validateSubqueryColumnsId-64] - _ = x[validateUnionSchemasMatchId-65] - _ = x[validateAggregationsId-66] - _ = x[validateDeleteFromId-67] - _ = x[cacheSubqueryAliasesInJoinsId-68] - _ = x[BacktickDefaulColumnValueNamesId-69] - _ = x[TrackProcessId-70] + _ = x[flattenTableAliasesId-20] + _ = x[pushdownSubqueryAliasFiltersId-21] + _ = x[validateCheckConstraintId-22] + _ = x[replaceCountStarId-23] + _ = x[replaceCrossJoinsId-24] + _ = x[moveJoinCondsToFilterId-25] + _ = x[simplifyFiltersId-26] + _ = x[pushNotFiltersId-27] + _ = x[hoistOutOfScopeFiltersId-28] + _ = x[unnestInSubqueriesId-29] + _ = x[unnestExistsSubqueriesId-30] + _ = x[finalizeSubqueriesId-31] + _ = x[finalizeUnionsId-32] + _ = x[loadTriggersId-33] + _ = x[processTruncateId-34] + _ = x[resolveAlterColumnId-35] + _ = x[stripTableNameInDefaultsId-36] + _ = x[optimizeJoinsId-37] + _ = x[pushFiltersId-38] + _ = x[applyIndexesFromOuterScopeId-39] + _ = x[pruneTablesId-40] + _ = x[assignExecIndexesId-41] + _ = x[inlineSubqueryAliasRefsId-42] + _ = x[eraseProjectionId-43] + _ = x[flattenDistinctId-44] + _ = x[replaceAggId-45] + _ = x[replaceIdxSortId-46] + _ = x[insertTopNId-47] + _ = x[replaceIdxOrderByDistanceId-48] + _ = x[applyHashInId-49] + _ = x[resolveInsertRowsId-50] + _ = x[applyTriggersId-51] + _ = x[applyProceduresId-52] + _ = x[assignRoutinesId-53] + _ = x[modifyUpdateExprsForJoinId-54] + _ = x[applyForeignKeysId-55] + _ = x[validateResolvedId-56] + _ = x[validateOrderById-57] + _ = x[validateGroupById-58] + _ = x[validateSchemaSourceId-59] + _ = x[validateIndexCreationId-60] + _ = x[ValidateOperandsId-61] + _ = x[validateIntervalUsageId-62] + _ = x[validateSubqueryColumnsId-63] + _ = x[validateUnionSchemasMatchId-64] + _ = x[validateAggregationsId-65] + _ = x[validateDeleteFromId-66] + _ = x[cacheSubqueryAliasesInJoinsId-67] + _ = x[BacktickDefaulColumnValueNamesId-68] + _ = x[TrackProcessId-69] } -const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedurevalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesapplyEventSchedulerflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" +const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedurevalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" -var _RuleId_index = [...]uint16{0, 23, 45, 68, 87, 105, 120, 140, 158, 179, 201, 220, 237, 250, 272, 293, 316, 340, 367, 386, 404, 423, 442, 470, 494, 510, 527, 553, 568, 582, 604, 622, 644, 662, 676, 688, 703, 721, 754, 767, 778, 804, 815, 832, 855, 870, 885, 895, 909, 924, 949, 960, 977, 990, 1005, 1019, 1043, 1059, 1075, 1090, 1105, 1125, 1146, 1162, 1183, 1206, 1231, 1251, 1269, 1296, 1327, 1339} +var _RuleId_index = [...]uint16{0, 23, 45, 68, 87, 105, 120, 140, 158, 179, 201, 220, 237, 250, 272, 293, 316, 340, 367, 386, 404, 423, 451, 475, 491, 508, 534, 549, 563, 585, 603, 625, 643, 657, 669, 684, 702, 735, 748, 759, 785, 796, 813, 836, 851, 866, 876, 890, 905, 930, 941, 958, 971, 986, 1000, 1024, 1040, 1056, 1071, 1086, 1106, 1127, 1143, 1164, 1187, 1212, 1232, 1250, 1277, 1308, 1320} func (i RuleId) String() string { if i < 0 || i >= RuleId(len(_RuleId_index)-1) { diff --git a/sql/analyzer/rules.go b/sql/analyzer/rules.go index f63f6f57db..9970e56279 100644 --- a/sql/analyzer/rules.go +++ b/sql/analyzer/rules.go @@ -33,7 +33,6 @@ func init() { var OnceBeforeDefault = []Rule{ {applyDefaultSelectLimitId, applyDefaultSelectLimit}, {replaceCountStarId, replaceCountStar}, - {applyEventSchedulerId, applyEventScheduler}, {validateOffsetAndLimitId, validateOffsetAndLimit}, {validateCreateTableId, validateCreateTable}, {validateAlterTableId, validateAlterTable}, diff --git a/sql/analyzer/stored_procedures.go b/sql/analyzer/stored_procedures.go index 35a555a522..188d2125d8 100644 --- a/sql/analyzer/stored_procedures.go +++ b/sql/analyzer/stored_procedures.go @@ -54,7 +54,7 @@ func loadStoredProcedures(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan for _, procedure := range procedures { var procToRegister *plan.Procedure var parsedProcedure sql.Node - b := planbuilder.New(ctx, a.Catalog, sql.NewMysqlParser()) + b := planbuilder.New(ctx, a.Catalog, nil, nil) b.SetParserOptions(sql.NewSqlModeFromString(procedure.SqlMode).ParserOptions()) parsedProcedure, _, _, _, err = b.Parse(procedure.CreateStatement, nil, false) if err != nil { @@ -289,7 +289,7 @@ func applyProcedures(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scop return nil, transform.SameTree, err } var parsedProcedure sql.Node - b := planbuilder.New(ctx, a.Catalog, sql.NewMysqlParser()) + b := planbuilder.New(ctx, a.Catalog, nil, nil) b.SetParserOptions(sql.NewSqlModeFromString(procedure.SqlMode).ParserOptions()) if call.AsOf() != nil { asOf, err := call.AsOf().Eval(ctx, nil) diff --git a/sql/analyzer/triggers.go b/sql/analyzer/triggers.go index 4f9edadd6a..e94f056b74 100644 --- a/sql/analyzer/triggers.go +++ b/sql/analyzer/triggers.go @@ -193,7 +193,7 @@ func applyTriggers(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, return nil, transform.SameTree, err } - b := planbuilder.New(ctx, a.Catalog, sql.NewMysqlParser()) + b := planbuilder.New(ctx, a.Catalog, nil, nil) prevActive := b.TriggerCtx().Active b.TriggerCtx().Active = true defer func() { diff --git a/sql/events.go b/sql/events.go index f682e6fa88..496b39ec1d 100644 --- a/sql/events.go +++ b/sql/events.go @@ -28,15 +28,6 @@ import ( const EventDateSpaceTimeFormat = "2006-01-02 15:04:05" -// EventSchedulerStatement represents a SQL statement that requires a EventScheduler -// (e.g. CREATE / ALTER / DROP EVENT and DROP DATABASE). -type EventSchedulerStatement interface { - Node - // WithEventScheduler returns a new instance of this EventSchedulerStatement, - // with the event scheduler notifier configured. - WithEventScheduler(controller EventScheduler) Node -} - // EventScheduler is an interface used for notifying the EventSchedulerStatus // for querying any events related statements. This allows plan Nodes to communicate // to the EventSchedulerStatus. diff --git a/sql/information_schema/routines_table.go b/sql/information_schema/routines_table.go index 811eb5bd84..1273367863 100644 --- a/sql/information_schema/routines_table.go +++ b/sql/information_schema/routines_table.go @@ -138,6 +138,7 @@ func routinesRowIter(ctx *Context, c Catalog, p map[string][]*plan.Procedure) (R if privSet == nil { privSet = mysql_db.NewPrivilegeSet() } + for dbName, procedures := range p { if !hasRoutinePrivsOnDB(privSet, dbName) { continue diff --git a/sql/plan/alter_event.go b/sql/plan/alter_event.go index 0b795bf26f..8c919eeb00 100644 --- a/sql/plan/alter_event.go +++ b/sql/plan/alter_event.go @@ -31,7 +31,6 @@ import ( var _ sql.Node = (*AlterEvent)(nil) var _ sql.Expressioner = (*AlterEvent)(nil) var _ sql.Databaser = (*AlterEvent)(nil) -var _ sql.EventSchedulerStatement = (*AlterEvent)(nil) type AlterEvent struct { ddlNode @@ -71,6 +70,7 @@ type AlterEvent struct { // NewAlterEvent returns a *AlterEvent node. func NewAlterEvent( db sql.Database, + es sql.EventScheduler, name, definer string, alterSchedule bool, at, starts, ends *OnScheduleTimestamp, @@ -89,6 +89,7 @@ func NewAlterEvent( ) *AlterEvent { return &AlterEvent{ ddlNode: ddlNode{db}, + scheduler: es, EventName: name, Definer: definer, AlterOnSchedule: alterSchedule, @@ -403,13 +404,6 @@ func (a *AlterEvent) WithExpressions(e ...sql.Expression) (sql.Node, error) { return &na, nil } -// WithEventScheduler is used to notify EventSchedulerStatus to update the events list for ALTER EVENT. -func (a *AlterEvent) WithEventScheduler(scheduler sql.EventScheduler) sql.Node { - na := *a - na.scheduler = scheduler - return &na -} - // alterEventIter is the row iterator for *CreateEvent. type alterEventIter struct { once sync.Once diff --git a/sql/plan/dbddl.go b/sql/plan/dbddl.go index 6a2e192460..1e018c81ab 100644 --- a/sql/plan/dbddl.go +++ b/sql/plan/dbddl.go @@ -122,12 +122,11 @@ type DropDB struct { IfExists bool // EventScheduler is used to notify EventSchedulerStatus of database deletion, // so the events of this database in the scheduler will be removed. - EventScheduler sql.EventScheduler + Scheduler sql.EventScheduler } var _ sql.Node = (*DropDB)(nil) var _ sql.CollationCoercible = (*DropDB)(nil) -var _ sql.EventSchedulerStatement = (*DropDB)(nil) func (d *DropDB) Resolved() bool { return true @@ -157,13 +156,6 @@ func (d *DropDB) WithChildren(children ...sql.Node) (sql.Node, error) { return NillaryWithChildren(d, children...) } -// WithEventScheduler is used to drop all events from EventSchedulerStatus for DROP DATABASE. -func (d *DropDB) WithEventScheduler(scheduler sql.EventScheduler) sql.Node { - na := *d - na.EventScheduler = scheduler - return &na -} - // CheckPrivileges implements the interface sql.Node. func (d *DropDB) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, sql.PrivilegeType_Drop)) diff --git a/sql/plan/ddl_event.go b/sql/plan/ddl_event.go index 0a6ba3c64b..c9f8cbb216 100644 --- a/sql/plan/ddl_event.go +++ b/sql/plan/ddl_event.go @@ -32,7 +32,6 @@ import ( var _ sql.Node = (*CreateEvent)(nil) var _ sql.Expressioner = (*CreateEvent)(nil) var _ sql.Databaser = (*CreateEvent)(nil) -var _ sql.EventSchedulerStatement = (*CreateEvent)(nil) type CreateEvent struct { ddlNode @@ -48,13 +47,14 @@ type CreateEvent struct { DefinitionString string DefinitionNode sql.Node IfNotExists bool - // eventScheduler is used to notify EventSchedulerStatus of the event creation - eventScheduler sql.EventScheduler + // scheduler is used to notify EventSchedulerStatus of the event creation + scheduler sql.EventScheduler } // NewCreateEvent returns a *CreateEvent node. func NewCreateEvent( db sql.Database, + es sql.EventScheduler, name, definer string, at, starts, ends *OnScheduleTimestamp, every *expression.Interval, @@ -66,6 +66,7 @@ func NewCreateEvent( ) *CreateEvent { return &CreateEvent{ ddlNode: ddlNode{db}, + scheduler: es, EventName: name, Definer: definer, At: at, @@ -252,17 +253,10 @@ func (c *CreateEvent) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) event: eventDefinition, eventDb: eventDb, ifNotExists: c.IfNotExists, - eventScheduler: c.eventScheduler, + eventScheduler: c.scheduler, }, nil } -// WithEventScheduler is used to notify EventSchedulerStatus to update the events list for CREATE EVENT. -func (c *CreateEvent) WithEventScheduler(scheduler sql.EventScheduler) sql.Node { - nc := *c - nc.eventScheduler = scheduler - return &nc -} - // GetEventDefinition returns an EventDefinition object with all of its fields populated from the details // of this CREATE EVENT statement. func (c *CreateEvent) GetEventDefinition(ctx *sql.Context, eventCreationTime, lastAltered, lastExecuted time.Time, tz string) (sql.EventDefinition, error) { @@ -581,20 +575,20 @@ func (ost *OnScheduleTimestamp) EvalTime(ctx *sql.Context, tz string) (time.Time var _ sql.Node = (*DropEvent)(nil) var _ sql.Databaser = (*DropEvent)(nil) -var _ sql.EventSchedulerStatement = (*DropEvent)(nil) type DropEvent struct { ddlNode EventName string IfExists bool // eventScheduler is used to notify EventSchedulerStatus of the event deletion - eventScheduler sql.EventScheduler + scheduler sql.EventScheduler } // NewDropEvent creates a new *DropEvent node. -func NewDropEvent(db sql.Database, eventName string, ifExists bool) *DropEvent { +func NewDropEvent(db sql.Database, es sql.EventScheduler, eventName string, ifExists bool) *DropEvent { return &DropEvent{ ddlNode: ddlNode{db}, + scheduler: es, EventName: strings.ToLower(eventName), IfExists: ifExists, } @@ -630,8 +624,8 @@ func (d *DropEvent) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) } // make sure to notify the EventSchedulerStatus before dropping the event in the database - if d.eventScheduler != nil { - d.eventScheduler.RemoveEvent(eventDb.Name(), d.EventName) + if d.scheduler != nil { + d.scheduler.RemoveEvent(eventDb.Name(), d.EventName) } err := eventDb.DropEvent(ctx, d.EventName) @@ -667,10 +661,3 @@ func (d *DropEvent) WithDatabase(database sql.Database) (sql.Node, error) { nde.Db = database return &nde, nil } - -// WithEventScheduler is used to notify EventSchedulerStatus to update the events list for DROP EVENT. -func (d *DropEvent) WithEventScheduler(scheduler sql.EventScheduler) sql.Node { - nd := *d - nd.eventScheduler = scheduler - return &nd -} diff --git a/sql/planbuilder/builder.go b/sql/planbuilder/builder.go index fc65349bfb..6bf6abd8de 100644 --- a/sql/planbuilder/builder.go +++ b/sql/planbuilder/builder.go @@ -47,8 +47,11 @@ type Builder struct { bindCtx *BindvarContext insertActive bool nesting int - parser sql.Parser - qFlags *sql.QueryFlags + // EventScheduler is used to communicate with the event scheduler + // for any EVENT related statements. It can be nil if EventScheduler is not defined. + scheduler sql.EventScheduler + parser sql.Parser + qFlags *sql.QueryFlags } // BindvarContext holds bind variable replacement literals. @@ -103,14 +106,16 @@ type ProcContext struct { DbName string } -// New takes ctx, catalog and parser. If the parser is nil, then default parser is mysql parser. -func New(ctx *sql.Context, cat sql.Catalog, p sql.Parser) *Builder { - sqlMode := sql.LoadSqlMode(ctx) - +// New takes ctx, catalog, event scheduler, and parser. If the parser is nil, then default parser is mysql parser. +func New(ctx *sql.Context, cat sql.Catalog, es sql.EventScheduler, p sql.Parser) *Builder { + if p == nil { + p = sql.NewMysqlParser() + } return &Builder{ ctx: ctx, cat: cat, - parserOpts: sqlMode.ParserOptions(), + scheduler: es, + parserOpts: sql.LoadSqlMode(ctx).ParserOptions(), f: &factory{}, parser: p, qFlags: &sql.QueryFlags{}, diff --git a/sql/planbuilder/create_ddl.go b/sql/planbuilder/create_ddl.go index 7c3a35bd12..1ac934760e 100644 --- a/sql/planbuilder/create_ddl.go +++ b/sql/planbuilder/create_ddl.go @@ -279,6 +279,7 @@ func (b *Builder) buildCreateEvent(inScope *scope, subQuery string, fullQuery st outScope.node = plan.NewCreateEvent( database, + b.scheduler, eventSpec.EventName.Name.String(), definer, at, starts, ends, everyInterval, onCompletionPreserve, @@ -419,7 +420,9 @@ func (b *Builder) buildAlterEvent(inScope *scope, subQuery string, fullQuery str outScope = inScope.push() alterEvent := plan.NewAlterEvent( - database, eventName, definer, + database, + b.scheduler, + eventName, definer, alterSchedule, at, starts, ends, everyInterval, alterOnComp, newOnCompPreserve, alterEventName, newName, diff --git a/sql/planbuilder/ddl.go b/sql/planbuilder/ddl.go index dd4de53cf1..714a8de842 100644 --- a/sql/planbuilder/ddl.go +++ b/sql/planbuilder/ddl.go @@ -156,7 +156,7 @@ func (b *Builder) buildDDL(inScope *scope, subQuery string, fullQuery string, c dbName = b.ctx.GetCurrentDatabase() } eventName := c.EventSpec.EventName.Name.String() - outScope.node = plan.NewDropEvent(b.resolveDb(dbName), eventName, c.IfExists) + outScope.node = plan.NewDropEvent(b.resolveDb(dbName), b.scheduler, eventName, c.IfExists) return } if len(c.FromViews) != 0 { diff --git a/sql/planbuilder/parse.go b/sql/planbuilder/parse.go index 58550301c5..8ebd464af1 100644 --- a/sql/planbuilder/parse.go +++ b/sql/planbuilder/parse.go @@ -39,7 +39,7 @@ func Parse(ctx *sql.Context, cat sql.Catalog, query string) (sql.Node, *sql.Quer func ParseWithOptions(ctx *sql.Context, cat sql.Catalog, query string, options ast.ParserOptions) (sql.Node, *sql.QueryFlags, error) { // TODO: need correct parser - b := New(ctx, cat, sql.NewMysqlParser()) + b := New(ctx, cat, nil, nil) b.SetParserOptions(options) node, _, _, qFlags, err := b.Parse(query, nil, false) return node, qFlags, err diff --git a/sql/planbuilder/parse_test.go b/sql/planbuilder/parse_test.go index c0275977ec..1a43b62f72 100644 --- a/sql/planbuilder/parse_test.go +++ b/sql/planbuilder/parse_test.go @@ -2503,7 +2503,7 @@ Project ctx := sql.NewContext(context.Background(), sql.WithSession(sess)) ctx.SetCurrentDatabase("mydb") - b := New(ctx, cat, sql.NewMysqlParser()) + b := New(ctx, cat, nil, nil) for _, tt := range tests { t.Run(tt.Query, func(t *testing.T) { @@ -2861,7 +2861,7 @@ func TestPlanBuilderErr(t *testing.T) { ctx := sql.NewContext(context.Background(), sql.WithSession(sess)) ctx.SetCurrentDatabase("mydb") - b := New(ctx, cat, sql.NewMysqlParser()) + b := New(ctx, cat, nil, nil) for _, tt := range tests { t.Run(tt.Query, func(t *testing.T) { diff --git a/sql/rowexec/ddl.go b/sql/rowexec/ddl.go index a06e14fdae..9a0b591dd2 100644 --- a/sql/rowexec/ddl.go +++ b/sql/rowexec/ddl.go @@ -759,8 +759,8 @@ func (b *BaseBuilder) buildDropDB(ctx *sql.Context, n *plan.DropDB, row sql.Row) } // make sure to notify the EventSchedulerStatus before dropping the database - if n.EventScheduler != nil { - n.EventScheduler.RemoveSchemaEvents(n.DbName) + if n.Scheduler != nil { + n.Scheduler.RemoveSchemaEvents(n.DbName) } err := n.Catalog.RemoveDatabase(ctx, n.DbName)