From be458c255c38028eed0537c68e13a8bb51f1ceaa Mon Sep 17 00:00:00 2001 From: Daylon Wilkins Date: Thu, 30 Jan 2025 04:17:50 -0800 Subject: [PATCH] Added the concept of an interpreter expression --- engine.go | 3 +++ enginetest/initialization.go | 1 + sql/analyzer/analyzer.go | 2 ++ sql/analyzer/interpreter.go | 47 +++++++++++++++++++++++++++++++++++ sql/analyzer/rule_ids.go | 1 + sql/analyzer/ruleid_string.go | 33 ++++++++++++------------ sql/analyzer/rules.go | 1 + 7 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 sql/analyzer/interpreter.go diff --git a/engine.go b/engine.go index 432bfc9f83..80c7685d0b 100644 --- a/engine.go +++ b/engine.go @@ -150,6 +150,8 @@ type Engine struct { Parser sql.Parser } +var _ analyzer.StatementRunner = (*Engine)(nil) + type ColumnWithRawDefault struct { SqlColumn *sql.Column Default string @@ -195,6 +197,7 @@ func New(a *analyzer.Analyzer, cfg *Config) *Engine { Parser: sql.GlobalParser, } ret.ReadOnly.Store(cfg.IsReadOnly) + a.Runner = ret return ret } diff --git a/enginetest/initialization.go b/enginetest/initialization.go index f9e1574ca2..bf1c6c11c3 100644 --- a/enginetest/initialization.go +++ b/enginetest/initialization.go @@ -91,6 +91,7 @@ func NewEngineWithProvider(_ *testing.T, harness Harness, provider sql.DatabaseP if idh, ok := harness.(IndexDriverHarness); ok { idh.InitializeIndexDriver(engine.Analyzer.Catalog.AllDatabases(NewContext(harness))) } + analyzer.Runner = engine return engine } diff --git a/sql/analyzer/analyzer.go b/sql/analyzer/analyzer.go index b7e698fdf7..5bd7df72ea 100644 --- a/sql/analyzer/analyzer.go +++ b/sql/analyzer/analyzer.go @@ -286,6 +286,8 @@ type Analyzer struct { Coster memo.Coster // ExecBuilder converts a sql.Node tree into an executable iterator. ExecBuilder sql.NodeExecBuilder + // Runner represents the engine, which is represented as a separate interface to work around circular dependencies + Runner StatementRunner } // NewDefault creates a default Analyzer instance with all default Rules and configuration. diff --git a/sql/analyzer/interpreter.go b/sql/analyzer/interpreter.go new file mode 100644 index 0000000000..80d07c620e --- /dev/null +++ b/sql/analyzer/interpreter.go @@ -0,0 +1,47 @@ +// Copyright 2022 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/vitess/go/vt/sqlparser" + + "github.com/dolthub/go-mysql-server/sql/transform" + + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/plan" +) + +// Interpreter is an interface that implements an interpreter. These are typically used for functions (which may be +// implemented as a set of operations that are interpreted during runtime). +type Interpreter interface { + SetStatementRunner(ctx *sql.Context, runner StatementRunner) sql.Expression +} + +// StatementRunner is essentially an interface that the engine will implement. We cannot directly reference the engine +// here as it will cause an import cycle, so this may be updated to suit any function changes that the engine +// experiences. +type StatementRunner interface { + QueryWithBindings(ctx *sql.Context, query string, parsed sqlparser.Statement, bindings map[string]sqlparser.Expr, qFlags *sql.QueryFlags) (sql.Schema, sql.RowIter, *sql.QueryFlags, error) +} + +// interpreter hands the engine to any interpreter expressions. +func interpreter(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, sel RuleSelector, qFlags *sql.QueryFlags) (sql.Node, transform.TreeIdentity, error) { + return transform.NodeExprs(n, func(expr sql.Expression) (sql.Expression, transform.TreeIdentity, error) { + if interp, ok := expr.(Interpreter); ok { + return interp.SetStatementRunner(ctx, a.Runner), transform.NewTree, nil + } + return expr, transform.SameTree, nil + }) +} diff --git a/sql/analyzer/rule_ids.go b/sql/analyzer/rule_ids.go index 7ff2e8a848..b473df9432 100644 --- a/sql/analyzer/rule_ids.go +++ b/sql/analyzer/rule_ids.go @@ -66,6 +66,7 @@ const ( assignRoutinesId // assignRoutines modifyUpdateExprsForJoinId // modifyUpdateExprsForJoin applyForeignKeysId // applyForeignKeys + interpreterId // interpreter // validate validateResolvedId // validateResolved diff --git a/sql/analyzer/ruleid_string.go b/sql/analyzer/ruleid_string.go index d334ecce2d..8a3fe21abc 100755 --- a/sql/analyzer/ruleid_string.go +++ b/sql/analyzer/ruleid_string.go @@ -64,25 +64,26 @@ func _() { _ = 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] + _ = x[interpreterId-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] } -const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedurevalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" +const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedurevalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysinterpretervalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" -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} +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, 1051, 1067, 1082, 1097, 1117, 1138, 1154, 1175, 1198, 1223, 1243, 1261, 1288, 1319, 1331} 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 f4b4c7e5bc..081829406f 100644 --- a/sql/analyzer/rules.go +++ b/sql/analyzer/rules.go @@ -93,6 +93,7 @@ var OnceAfterDefault = []Rule{ {assignRoutinesId, assignRoutines}, {modifyUpdateExprsForJoinId, modifyUpdateExprsForJoin}, {applyForeignKeysId, applyForeignKeys}, + {interpreterId, interpreter}, } // DefaultValidationRules to apply while analyzing nodes.