Skip to content

Commit d3b95b2

Browse files
authored
rewriting stored procedures (#2851)
1 parent b9931b0 commit d3b95b2

29 files changed

+2233
-161
lines changed

engine.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ type Engine struct {
150150
Parser sql.Parser
151151
}
152152

153-
var _ analyzer.StatementRunner = (*Engine)(nil)
153+
var _ sql.StatementRunner = (*Engine)(nil)
154154

155155
type ColumnWithRawDefault struct {
156156
SqlColumn *sql.Column

enginetest/memory_engine_test.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,26 +205,36 @@ func TestSingleScript(t *testing.T) {
205205
t.Skip()
206206
var scripts = []queries.ScriptTest{
207207
{
208-
Name: "test script",
209-
SetUpScript: []string{
210-
"create table t (i int);",
211-
},
208+
Name: "AS OF propagates to nested CALLs",
209+
SetUpScript: []string{},
212210
Assertions: []queries.ScriptTestAssertion{
213211
{
214-
Query: "select 1 into @a",
215-
Expected: []sql.Row{},
212+
Query: "create procedure create_proc() create table t (i int primary key, j int);",
213+
Expected: []sql.Row{
214+
{types.NewOkResult(0)},
215+
},
216+
},
217+
{
218+
Query: "call create_proc()",
219+
Expected: []sql.Row{
220+
{types.NewOkResult(0)},
221+
},
216222
},
217223
},
218224
},
219225
}
220226

221227
for _, test := range scripts {
222228
harness := enginetest.NewMemoryHarness("", 1, testNumPartitions, true, nil)
229+
harness.UseServer()
223230
engine, err := harness.NewEngine(t)
224231
if err != nil {
225232
panic(err)
226233
}
227234

235+
//engine.EngineAnalyzer().Debug = true
236+
//engine.EngineAnalyzer().Verbose = true
237+
228238
enginetest.TestScriptWithEngine(t, engine, harness, test)
229239
}
230240
}

enginetest/queries/procedure_queries.go

Lines changed: 145 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"time"
1919

2020
"github.com/dolthub/go-mysql-server/sql"
21+
"github.com/dolthub/go-mysql-server/sql/plan"
2122
"github.com/dolthub/go-mysql-server/sql/types"
2223
)
2324

@@ -75,17 +76,13 @@ var ProcedureLogicTests = []ScriptTest{
7576
{
7677
Query: "CALL testabc(2, 3)",
7778
Expected: []sql.Row{
78-
{
79-
6.0,
80-
},
79+
{6.0},
8180
},
8281
},
8382
{
8483
Query: "CALL testabc(9, 9.5)",
8584
Expected: []sql.Row{
86-
{
87-
85.5,
88-
},
85+
{85.5},
8986
},
9087
},
9188
},
@@ -906,9 +903,11 @@ END;`,
906903
SetUpScript: []string{
907904
"CREATE TABLE inventory (item_id int primary key, shelf_id int, item varchar(10))",
908905
"INSERT INTO inventory VALUES (1, 1, 'a'), (2, 1, 'b'), (3, 2, 'c'), (4, 1, 'd'), (5, 4, 'e')",
909-
`CREATE PROCEDURE count_and_print(IN p_shelf_id INT, OUT p_count INT) BEGIN
910-
SELECT item FROM inventory WHERE shelf_id = p_shelf_id ORDER BY item ASC;
911-
SELECT COUNT(*) INTO p_count FROM inventory WHERE shelf_id = p_shelf_id;
906+
`
907+
CREATE PROCEDURE count_and_print(IN p_shelf_id INT, OUT p_count INT)
908+
BEGIN
909+
SELECT item FROM inventory WHERE shelf_id = p_shelf_id ORDER BY item ASC;
910+
SELECT COUNT(*) INTO p_count FROM inventory WHERE shelf_id = p_shelf_id;
912911
END`,
913912
},
914913
Assertions: []ScriptTestAssertion{
@@ -989,8 +988,12 @@ END;`,
989988
Expected: []sql.Row{{}},
990989
},
991990
{
992-
Query: "CALL p1(@x);",
993-
Expected: []sql.Row{{}},
991+
// TODO: Set statements don't return anything for whatever reason
992+
SkipResultCheckOnServerEngine: true,
993+
Query: "CALL p1(@x);",
994+
Expected: []sql.Row{
995+
{types.NewOkResult(0)},
996+
},
994997
},
995998
{
996999
Query: "SELECT @x;",
@@ -1020,8 +1023,6 @@ BEGIN
10201023
ELSEIF x = 4 THEN
10211024
SIGNAL specialty2;
10221025
ELSE
1023-
SIGNAL SQLSTATE '01000'
1024-
SET MESSAGE_TEXT = 'A warning occurred', MYSQL_ERRNO = 1000;
10251026
SIGNAL SQLSTATE '45000'
10261027
SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1001;
10271028
END IF;
@@ -1051,6 +1052,10 @@ END;`,
10511052
Query: "CALL p1(4)",
10521053
ExpectedErrStr: "Unhandled user-defined not found condition (errno 1643) (sqlstate 02000)",
10531054
},
1055+
{
1056+
Query: "CALL p1(5)",
1057+
ExpectedErrStr: "An error occurred (errno 1001) (sqlstate 45000)",
1058+
},
10541059
},
10551060
},
10561061
{
@@ -1266,17 +1271,18 @@ END;`,
12661271
`CREATE PROCEDURE duplicate_key()
12671272
BEGIN
12681273
DECLARE a, b INT DEFAULT 1;
1269-
BEGIN
1274+
BEGIN
12701275
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET a = 7;
12711276
INSERT INTO t1 values (0);
1272-
END;
1273-
SELECT a;
1277+
END;
1278+
SELECT a;
12741279
END;`,
12751280
},
12761281
Assertions: []ScriptTestAssertion{
12771282
{
1278-
Query: "CALL eof();",
1279-
Expected: []sql.Row{},
1283+
// TODO: MySQL returns: ERROR: 1329: No data - zero rows fetched, selected, or processed
1284+
Query: "CALL eof();",
1285+
ExpectedErrStr: "exhausted fetch iterator",
12801286
},
12811287
{
12821288
Query: "CALL duplicate_key();",
@@ -1392,8 +1398,12 @@ END;`,
13921398
},
13931399
Assertions: []ScriptTestAssertion{
13941400
{
1395-
Query: "CALL outer_declare();",
1396-
Expected: []sql.Row{},
1401+
// TODO: Set statements don't return anything for whatever reason
1402+
SkipResultCheckOnServerEngine: true,
1403+
Query: "CALL outer_declare();",
1404+
Expected: []sql.Row{
1405+
{types.NewOkResult(0)},
1406+
},
13971407
},
13981408
{
13991409
Query: "CALL inner_declare();",
@@ -2214,9 +2224,7 @@ var ProcedureCallTests = []ScriptTest{
22142224
{
22152225
Query: "SELECT @outparam",
22162226
Expected: []sql.Row{
2217-
{
2218-
nil,
2219-
},
2227+
{nil},
22202228
},
22212229
},
22222230
},
@@ -2270,9 +2278,7 @@ var ProcedureCallTests = []ScriptTest{
22702278
{
22712279
Query: "SELECT @outparam",
22722280
Expected: []sql.Row{
2273-
{
2274-
int64(777),
2275-
},
2281+
{int64(777)},
22762282
},
22772283
},
22782284
},
@@ -2831,19 +2837,118 @@ var ProcedureCreateInSubroutineTests = []ScriptTest{
28312837
},
28322838
},
28332839
},
2840+
28342841
{
2835-
Name: "procedure must not contain CREATE TABLE",
2842+
Name: "table ddl statements in stored procedures",
28362843
Assertions: []ScriptTestAssertion{
28372844
{
2838-
Query: "create procedure p() create table t (pk int);",
2839-
ExpectedErrStr: "CREATE statements in CREATE PROCEDURE not yet supported",
2845+
Query: "create procedure create_proc() create table t (i int primary key, j int);",
2846+
Expected: []sql.Row{
2847+
{types.NewOkResult(0)},
2848+
},
2849+
},
2850+
{
2851+
SkipResultCheckOnServerEngine: true,
2852+
Query: "call create_proc()",
2853+
Expected: []sql.Row{
2854+
{types.NewOkResult(0)},
2855+
},
2856+
},
2857+
{
2858+
Query: "show create table t;",
2859+
Expected: []sql.Row{
2860+
{"t", "CREATE TABLE `t` (\n" +
2861+
" `i` int NOT NULL,\n" +
2862+
" `j` int,\n" +
2863+
" PRIMARY KEY (`i`)\n" +
2864+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"},
2865+
},
2866+
},
2867+
{
2868+
Query: "call create_proc()",
2869+
ExpectedErrStr: "table with name t already exists",
28402870
},
2871+
28412872
{
2842-
Query: "create procedure p() begin create table t (pk int); end;",
2843-
ExpectedErrStr: "CREATE statements in CREATE PROCEDURE not yet supported",
2873+
Query: "create procedure insert_proc() insert into t values (1, 1), (2, 2), (3, 3);",
2874+
Expected: []sql.Row{
2875+
{types.NewOkResult(0)},
2876+
},
2877+
},
2878+
{
2879+
SkipResultCheckOnServerEngine: true,
2880+
Query: "call insert_proc()",
2881+
Expected: []sql.Row{
2882+
{types.NewOkResult(3)},
2883+
},
2884+
},
2885+
{
2886+
Query: "select * from t",
2887+
Expected: []sql.Row{
2888+
{1, 1},
2889+
{2, 2},
2890+
{3, 3},
2891+
},
2892+
},
2893+
{
2894+
SkipResultCheckOnServerEngine: true,
2895+
Query: "call insert_proc()",
2896+
ExpectedErrStr: "duplicate primary key given: [1]",
2897+
},
2898+
2899+
{
2900+
Query: "create procedure update_proc() update t set j = 999 where i > 1;",
2901+
Expected: []sql.Row{
2902+
{types.NewOkResult(0)},
2903+
},
2904+
},
2905+
{
2906+
SkipResultCheckOnServerEngine: true,
2907+
Query: "call update_proc()",
2908+
Expected: []sql.Row{
2909+
{types.OkResult{RowsAffected: 2, Info: plan.UpdateInfo{Matched: 2, Updated: 2}}},
2910+
},
2911+
},
2912+
{
2913+
Query: "select * from t",
2914+
Expected: []sql.Row{
2915+
{1, 1},
2916+
{2, 999},
2917+
{3, 999},
2918+
},
2919+
},
2920+
{
2921+
SkipResultCheckOnServerEngine: true,
2922+
Query: "call update_proc()",
2923+
Expected: []sql.Row{
2924+
{types.OkResult{RowsAffected: 0, Info: plan.UpdateInfo{Matched: 2}}},
2925+
},
2926+
},
2927+
2928+
{
2929+
Query: "create procedure drop_proc() drop table t;",
2930+
Expected: []sql.Row{
2931+
{types.NewOkResult(0)},
2932+
},
2933+
},
2934+
{
2935+
SkipResultCheckOnServerEngine: true,
2936+
Query: "call drop_proc()",
2937+
Expected: []sql.Row{
2938+
{types.NewOkResult(0)},
2939+
},
2940+
},
2941+
{
2942+
Query: "show tables like 't'",
2943+
Expected: []sql.Row{},
2944+
},
2945+
{
2946+
Query: "call drop_proc()",
2947+
ExpectedErrStr: "table not found: t",
28442948
},
28452949
},
28462950
},
2951+
28472952
{
28482953
Name: "procedure must not contain CREATE TRIGGER",
28492954
SetUpScript: []string{
@@ -2875,16 +2980,20 @@ var ProcedureCreateInSubroutineTests = []ScriptTest{
28752980
},
28762981
},
28772982
{
2878-
Name: "procedure must not contain CREATE VIEW",
2983+
Name: "procedure can CREATE VIEW",
28792984
SetUpScript: []string{},
28802985
Assertions: []ScriptTestAssertion{
28812986
{
2882-
Query: "create procedure p() create view v as select 1;",
2883-
ExpectedErrStr: "CREATE statements in CREATE PROCEDURE not yet supported",
2987+
Query: "create procedure p1() create view v as select 1;",
2988+
Expected: []sql.Row{
2989+
{types.NewOkResult(0)},
2990+
},
28842991
},
28852992
{
2886-
Query: "create procedure p() begin create view v as select 1; end;",
2887-
ExpectedErrStr: "CREATE statements in CREATE PROCEDURE not yet supported",
2993+
Query: "create procedure p() begin create view v as select 1; end;",
2994+
Expected: []sql.Row{
2995+
{types.NewOkResult(0)},
2996+
},
28882997
},
28892998
},
28902999
},

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad
77
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71
88
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81
9-
github.com/dolthub/vitess v0.0.0-20250423221552-f731ee5c5379
9+
github.com/dolthub/vitess v0.0.0-20250430180243-0eee73763bc5
1010
github.com/go-kit/kit v0.10.0
1111
github.com/go-sql-driver/mysql v1.7.2-0.20231213112541-0004702b931d
1212
github.com/gocraft/dbr/v2 v2.7.2

go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,8 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE
5858
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI=
5959
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE=
6060
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY=
61-
github.com/dolthub/vitess v0.0.0-20250410233614-8d8c7a5b3d6b h1:2wE+qJwJ5SRIzz+dJQT8XbkpK+g8/pFt34AU/iJ5K+Y=
62-
github.com/dolthub/vitess v0.0.0-20250410233614-8d8c7a5b3d6b/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
63-
github.com/dolthub/vitess v0.0.0-20250414165810-f0031a6472b7 h1:4Y043kZgAH1WhOER0nk+02KPKxJX8Ir6yK7cGzY04c4=
64-
github.com/dolthub/vitess v0.0.0-20250414165810-f0031a6472b7/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
65-
github.com/dolthub/vitess v0.0.0-20250417230335-b8d80bc39341 h1:qebIGlJEgi/mSXVZ39P77cklPuuIl8gApyTVMnKm79s=
66-
github.com/dolthub/vitess v0.0.0-20250417230335-b8d80bc39341/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
67-
github.com/dolthub/vitess v0.0.0-20250423221552-f731ee5c5379 h1:3nPFx23Ol0djIPf9rDw/y38yEn1BXqTXOUkYrWfxrEI=
68-
github.com/dolthub/vitess v0.0.0-20250423221552-f731ee5c5379/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
61+
github.com/dolthub/vitess v0.0.0-20250430180243-0eee73763bc5 h1:eyC/UHnNsCham/65hV9p/Si0S+cq774kbgk0/KPFYws=
62+
github.com/dolthub/vitess v0.0.0-20250430180243-0eee73763bc5/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70=
6963
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
7064
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
7165
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=

sql/analyzer/analyzer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ type Analyzer struct {
294294
// ExecBuilder converts a sql.Node tree into an executable iterator.
295295
ExecBuilder sql.NodeExecBuilder
296296
// Runner represents the engine, which is represented as a separate interface to work around circular dependencies
297-
Runner StatementRunner
297+
Runner sql.StatementRunner
298298
// Parser is the parser used to parse SQL statements.
299299
Parser sql.Parser
300300
// SchemaFormatter is used to format the schema of a node to a string.

0 commit comments

Comments
 (0)