Skip to content

Commit 7830530

Browse files
committed
Hooks example
1 parent 83d2fda commit 7830530

File tree

7 files changed

+409
-29
lines changed

7 files changed

+409
-29
lines changed

engine.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/dolthub/go-mysql-server/sql/analyzer"
3333
"github.com/dolthub/go-mysql-server/sql/expression"
3434
"github.com/dolthub/go-mysql-server/sql/expression/function"
35+
_ "github.com/dolthub/go-mysql-server/sql/hooks/noop"
3536
"github.com/dolthub/go-mysql-server/sql/plan"
3637
"github.com/dolthub/go-mysql-server/sql/planbuilder"
3738
"github.com/dolthub/go-mysql-server/sql/rowexec"

sql/hooks/hooks.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2025 Dolthub, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package hooks
16+
17+
import (
18+
"github.com/dolthub/go-mysql-server/sql"
19+
"github.com/dolthub/go-mysql-server/sql/plan"
20+
)
21+
22+
// Global is a variable that contains the interface for calling hooks. By default, this contains no-op hooks as
23+
// integrators may implement their own hooks. This variable should be overwritten by the integrator.
24+
var Global Hooks
25+
26+
// Hooks is an interface that represents various hooks that are called within a statement's lifecycle.
27+
type Hooks interface {
28+
// Table returns hooks related to direct table statements.
29+
Table() Table
30+
// TableColumn returns hooks related to table column statements.
31+
TableColumn() TableColumn
32+
}
33+
34+
// Table contains hooks related to direct table statements.
35+
type Table interface {
36+
// Create returns hooks related to CREATE TABLE statements.
37+
Create() CreateTable
38+
// Rename returns hooks related to RENAME TABLE statements.
39+
Rename() RenameTable
40+
// Drop returns hooks related to DROP TABLE statements.
41+
Drop() DropTable
42+
}
43+
44+
// TableColumn contains hooks related to table column statements.
45+
type TableColumn interface {
46+
// Add returns hooks related to ALTER TABLE ... ADD COLUMN statements.
47+
Add() TableAddColumn
48+
// Rename returns hooks related to ALTER TABLE ... RENAME COLUMN statements.
49+
Rename() TableRenameColumn
50+
// Modify returns hooks related to ALTER TABLE ... MODIFY COLUMN statements.
51+
Modify() TableModifyColumn
52+
// Drop returns hooks related to ALTER TABLE ... DROP COLUMN statements.
53+
Drop() TableDropColumn
54+
}
55+
56+
// CreateTable contains hooks related to CREATE TABLE statements.
57+
type CreateTable interface {
58+
// PreSQLExecution is called before the final step of statement execution, after analysis.
59+
PreSQLExecution(*sql.Context, *plan.CreateTable) (*plan.CreateTable, error)
60+
// PostSQLExecution is called after the final step of statement execution, after analysis.
61+
PostSQLExecution(*sql.Context, *plan.CreateTable) error
62+
}
63+
64+
// RenameTable contains hooks related to RENAME TABLE statements.
65+
type RenameTable interface {
66+
// PreSQLExecution is called before the final step of statement execution, after analysis.
67+
PreSQLExecution(*sql.Context, *plan.RenameTable) (*plan.RenameTable, error)
68+
// PostSQLExecution is called after the final step of statement execution, after analysis.
69+
PostSQLExecution(*sql.Context, *plan.RenameTable) error
70+
}
71+
72+
// DropTable contains hooks related to DROP TABLE statements.
73+
type DropTable interface {
74+
// PreSQLExecution is called before the final step of statement execution, after analysis.
75+
PreSQLExecution(*sql.Context, *plan.DropTable) (*plan.DropTable, error)
76+
// PostSQLExecution is called after the final step of statement execution, after analysis.
77+
PostSQLExecution(*sql.Context, *plan.DropTable) error
78+
}
79+
80+
// TableAddColumn contains hooks related to ALTER TABLE ... ADD COLUMN statements.
81+
type TableAddColumn interface {
82+
// PreSQLExecution is called before the final step of statement execution, after analysis.
83+
PreSQLExecution(*sql.Context, *plan.AddColumn) (*plan.AddColumn, error)
84+
// PostSQLExecution is called after the final step of statement execution, after analysis.
85+
PostSQLExecution(*sql.Context, *plan.AddColumn) error
86+
}
87+
88+
// TableRenameColumn contains hooks related to ALTER TABLE ... RENAME COLUMN statements.
89+
type TableRenameColumn interface {
90+
// PreSQLExecution is called before the final step of statement execution, after analysis.
91+
PreSQLExecution(*sql.Context, *plan.RenameColumn) (*plan.RenameColumn, error)
92+
// PostSQLExecution is called after the final step of statement execution, after analysis.
93+
PostSQLExecution(*sql.Context, *plan.RenameColumn) error
94+
}
95+
96+
// TableModifyColumn contains hooks related to ALTER TABLE ... MODIFY COLUMN statements.
97+
type TableModifyColumn interface {
98+
// PreSQLExecution is called before the final step of statement execution, after analysis.
99+
PreSQLExecution(*sql.Context, *plan.ModifyColumn) (*plan.ModifyColumn, error)
100+
// PostSQLExecution is called after the final step of statement execution, after analysis.
101+
PostSQLExecution(*sql.Context, *plan.ModifyColumn) error
102+
}
103+
104+
// TableDropColumn contains hooks related to ALTER TABLE ... DROP COLUMN statements.
105+
type TableDropColumn interface {
106+
// PreSQLExecution is called before the final step of statement execution, after analysis.
107+
PreSQLExecution(*sql.Context, *plan.DropColumn) (*plan.DropColumn, error)
108+
// PostSQLExecution is called after the final step of statement execution, after analysis.
109+
PostSQLExecution(*sql.Context, *plan.DropColumn) error
110+
}

