Skip to content

Commit 1878202

Browse files
lingcodergqcn
andauthored
test(contrib/drivers/mariadb): add layer 3 features and issue regression tests (gogf#4724)
## Summary - Port 5 feature tests: duplicate-key handling (OnDuplicate/OnDuplicateEx/Save), JSON field operations, row-level locking (Lock/LockUpdate/LockShared with transactions), master-slave configuration, table metadata inspection - Port 1 partition test: RANGE partitioning with Partition() clause (adapted from MySQL baseline) - Port 30 issue regression tests from MySQL baseline - Includes 14 testdata SQL files for issue-specific table schemas Layer 3 tests cover MariaDB-specific adaptations where needed (e.g., SKIP LOCKED requires MariaDB 10.6+ — commented out for compatibility, LOCK IN SHARE MODE instead of FOR SHARE for older versions). All tests are structurally aligned with the MySQL driver baseline. Package and import references are adapted for MariaDB. ref gogf#4689 Co-authored-by: John Guo <claymore1986@gmail.com>
1 parent bb71ccf commit 1878202

21 files changed

Lines changed: 4064 additions & 0 deletions
Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package mariadb_test
8+
9+
import (
10+
"context"
11+
"fmt"
12+
"testing"
13+
14+
"github.com/gogf/gf/v2/database/gdb"
15+
"github.com/gogf/gf/v2/os/gtime"
16+
"github.com/gogf/gf/v2/test/gtest"
17+
)
18+
19+
func createDuplicateTable(table ...string) string {
20+
var name string
21+
if len(table) > 0 {
22+
name = table[0]
23+
} else {
24+
name = fmt.Sprintf(`duplicate_table_%d`, gtime.TimestampNano())
25+
}
26+
dropTable(name)
27+
if _, err := db.Exec(ctx, fmt.Sprintf(`
28+
CREATE TABLE %s (
29+
id int(10) unsigned NOT NULL AUTO_INCREMENT,
30+
email varchar(100) NOT NULL,
31+
username varchar(45) NULL,
32+
score int(10) unsigned DEFAULT 0,
33+
login_count int(10) unsigned DEFAULT 0,
34+
PRIMARY KEY (id),
35+
UNIQUE KEY uk_email (email)
36+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
37+
`, name)); err != nil {
38+
gtest.Fatal(err)
39+
}
40+
return name
41+
}
42+
43+
func Test_OnDuplicateKeyUpdate_Basic(t *testing.T) {
44+
table := createDuplicateTable()
45+
defer dropTable(table)
46+
47+
gtest.C(t, func(t *gtest.T) {
48+
// First insert
49+
_, err := db.Exec(ctx, fmt.Sprintf(
50+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
51+
table,
52+
), "user1@example.com", "user1", 100)
53+
t.AssertNil(err)
54+
55+
one, err := db.Model(table).Where("email", "user1@example.com").One()
56+
t.AssertNil(err)
57+
t.Assert(one["username"], "user1")
58+
t.Assert(one["score"], 100)
59+
60+
// Duplicate insert - should update
61+
_, err = db.Exec(ctx, fmt.Sprintf(
62+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
63+
table,
64+
), "user1@example.com", "user1_updated", 200)
65+
t.AssertNil(err)
66+
67+
one, err = db.Model(table).Where("email", "user1@example.com").One()
68+
t.AssertNil(err)
69+
t.Assert(one["username"], "user1_updated")
70+
t.Assert(one["score"], 200)
71+
72+
// Verify only one record exists
73+
count, err := db.Model(table).Count()
74+
t.AssertNil(err)
75+
t.Assert(count, 1)
76+
})
77+
}
78+
79+
func Test_OnDuplicateKeyUpdate_Increment(t *testing.T) {
80+
table := createDuplicateTable()
81+
defer dropTable(table)
82+
83+
gtest.C(t, func(t *gtest.T) {
84+
// First insert
85+
_, err := db.Exec(ctx, fmt.Sprintf(
86+
"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1",
87+
table,
88+
), "user1@example.com", "user1", 1)
89+
t.AssertNil(err)
90+
91+
one, err := db.Model(table).Where("email", "user1@example.com").One()
92+
t.AssertNil(err)
93+
t.Assert(one["login_count"], 1)
94+
95+
// Duplicate - increment login_count
96+
_, err = db.Exec(ctx, fmt.Sprintf(
97+
"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1",
98+
table,
99+
), "user1@example.com", "user1", 1)
100+
t.AssertNil(err)
101+
102+
one, err = db.Model(table).Where("email", "user1@example.com").One()
103+
t.AssertNil(err)
104+
t.Assert(one["login_count"], 2)
105+
106+
// Third time
107+
_, err = db.Exec(ctx, fmt.Sprintf(
108+
"INSERT INTO %s (email, username, login_count) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE login_count = login_count + 1",
109+
table,
110+
), "user1@example.com", "user1", 1)
111+
t.AssertNil(err)
112+
113+
one, err = db.Model(table).Where("email", "user1@example.com").One()
114+
t.AssertNil(err)
115+
t.Assert(one["login_count"], 3)
116+
})
117+
}
118+
119+
func Test_OnDuplicateKeyUpdate_MultipleColumns(t *testing.T) {
120+
table := createDuplicateTable()
121+
defer dropTable(table)
122+
123+
gtest.C(t, func(t *gtest.T) {
124+
// First insert
125+
_, err := db.Exec(ctx, fmt.Sprintf(
126+
"INSERT INTO %s (email, username, score, login_count) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score), login_count = login_count + 1",
127+
table,
128+
), "user1@example.com", "user1", 100, 1)
129+
t.AssertNil(err)
130+
131+
one, err := db.Model(table).Where("email", "user1@example.com").One()
132+
t.AssertNil(err)
133+
t.Assert(one["username"], "user1")
134+
t.Assert(one["score"], 100)
135+
t.Assert(one["login_count"], 1)
136+
137+
// Duplicate - update multiple columns
138+
_, err = db.Exec(ctx, fmt.Sprintf(
139+
"INSERT INTO %s (email, username, score, login_count) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score), login_count = login_count + 1",
140+
table,
141+
), "user1@example.com", "user1_v2", 200, 1)
142+
t.AssertNil(err)
143+
144+
one, err = db.Model(table).Where("email", "user1@example.com").One()
145+
t.AssertNil(err)
146+
t.Assert(one["username"], "user1_v2")
147+
t.Assert(one["score"], 200)
148+
t.Assert(one["login_count"], 2)
149+
})
150+
}
151+
152+
func Test_OnDuplicateKeyUpdate_Batch(t *testing.T) {
153+
table := createDuplicateTable()
154+
defer dropTable(table)
155+
156+
gtest.C(t, func(t *gtest.T) {
157+
// Insert multiple records
158+
_, err := db.Exec(ctx, fmt.Sprintf(
159+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
160+
table,
161+
), "user1@example.com", "user1", 100,
162+
"user2@example.com", "user2", 200,
163+
"user3@example.com", "user3", 300)
164+
t.AssertNil(err)
165+
166+
count, err := db.Model(table).Count()
167+
t.AssertNil(err)
168+
t.Assert(count, 3)
169+
170+
// Update with duplicate - should update specific records
171+
_, err = db.Exec(ctx, fmt.Sprintf(
172+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
173+
table,
174+
), "user1@example.com", "user1_updated", 150,
175+
"user2@example.com", "user2_updated", 250)
176+
t.AssertNil(err)
177+
178+
// Still 3 records
179+
count, err = db.Model(table).Count()
180+
t.AssertNil(err)
181+
t.Assert(count, 3)
182+
183+
// Verify updates
184+
one, err := db.Model(table).Where("email", "user1@example.com").One()
185+
t.AssertNil(err)
186+
t.Assert(one["username"], "user1_updated")
187+
t.Assert(one["score"], 150)
188+
189+
one, err = db.Model(table).Where("email", "user2@example.com").One()
190+
t.AssertNil(err)
191+
t.Assert(one["username"], "user2_updated")
192+
t.Assert(one["score"], 250)
193+
194+
// user3 unchanged
195+
one, err = db.Model(table).Where("email", "user3@example.com").One()
196+
t.AssertNil(err)
197+
t.Assert(one["username"], "user3")
198+
t.Assert(one["score"], 300)
199+
})
200+
}
201+
202+
func Test_OnDuplicateKeyUpdate_ConditionalUpdate(t *testing.T) {
203+
table := createDuplicateTable()
204+
defer dropTable(table)
205+
206+
gtest.C(t, func(t *gtest.T) {
207+
// First insert
208+
_, err := db.Exec(ctx, fmt.Sprintf(
209+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)",
210+
table,
211+
), "user1@example.com", "user1", 100)
212+
t.AssertNil(err)
213+
214+
one, err := db.Model(table).Where("email", "user1@example.com").One()
215+
t.AssertNil(err)
216+
t.Assert(one["score"], 100)
217+
218+
// Try to update with lower score - should not update
219+
_, err = db.Exec(ctx, fmt.Sprintf(
220+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)",
221+
table,
222+
), "user1@example.com", "user1", 50)
223+
t.AssertNil(err)
224+
225+
one, err = db.Model(table).Where("email", "user1@example.com").One()
226+
t.AssertNil(err)
227+
t.Assert(one["score"], 100) // Still 100
228+
229+
// Update with higher score - should update
230+
_, err = db.Exec(ctx, fmt.Sprintf(
231+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE score = IF(VALUES(score) > score, VALUES(score), score)",
232+
table,
233+
), "user1@example.com", "user1", 150)
234+
t.AssertNil(err)
235+
236+
one, err = db.Model(table).Where("email", "user1@example.com").One()
237+
t.AssertNil(err)
238+
t.Assert(one["score"], 150) // Updated to 150
239+
})
240+
}
241+
242+
func Test_OnDuplicateKeyUpdate_WithTransaction(t *testing.T) {
243+
table := createDuplicateTable()
244+
defer dropTable(table)
245+
246+
gtest.C(t, func(t *gtest.T) {
247+
// Transaction with ON DUPLICATE KEY UPDATE
248+
err := db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
249+
// First insert
250+
_, err := tx.Exec(fmt.Sprintf(
251+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
252+
table,
253+
), "user1@example.com", "user1", 100)
254+
if err != nil {
255+
return err
256+
}
257+
258+
// Duplicate in same transaction
259+
_, err = tx.Exec(fmt.Sprintf(
260+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
261+
table,
262+
), "user1@example.com", "user1_updated", 200)
263+
return err
264+
})
265+
t.AssertNil(err)
266+
267+
// Verify final state
268+
one, err := db.Model(table).Where("email", "user1@example.com").One()
269+
t.AssertNil(err)
270+
t.Assert(one["username"], "user1_updated")
271+
t.Assert(one["score"], 200)
272+
273+
count, err := db.Model(table).Count()
274+
t.AssertNil(err)
275+
t.Assert(count, 1)
276+
})
277+
}
278+
279+
func Test_OnDuplicateKeyUpdate_MixedInsertUpdate(t *testing.T) {
280+
table := createDuplicateTable()
281+
defer dropTable(table)
282+
283+
gtest.C(t, func(t *gtest.T) {
284+
// First batch insert
285+
_, err := db.Exec(ctx, fmt.Sprintf(
286+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
287+
table,
288+
), "user1@example.com", "user1", 100,
289+
"user2@example.com", "user2", 200)
290+
t.AssertNil(err)
291+
292+
count, err := db.Model(table).Count()
293+
t.AssertNil(err)
294+
t.Assert(count, 2)
295+
296+
// Mixed batch: one duplicate, one new
297+
_, err = db.Exec(ctx, fmt.Sprintf(
298+
"INSERT INTO %s (email, username, score) VALUES (?, ?, ?), (?, ?, ?) ON DUPLICATE KEY UPDATE username = VALUES(username), score = VALUES(score)",
299+
table,
300+
), "user1@example.com", "user1_updated", 150,
301+
"user3@example.com", "user3", 300)
302+
t.AssertNil(err)
303+
304+
// Should have 3 records now
305+
count, err = db.Model(table).Count()
306+
t.AssertNil(err)
307+
t.Assert(count, 3)
308+
309+
// Verify user1 was updated
310+
one, err := db.Model(table).Where("email", "user1@example.com").One()
311+
t.AssertNil(err)
312+
t.Assert(one["username"], "user1_updated")
313+
t.Assert(one["score"], 150)
314+
315+
// Verify user3 was inserted
316+
one, err = db.Model(table).Where("email", "user3@example.com").One()
317+
t.AssertNil(err)
318+
t.Assert(one["username"], "user3")
319+
t.Assert(one["score"], 300)
320+
})
321+
}

0 commit comments

Comments
 (0)