From 1a4cc3db2ffb64589f98a9d48b85bc1e98a8a77f 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 3bd50f04d0..a4e75156b3 100644 --- a/sql/analyzer/rule_ids.go +++ b/sql/analyzer/rule_ids.go @@ -65,6 +65,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 ad687ce11e..f4ce57ccce 100755 --- a/sql/analyzer/ruleid_string.go +++ b/sql/analyzer/ruleid_string.go @@ -63,25 +63,26 @@ func _() { _ = x[assignRoutinesId-52] _ = x[modifyUpdateExprsForJoinId-53] _ = x[applyForeignKeysId-54] - _ = x[validateResolvedId-55] - _ = x[validateOrderById-56] - _ = x[validateGroupById-57] - _ = x[validateSchemaSourceId-58] - _ = x[validateIndexCreationId-59] - _ = x[ValidateOperandsId-60] - _ = x[validateIntervalUsageId-61] - _ = x[validateSubqueryColumnsId-62] - _ = x[validateUnionSchemasMatchId-63] - _ = x[validateAggregationsId-64] - _ = x[validateDeleteFromId-65] - _ = x[cacheSubqueryAliasesInJoinsId-66] - _ = x[BacktickDefaulColumnValueNamesId-67] - _ = x[TrackProcessId-68] + _ = x[interpreterId-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 = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" +const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateStarExpressionsvalidateCreateTablevalidateAlterTablevalidateExprSemloadStoredProceduresvalidateDropTablesresolveDropConstraintvalidateDropConstraintresolveCreateSelectresolveSubqueriesresolveUnionsvalidateColumnDefaultsvalidateCreateTriggervalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesflattenTableAliasespushdownSubqueryAliasFiltersvalidateCheckConstraintsreplaceCountStarreplaceCrossJoinsmoveJoinConditionsToFiltersimplifyFilterspushNotFiltershoistOutOfScopeFiltersunnestInSubqueriesunnestExistsSubqueriesfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnstripTableNamesFromColumnDefaultsoptimizeJoinspushFiltersapplyIndexesFromOuterScopepruneTablesassignExecIndexesinlineSubqueryAliasRefseraseProjectionflattenDistinctreplaceAggreplaceIdxSortinsertTopNNodesreplaceIdxOrderByDistanceapplyHashInresolveInsertRowsapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyForeignKeysinterpretervalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateIntervalUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsvalidateDeleteFromcacheSubqueryAliasesInJoinsbacktickDefaultColumnValueNamestrackProcess" -var _RuleId_index = [...]uint16{0, 23, 45, 68, 87, 105, 120, 140, 158, 179, 201, 220, 237, 250, 272, 293, 317, 344, 363, 381, 400, 428, 452, 468, 485, 511, 526, 540, 562, 580, 602, 620, 634, 646, 661, 679, 712, 725, 736, 762, 773, 790, 813, 828, 843, 853, 867, 882, 907, 918, 935, 948, 963, 977, 1001, 1017, 1033, 1048, 1063, 1083, 1104, 1120, 1141, 1164, 1189, 1209, 1227, 1254, 1285, 1297} +var _RuleId_index = [...]uint16{0, 23, 45, 68, 87, 105, 120, 140, 158, 179, 201, 220, 237, 250, 272, 293, 317, 344, 363, 381, 400, 428, 452, 468, 485, 511, 526, 540, 562, 580, 602, 620, 634, 646, 661, 679, 712, 725, 736, 762, 773, 790, 813, 828, 843, 853, 867, 882, 907, 918, 935, 948, 963, 977, 1001, 1017, 1028, 1044, 1059, 1074, 1094, 1115, 1131, 1152, 1175, 1200, 1220, 1238, 1265, 1296, 1308} 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 33378e0602..6f063e5305 100644 --- a/sql/analyzer/rules.go +++ b/sql/analyzer/rules.go @@ -92,6 +92,7 @@ var OnceAfterDefault = []Rule{ {assignRoutinesId, assignRoutines}, {modifyUpdateExprsForJoinId, modifyUpdateExprsForJoin}, {applyForeignKeysId, applyForeignKeys}, + {interpreterId, interpreter}, } // DefaultValidationRules to apply while analyzing nodes.