sql/hooks/noop/impl.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// Copyright 2025 Dolthub, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package noop
16+
17+
import (
18+
"github.com/dolthub/go-mysql-server/sql"
19+
"github.com/dolthub/go-mysql-server/sql/hooks"
20+
"github.com/dolthub/go-mysql-server/sql/plan"
21+
)
22+
23+
// init sets the global hooks to be no-ops by default. It is intended that the variable will be replaced by the
24+
// integrator.
25+
func init() {
26+
hooks.Global = NoOp{}
27+
}
28+
29+
// NoOp implements hooks.Hooks while having all operations be no-ops. Integrators may supply their own implementation.
30+
type NoOp struct{}
31+
32+
var _ hooks.Hooks = NoOp{}
33+
34+
// Table implements the interface hooks.Hooks.
35+
func (NoOp) Table() hooks.Table {
36+
return Table{}
37+
}
38+
39+
// TableColumn implements the interface hooks.Hooks.
40+
func (NoOp) TableColumn() hooks.TableColumn {
41+
return TableColumn{}
42+
}
43+
44+
// Table implements no-ops for the hooks.Table interface.
45+
type Table struct{}
46+
47+
var _ hooks.Table = Table{}
48+
49+
// Create implements the interface hooks.Table.
50+
func (Table) Create() hooks.CreateTable {
51+
return CreateTable{}
52+
}
53+
54+
// Rename implements the interface hooks.Table.
55+
func (Table) Rename() hooks.RenameTable {
56+
return RenameTable{}
57+
}
58+
59+
// Drop implements the interface hooks.Table.
60+
func (Table) Drop() hooks.DropTable {
61+
return DropTable{}
62+
}
63+
64+
// TableColumn implements no-ops for the hooks.TableColumn interface.
65+
type TableColumn struct{}
66+
67+
var _ hooks.TableColumn = TableColumn{}
68+
69+
// Add implements the interface hooks.TableColumn.
70+
func (TableColumn) Add() hooks.TableAddColumn {
71+
return TableAddColumn{}
72+
}
73+
74+
// Rename implements the interface hooks.TableColumn.
75+
func (TableColumn) Rename() hooks.TableRenameColumn {
76+
return TableRenameColumn{}
77+
}
78+
79+
// Modify implements the interface hooks.TableColumn.
80+
func (TableColumn) Modify() hooks.TableModifyColumn {
81+
return TableModifyColumn{}
82+
}
83+
84+
// Drop implements the interface hooks.TableColumn.
85+
func (TableColumn) Drop() hooks.TableDropColumn {
86+
return TableDropColumn{}
87+
}
88+
89+
// CreateTable implements no-ops for the hooks.CreateTable interface.
90+
type CreateTable struct{}
91+
92+
var _ hooks.CreateTable = CreateTable{}
93+
94+
// PreSQLExecution implements the interface hooks.CreateTable.
95+
func (CreateTable) PreSQLExecution(_ *sql.Context, n *plan.CreateTable) (*plan.CreateTable, error) {
96+
return n, nil
97+
}
98+
99+
// PostSQLExecution implements the interface hooks.CreateTable.
100+
func (CreateTable) PostSQLExecution(_ *sql.Context, n *plan.CreateTable) error {
101+
return nil
102+
}
103+
104+
// RenameTable implements no-ops for the hooks.RenameTable interface.
105+
type RenameTable struct{}
106+
107+
var _ hooks.RenameTable = RenameTable{}
108+
109+
// PreSQLExecution implements the interface hooks.RenameTable.
110+
func (RenameTable) PreSQLExecution(_ *sql.Context, n *plan.RenameTable) (*plan.RenameTable, error) {
111+
return n, nil
112+
}
113+
114+
// PostSQLExecution implements the interface hooks.RenameTable.
115+
func (RenameTable) PostSQLExecution(_ *sql.Context, n *plan.RenameTable) error {
116+
return nil
117+
}
118+
119+
// DropTable implements no-ops for the hooks.DropTable interface.
120+
type DropTable struct{}
121+
122+
var _ hooks.DropTable = DropTable{}
123+
124+
// PreSQLExecution implements the interface hooks.DropTable.
125+
func (DropTable) PreSQLExecution(_ *sql.Context, n *plan.DropTable) (*plan.DropTable, error) {
126+
return n, nil
127+
}
128+
129+
// PostSQLExecution implements the interface hooks.DropTable.
130+
func (DropTable) PostSQLExecution(_ *sql.Context, n *plan.DropTable) error {
131+
return nil
132+
}
133+
134+
// TableAddColumn implements no-ops for the hooks.TableAddColumn interface.
135+
type TableAddColumn struct{}
136+
137+
var _ hooks.TableAddColumn = TableAddColumn{}
138+
139+
// PreSQLExecution implements the interface hooks.TableAddColumn.
140+
func (TableAddColumn) PreSQLExecution(_ *sql.Context, n *plan.AddColumn) (*plan.AddColumn, error) {
141+
return n, nil
142+
}
143+
144+
// PostSQLExecution implements the interface hooks.TableAddColumn.
145+
func (TableAddColumn) PostSQLExecution(_ *sql.Context, n *plan.AddColumn) error {
146+
return nil
147+
}
148+
149+
// TableRenameColumn implements no-ops for the hooks.TableRenameColumn interface.
150+
type TableRenameColumn struct{}
151+
152+
var _ hooks.TableRenameColumn = TableRenameColumn{}
153+
154+
// PreSQLExecution implements the interface hooks.TableRenameColumn.
155+
func (TableRenameColumn) PreSQLExecution(_ *sql.Context, n *plan.RenameColumn) (*plan.RenameColumn, error) {
156+
return n, nil
157+
}
158+
159+
// PostSQLExecution implements the interface hooks.TableRenameColumn.
160+
func (TableRenameColumn) PostSQLExecution(_ *sql.Context, n *plan.RenameColumn) error {
161+
return nil
162+
}
163+
164+
// TableModifyColumn implements no-ops for the hooks.TableModifyColumn interface.
165+
type TableModifyColumn struct{}
166+
167+
var _ hooks.TableModifyColumn = TableModifyColumn{}
168+
169+
// PreSQLExecution implements the interface hooks.TableModifyColumn.
170+
func (TableModifyColumn) PreSQLExecution(_ *sql.Context, n *plan.ModifyColumn) (*plan.ModifyColumn, error) {
171+
return n, nil
172+
}
173+
174+
// PostSQLExecution implements the interface hooks.TableModifyColumn.
175+
func (TableModifyColumn) PostSQLExecution(_ *sql.Context, n *plan.ModifyColumn) error {
176+
return nil
177+
}
178+
179+
// TableDropColumn implements no-ops for the hooks.TableDropColumn interface.
180+
type TableDropColumn struct{}
181+
182+
var _ hooks.TableDropColumn = TableDropColumn{}
183+
184+
// PreSQLExecution implements the interface hooks.TableDropColumn.
185+
func (TableDropColumn) PreSQLExecution(_ *sql.Context, n *plan.DropColumn) (*plan.DropColumn, error) {
186+
return n, nil
187+
}
188+
189+
// PostSQLExecution implements the interface hooks.TableDropColumn.
190+
func (TableDropColumn) PostSQLExecution(_ *sql.Context, n *plan.DropColumn) error {
191+
return nil
192+
}

