From 783053059585f1216cdf16c228905458fadd237a Mon Sep 17 00:00:00 2001 From: Daylon Wilkins Date: Thu, 13 Nov 2025 07:49:52 -0800 Subject: [PATCH] Hooks example --- engine.go | 1 + sql/hooks/hooks.go | 110 ++++++++++++++++++++++ sql/hooks/noop/impl.go | 192 +++++++++++++++++++++++++++++++++++++++ sql/plan/alter_table.go | 30 +----- sql/rowexec/ddl.go | 73 ++++++++++++++- sql/rowexec/ddl_iters.go | 22 +++++ sql/rowexec/dml.go | 10 ++ 7 files changed, 409 insertions(+), 29 deletions(-) create mode 100644 sql/hooks/hooks.go create mode 100644 sql/hooks/noop/impl.go diff --git a/engine.go b/engine.go index 1b9895e9f6..b7d7946e77 100644 --- a/engine.go +++ b/engine.go @@ -32,6 +32,7 @@ import ( "github.com/dolthub/go-mysql-server/sql/analyzer" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/expression/function" + _ "github.com/dolthub/go-mysql-server/sql/hooks/noop" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/planbuilder" "github.com/dolthub/go-mysql-server/sql/rowexec" diff --git a/sql/hooks/hooks.go b/sql/hooks/hooks.go new file mode 100644 index 0000000000..52740a8e69 --- /dev/null +++ b/sql/hooks/hooks.go @@ -0,0 +1,110 @@ +// Copyright 2025 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 hooks + +import ( + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/plan" +) + +// Global is a variable that contains the interface for calling hooks. By default, this contains no-op hooks as +// integrators may implement their own hooks. This variable should be overwritten by the integrator. +var Global Hooks + +// Hooks is an interface that represents various hooks that are called within a statement's lifecycle. +type Hooks interface { + // Table returns hooks related to direct table statements. + Table() Table + // TableColumn returns hooks related to table column statements. + TableColumn() TableColumn +} + +// Table contains hooks related to direct table statements. +type Table interface { + // Create returns hooks related to CREATE TABLE statements. + Create() CreateTable + // Rename returns hooks related to RENAME TABLE statements. + Rename() RenameTable + // Drop returns hooks related to DROP TABLE statements. + Drop() DropTable +} + +// TableColumn contains hooks related to table column statements. +type TableColumn interface { + // Add returns hooks related to ALTER TABLE ... ADD COLUMN statements. + Add() TableAddColumn + // Rename returns hooks related to ALTER TABLE ... RENAME COLUMN statements. + Rename() TableRenameColumn + // Modify returns hooks related to ALTER TABLE ... MODIFY COLUMN statements. + Modify() TableModifyColumn + // Drop returns hooks related to ALTER TABLE ... DROP COLUMN statements. + Drop() TableDropColumn +} + +// CreateTable contains hooks related to CREATE TABLE statements. +type CreateTable interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.CreateTable) (*plan.CreateTable, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.CreateTable) error +} + +// RenameTable contains hooks related to RENAME TABLE statements. +type RenameTable interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.RenameTable) (*plan.RenameTable, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.RenameTable) error +} + +// DropTable contains hooks related to DROP TABLE statements. +type DropTable interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.DropTable) (*plan.DropTable, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.DropTable) error +} + +// TableAddColumn contains hooks related to ALTER TABLE ... ADD COLUMN statements. +type TableAddColumn interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.AddColumn) (*plan.AddColumn, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.AddColumn) error +} + +// TableRenameColumn contains hooks related to ALTER TABLE ... RENAME COLUMN statements. +type TableRenameColumn interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.RenameColumn) (*plan.RenameColumn, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.RenameColumn) error +} + +// TableModifyColumn contains hooks related to ALTER TABLE ... MODIFY COLUMN statements. +type TableModifyColumn interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.ModifyColumn) (*plan.ModifyColumn, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.ModifyColumn) error +} + +// TableDropColumn contains hooks related to ALTER TABLE ... DROP COLUMN statements. +type TableDropColumn interface { + // PreSQLExecution is called before the final step of statement execution, after analysis. + PreSQLExecution(*sql.Context, *plan.DropColumn) (*plan.DropColumn, error) + // PostSQLExecution is called after the final step of statement execution, after analysis. + PostSQLExecution(*sql.Context, *plan.DropColumn) error +} diff --git a/sql/hooks/noop/impl.go b/sql/hooks/noop/impl.go new file mode 100644 index 0000000000..0ced6d0e5a --- /dev/null +++ b/sql/hooks/noop/impl.go @@ -0,0 +1,192 @@ +// Copyright 2025 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 noop + +import ( + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/hooks" + "github.com/dolthub/go-mysql-server/sql/plan" +) + +// init sets the global hooks to be no-ops by default. It is intended that the variable will be replaced by the +// integrator. +func init() { + hooks.Global = NoOp{} +} + +// NoOp implements hooks.Hooks while having all operations be no-ops. Integrators may supply their own implementation. +type NoOp struct{} + +var _ hooks.Hooks = NoOp{} + +// Table implements the interface hooks.Hooks. +func (NoOp) Table() hooks.Table { + return Table{} +} + +// TableColumn implements the interface hooks.Hooks. +func (NoOp) TableColumn() hooks.TableColumn { + return TableColumn{} +} + +// Table implements no-ops for the hooks.Table interface. +type Table struct{} + +var _ hooks.Table = Table{} + +// Create implements the interface hooks.Table. +func (Table) Create() hooks.CreateTable { + return CreateTable{} +} + +// Rename implements the interface hooks.Table. +func (Table) Rename() hooks.RenameTable { + return RenameTable{} +} + +// Drop implements the interface hooks.Table. +func (Table) Drop() hooks.DropTable { + return DropTable{} +} + +// TableColumn implements no-ops for the hooks.TableColumn interface. +type TableColumn struct{} + +var _ hooks.TableColumn = TableColumn{} + +// Add implements the interface hooks.TableColumn. +func (TableColumn) Add() hooks.TableAddColumn { + return TableAddColumn{} +} + +// Rename implements the interface hooks.TableColumn. +func (TableColumn) Rename() hooks.TableRenameColumn { + return TableRenameColumn{} +} + +// Modify implements the interface hooks.TableColumn. +func (TableColumn) Modify() hooks.TableModifyColumn { + return TableModifyColumn{} +} + +// Drop implements the interface hooks.TableColumn. +func (TableColumn) Drop() hooks.TableDropColumn { + return TableDropColumn{} +} + +// CreateTable implements no-ops for the hooks.CreateTable interface. +type CreateTable struct{} + +var _ hooks.CreateTable = CreateTable{} + +// PreSQLExecution implements the interface hooks.CreateTable. +func (CreateTable) PreSQLExecution(_ *sql.Context, n *plan.CreateTable) (*plan.CreateTable, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.CreateTable. +func (CreateTable) PostSQLExecution(_ *sql.Context, n *plan.CreateTable) error { + return nil +} + +// RenameTable implements no-ops for the hooks.RenameTable interface. +type RenameTable struct{} + +var _ hooks.RenameTable = RenameTable{} + +// PreSQLExecution implements the interface hooks.RenameTable. +func (RenameTable) PreSQLExecution(_ *sql.Context, n *plan.RenameTable) (*plan.RenameTable, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.RenameTable. +func (RenameTable) PostSQLExecution(_ *sql.Context, n *plan.RenameTable) error { + return nil +} + +// DropTable implements no-ops for the hooks.DropTable interface. +type DropTable struct{} + +var _ hooks.DropTable = DropTable{} + +// PreSQLExecution implements the interface hooks.DropTable. +func (DropTable) PreSQLExecution(_ *sql.Context, n *plan.DropTable) (*plan.DropTable, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.DropTable. +func (DropTable) PostSQLExecution(_ *sql.Context, n *plan.DropTable) error { + return nil +} + +// TableAddColumn implements no-ops for the hooks.TableAddColumn interface. +type TableAddColumn struct{} + +var _ hooks.TableAddColumn = TableAddColumn{} + +// PreSQLExecution implements the interface hooks.TableAddColumn. +func (TableAddColumn) PreSQLExecution(_ *sql.Context, n *plan.AddColumn) (*plan.AddColumn, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.TableAddColumn. +func (TableAddColumn) PostSQLExecution(_ *sql.Context, n *plan.AddColumn) error { + return nil +} + +// TableRenameColumn implements no-ops for the hooks.TableRenameColumn interface. +type TableRenameColumn struct{} + +var _ hooks.TableRenameColumn = TableRenameColumn{} + +// PreSQLExecution implements the interface hooks.TableRenameColumn. +func (TableRenameColumn) PreSQLExecution(_ *sql.Context, n *plan.RenameColumn) (*plan.RenameColumn, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.TableRenameColumn. +func (TableRenameColumn) PostSQLExecution(_ *sql.Context, n *plan.RenameColumn) error { + return nil +} + +// TableModifyColumn implements no-ops for the hooks.TableModifyColumn interface. +type TableModifyColumn struct{} + +var _ hooks.TableModifyColumn = TableModifyColumn{} + +// PreSQLExecution implements the interface hooks.TableModifyColumn. +func (TableModifyColumn) PreSQLExecution(_ *sql.Context, n *plan.ModifyColumn) (*plan.ModifyColumn, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.TableModifyColumn. +func (TableModifyColumn) PostSQLExecution(_ *sql.Context, n *plan.ModifyColumn) error { + return nil +} + +// TableDropColumn implements no-ops for the hooks.TableDropColumn interface. +type TableDropColumn struct{} + +var _ hooks.TableDropColumn = TableDropColumn{} + +// PreSQLExecution implements the interface hooks.TableDropColumn. +func (TableDropColumn) PreSQLExecution(_ *sql.Context, n *plan.DropColumn) (*plan.DropColumn, error) { + return n, nil +} + +// PostSQLExecution implements the interface hooks.TableDropColumn. +func (TableDropColumn) PostSQLExecution(_ *sql.Context, n *plan.DropColumn) error { + return nil +} diff --git a/sql/plan/alter_table.go b/sql/plan/alter_table.go index 2f45203ccd..aafcf6e1fa 100644 --- a/sql/plan/alter_table.go +++ b/sql/plan/alter_table.go @@ -59,30 +59,6 @@ func (r *RenameTable) IsReadOnly() bool { return false } -func (r *RenameTable) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { - renamer, _ := r.Db.(sql.TableRenamer) - viewDb, _ := r.Db.(sql.ViewDatabase) - viewRegistry := ctx.GetViewRegistry() - - for i, oldName := range r.OldNames { - if tbl, exists := r.tableExists(ctx, oldName); exists { - err := r.renameTable(ctx, renamer, tbl, oldName, r.NewNames[i]) - if err != nil { - return nil, err - } - } else { - success, err := r.renameView(ctx, viewDb, viewRegistry, oldName, r.NewNames[i]) - if err != nil { - return nil, err - } else if !success { - return nil, sql.ErrTableNotFound.New(oldName) - } - } - } - - return sql.RowsToRowIter(sql.NewRow(types.NewOkResult(0))), nil -} - func (r *RenameTable) WithChildren(children ...sql.Node) (sql.Node, error) { return NillaryWithChildren(r, children...) } @@ -92,7 +68,7 @@ func (*RenameTable) CollationCoercibility(ctx *sql.Context) (collation sql.Colla return sql.Collation_binary, 7 } -func (r *RenameTable) tableExists(ctx *sql.Context, name string) (sql.Table, bool) { +func (r *RenameTable) TableExists(ctx *sql.Context, name string) (sql.Table, bool) { tbl, ok, err := r.Db.GetTableInsensitive(ctx, name) if err != nil || !ok { return nil, false @@ -100,7 +76,7 @@ func (r *RenameTable) tableExists(ctx *sql.Context, name string) (sql.Table, boo return tbl, true } -func (r *RenameTable) renameTable(ctx *sql.Context, renamer sql.TableRenamer, tbl sql.Table, oldName, newName string) error { +func (r *RenameTable) RenameTable(ctx *sql.Context, renamer sql.TableRenamer, tbl sql.Table, oldName, newName string) error { if renamer == nil { return sql.ErrRenameTableNotSupported.New(r.Db.Name()) } @@ -160,7 +136,7 @@ func (r *RenameTable) renameTable(ctx *sql.Context, renamer sql.TableRenamer, tb return nil } -func (r *RenameTable) renameView(ctx *sql.Context, viewDb sql.ViewDatabase, vr *sql.ViewRegistry, oldName, newName string) (bool, error) { +func (r *RenameTable) RenameView(ctx *sql.Context, viewDb sql.ViewDatabase, vr *sql.ViewRegistry, oldName, newName string) (bool, error) { if viewDb != nil { oldView, exists, err := viewDb.GetViewDefinition(ctx, oldName) if err != nil { diff --git a/sql/rowexec/ddl.go b/sql/rowexec/ddl.go index 483defa5e4..df07cedf06 100644 --- a/sql/rowexec/ddl.go +++ b/sql/rowexec/ddl.go @@ -28,6 +28,7 @@ import ( "github.com/dolthub/go-mysql-server/internal/similartext" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/fulltext" + "github.com/dolthub/go-mysql-server/sql/hooks" "github.com/dolthub/go-mysql-server/sql/mysql_db" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/types" @@ -240,10 +241,46 @@ func (b *BaseBuilder) buildDropCheck(ctx *sql.Context, n *plan.DropCheck, row sq } func (b *BaseBuilder) buildRenameTable(ctx *sql.Context, n *plan.RenameTable, row sql.Row) (sql.RowIter, error) { - return n.RowIter(ctx, row) + var err error + renameTableHooks := hooks.Global.Table().Rename() + n, err = renameTableHooks.PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } + + renamer, _ := n.Db.(sql.TableRenamer) + viewDb, _ := n.Db.(sql.ViewDatabase) + viewRegistry := ctx.GetViewRegistry() + + for i, oldName := range n.OldNames { + if tbl, exists := n.TableExists(ctx, oldName); exists { + err := n.RenameTable(ctx, renamer, tbl, oldName, n.NewNames[i]) + if err != nil { + return nil, err + } + } else { + success, err := n.RenameView(ctx, viewDb, viewRegistry, oldName, n.NewNames[i]) + if err != nil { + return nil, err + } else if !success { + return nil, sql.ErrTableNotFound.New(oldName) + } + } + } + if err = renameTableHooks.PostSQLExecution(ctx, n); err != nil { + return nil, err + } + + return sql.RowsToRowIter(sql.NewRow(types.NewOkResult(0))), nil } func (b *BaseBuilder) buildModifyColumn(ctx *sql.Context, n *plan.ModifyColumn, row sql.Row) (sql.RowIter, error) { + var err error + n, err = hooks.Global.TableColumn().Modify().PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } + tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table) if err != nil { return nil, err @@ -841,6 +878,13 @@ func (b *BaseBuilder) buildDropDB(ctx *sql.Context, n *plan.DropDB, row sql.Row) } func (b *BaseBuilder) buildRenameColumn(ctx *sql.Context, n *plan.RenameColumn, row sql.Row) (sql.RowIter, error) { + var err error + renameColumnHooks := hooks.Global.TableColumn().Rename() + n, err = renameColumnHooks.PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } + tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table) if err != nil { return nil, err @@ -881,11 +925,22 @@ func (b *BaseBuilder) buildRenameColumn(ctx *sql.Context, n *plan.RenameColumn, } } } + if err = alterable.ModifyColumn(ctx, n.ColumnName, col, nil); err != nil { + return nil, err + } + if err = renameColumnHooks.PostSQLExecution(ctx, n); err != nil { + return nil, err + } - return rowIterWithOkResultWithZeroRowsAffected(), alterable.ModifyColumn(ctx, n.ColumnName, col, nil) + return rowIterWithOkResultWithZeroRowsAffected(), nil } func (b *BaseBuilder) buildAddColumn(ctx *sql.Context, n *plan.AddColumn, row sql.Row) (sql.RowIter, error) { + var err error + n, err = hooks.Global.TableColumn().Add().PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } table, err := getTableFromDatabase(ctx, n.Database(), n.Table) if err != nil { return nil, err @@ -963,6 +1018,11 @@ func (b *BaseBuilder) buildAlterDB(ctx *sql.Context, n *plan.AlterDB, row sql.Ro func (b *BaseBuilder) buildCreateTable(ctx *sql.Context, n *plan.CreateTable, row sql.Row) (sql.RowIter, error) { var err error + createTableHooks := hooks.Global.Table().Create() + n, err = createTableHooks.PreSQLExecution(ctx, n) + if err != nil { + return sql.RowsToRowIter(), err + } // If it's set to Invalid, then no collation has been explicitly defined if n.Collation == sql.Collation_Unspecified { @@ -1122,6 +1182,10 @@ func (b *BaseBuilder) buildCreateTable(ctx *sql.Context, n *plan.CreateTable, ro } } + if err = createTableHooks.PostSQLExecution(ctx, n); err != nil { + return sql.RowsToRowIter(), err + } + return rowIterWithOkResultWithZeroRowsAffected(), nil } @@ -1199,6 +1263,11 @@ func (b *BaseBuilder) buildCreateTrigger(ctx *sql.Context, n *plan.CreateTrigger } func (b *BaseBuilder) buildDropColumn(ctx *sql.Context, n *plan.DropColumn, row sql.Row) (sql.RowIter, error) { + var err error + n, err = hooks.Global.TableColumn().Drop().PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table) if err != nil { return nil, err diff --git a/sql/rowexec/ddl_iters.go b/sql/rowexec/ddl_iters.go index 3a58743c7c..35b843ab5d 100644 --- a/sql/rowexec/ddl_iters.go +++ b/sql/rowexec/ddl_iters.go @@ -31,6 +31,7 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/fulltext" + "github.com/dolthub/go-mysql-server/sql/hooks" "github.com/dolthub/go-mysql-server/sql/mysql_db" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/transform" @@ -422,6 +423,9 @@ func (i *modifyColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } if rewritten { + if err = hooks.Global.TableColumn().Modify().PostSQLExecution(ctx, i.m); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } } @@ -441,6 +445,9 @@ func (i *modifyColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } } + if err = hooks.Global.TableColumn().Modify().PostSQLExecution(ctx, i.m); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } @@ -1332,6 +1339,9 @@ func (i *addColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } if rewritten { + if err = hooks.Global.TableColumn().Add().PostSQLExecution(ctx, i.a); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } } @@ -1349,6 +1359,9 @@ func (i *addColumnIter) Next(ctx *sql.Context) (sql.Row, error) { // We only need to update all table rows if the new column is non-nil if i.a.Column().Nullable && i.a.Column().Default == nil { + if err = hooks.Global.TableColumn().Add().PostSQLExecution(ctx, i.a); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } @@ -1357,6 +1370,9 @@ func (i *addColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } + if err = hooks.Global.TableColumn().Add().PostSQLExecution(ctx, i.a); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } @@ -1735,6 +1751,9 @@ func (i *dropColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } if rewritten { + if err = hooks.Global.TableColumn().Drop().PostSQLExecution(ctx, i.d); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } } @@ -1757,6 +1776,9 @@ func (i *dropColumnIter) Next(ctx *sql.Context) (sql.Row, error) { return nil, err } } + if err = hooks.Global.TableColumn().Drop().PostSQLExecution(ctx, i.d); err != nil { + return nil, err + } return sql.NewRow(types.NewOkResult(0)), nil } diff --git a/sql/rowexec/dml.go b/sql/rowexec/dml.go index c1d6fa9407..ab9581afad 100644 --- a/sql/rowexec/dml.go +++ b/sql/rowexec/dml.go @@ -22,6 +22,7 @@ import ( "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/fulltext" + "github.com/dolthub/go-mysql-server/sql/hooks" "github.com/dolthub/go-mysql-server/sql/plan" "github.com/dolthub/go-mysql-server/sql/transform" "github.com/dolthub/go-mysql-server/sql/types" @@ -200,6 +201,11 @@ func (b *BaseBuilder) buildDropTable(ctx *sql.Context, n *plan.DropTable, _ sql. var err error var curdb sql.Database + dropTableHooks := hooks.Global.Table().Drop() + n, err = dropTableHooks.PreSQLExecution(ctx, n) + if err != nil { + return nil, err + } sortedTables, err := sortTablesByFKDependencies(ctx, n.Tables) if err != nil { return nil, err @@ -266,6 +272,10 @@ func (b *BaseBuilder) buildDropTable(ctx *sql.Context, n *plan.DropTable, _ sql. } } + if err = dropTableHooks.PostSQLExecution(ctx, n); err != nil { + return nil, err + } + return rowIterWithOkResultWithZeroRowsAffected(), nil }