sql/plan/alter_table.go

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,30 +59,6 @@ func (r *RenameTable) IsReadOnly() bool {
5959
return false
6060
}
6161

62-
func (r *RenameTable) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) {
63-
renamer, _ := r.Db.(sql.TableRenamer)
64-
viewDb, _ := r.Db.(sql.ViewDatabase)
65-
viewRegistry := ctx.GetViewRegistry()
66-
67-
for i, oldName := range r.OldNames {
68-
if tbl, exists := r.tableExists(ctx, oldName); exists {
69-
err := r.renameTable(ctx, renamer, tbl, oldName, r.NewNames[i])
70-
if err != nil {
71-
return nil, err
72-
}
73-
} else {
74-
success, err := r.renameView(ctx, viewDb, viewRegistry, oldName, r.NewNames[i])
75-
if err != nil {
76-
return nil, err
77-
} else if !success {
78-
return nil, sql.ErrTableNotFound.New(oldName)
79-
}
80-
}
81-
}
82-
83-
return sql.RowsToRowIter(sql.NewRow(types.NewOkResult(0))), nil
84-
}
85-
8662
func (r *RenameTable) WithChildren(children ...sql.Node) (sql.Node, error) {
8763
return NillaryWithChildren(r, children...)
8864
}
@@ -92,15 +68,15 @@ func (*RenameTable) CollationCoercibility(ctx *sql.Context) (collation sql.Colla
9268
return sql.Collation_binary, 7
9369
}
9470

95-
func (r *RenameTable) tableExists(ctx *sql.Context, name string) (sql.Table, bool) {
71+
func (r *RenameTable) TableExists(ctx *sql.Context, name string) (sql.Table, bool) {
9672
tbl, ok, err := r.Db.GetTableInsensitive(ctx, name)
9773
if err != nil || !ok {
9874
return nil, false
9975
}
10076
return tbl, true
10177
}
10278

103-
func (r *RenameTable) renameTable(ctx *sql.Context, renamer sql.TableRenamer, tbl sql.Table, oldName, newName string) error {
79+
func (r *RenameTable) RenameTable(ctx *sql.Context, renamer sql.TableRenamer, tbl sql.Table, oldName, newName string) error {
10480
if renamer == nil {
10581
return sql.ErrRenameTableNotSupported.New(r.Db.Name())
10682
}
@@ -160,7 +136,7 @@ func (r *RenameTable) renameTable(ctx *sql.Context, renamer sql.TableRenamer, tb
160136
return nil
161137
}
162138

163-
func (r *RenameTable) renameView(ctx *sql.Context, viewDb sql.ViewDatabase, vr *sql.ViewRegistry, oldName, newName string) (bool, error) {
139+
func (r *RenameTable) RenameView(ctx *sql.Context, viewDb sql.ViewDatabase, vr *sql.ViewRegistry, oldName, newName string) (bool, error) {
164140
if viewDb != nil {
165141
oldView, exists, err := viewDb.GetViewDefinition(ctx, oldName)
166142
if err != nil {

0 commit comments

Comments
 (0)