v / vlib / db / mysql / mysql_test.v
247 lines · 222 sloc · 6.75 KB · 5ec8c10c31cb67d9ca9ab7036f96bf547dbae66e
Raw
1// vtest build: started_mysqld?
2import db.mysql
3import orm
4
5fn test_mysql() {
6 $if !network ? {
7 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
8 eprintln('> This test requires a working mysql server running on localhost.')
9 return
10 }
11 config := mysql.Config{
12 host: '127.0.0.1'
13 port: 3306
14 username: 'root'
15 password: '12345678'
16 dbname: 'mysql'
17 }
18
19 mut db := mysql.connect(config)!
20 defer {
21 db.close() or {}
22 }
23
24 assert db.validate()!
25
26 mut conn := orm.TransactionalConnection(db)
27 mut tx := orm.begin(mut conn)!
28 tx.transaction[int](fn (mut tx orm.Tx) !int {
29 return 1
30 })!
31 tx.commit()!
32
33 mut response := db.exec('drop table if exists users')!
34 assert response == []mysql.Row{}
35
36 response = db.exec('create table if not exists users (
37 id INT PRIMARY KEY AUTO_INCREMENT,
38 username TEXT,
39 last_name TEXT NULL DEFAULT NULL
40 )')!
41 assert response == []mysql.Row{}
42
43 mut result_code := db.exec_none('insert into users (username) values ("jackson")')
44 assert result_code == 0
45 result_code = db.exec_none('insert into users (username) values ("shannon")')
46 assert result_code == 0
47 result_code = db.exec_none('insert into users (username) values ("bailey")')
48 assert result_code == 0
49 result_code = db.exec_none('insert into users (username) values ("blaze")')
50 assert result_code == 0
51 rows := db.exec_param('insert into users (username) values (?)', 'Hi')!
52 assert rows == []mysql.Row{}
53
54 // Regression testing to ensure the query and exec return the same values
55 res := db.query('select * from users')!
56 response = res.rows()
57 assert response[0].vals[1] == 'jackson'
58 response = db.exec('select * from users')!
59 assert response[0].vals[1] == 'jackson'
60
61 response = db.exec('select * from users where id = 400')!
62 assert response.len == 0
63
64 single_row := db.exec_one('select * from users')!
65 assert single_row.vals[1] == 'jackson'
66
67 response = db.exec_param_many('select * from users where username = ?', [
68 'jackson',
69 ])!
70 assert response[0] == mysql.Row{
71 vals: ['1', 'jackson', '']
72 }
73
74 response = db.exec_param_many('select * from users where username = ? and id = ?', [
75 'bailey',
76 '3',
77 ])!
78 assert response[0] == mysql.Row{
79 vals: ['3', 'bailey', '']
80 }
81
82 response = db.exec_param_many('select * from users', [''])!
83 assert response == [
84 mysql.Row{
85 vals: ['1', 'jackson', '']
86 },
87 mysql.Row{
88 vals: ['2', 'shannon', '']
89 },
90 mysql.Row{
91 vals: ['3', 'bailey', '']
92 },
93 mysql.Row{
94 vals: ['4', 'blaze', '']
95 },
96 mysql.Row{
97 vals: ['5', 'Hi', '']
98 },
99 ]
100
101 response = db.exec_param('select * from users where username = ?', 'blaze')!
102 assert response[0] == mysql.Row{
103 vals: ['4', 'blaze', '']
104 }
105
106 // transaction test
107 // turn off `autocommit` first
108 db.autocommit(false)!
109 // begin a new transaction
110 db.begin()!
111 result_code = db.exec_none('insert into users (username) values ("tom")')
112 assert result_code == 0
113 // make a savepoint
114 db.savepoint('savepoint1')!
115 result_code = db.exec_none('insert into users (username) values ("kitty")')
116 assert result_code == 0
117 // rollback to `savepoint1`
118 db.rollback_to('savepoint1')!
119 result_code = db.exec_none('insert into users (username) values ("mars")')
120 assert result_code == 0
121 db.commit()!
122 response = db.exec_param_many('select * from users', [''])!
123 assert response == [
124 mysql.Row{
125 vals: ['1', 'jackson', '']
126 },
127 mysql.Row{
128 vals: ['2', 'shannon', '']
129 },
130 mysql.Row{
131 vals: ['3', 'bailey', '']
132 },
133 mysql.Row{
134 vals: ['4', 'blaze', '']
135 },
136 mysql.Row{
137 vals: ['5', 'Hi', '']
138 },
139 mysql.Row{
140 vals: ['6', 'tom', '']
141 },
142 mysql.Row{
143 vals: ['8', 'mars', '']
144 },
145 ]
146}
147
148fn test_mysql_multi_statements() {
149 $if !network ? {
150 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
151 eprintln('> This test requires a working mysql server running on localhost.')
152 return
153 }
154 config := mysql.Config{
155 host: '127.0.0.1'
156 port: 3306
157 username: 'root'
158 password: '12345678'
159 dbname: 'mysql'
160 flag: mysql.ConnectionFlag.client_multi_statements
161 }
162
163 mut db := mysql.connect(config)!
164 defer {
165 db.close() or {}
166 }
167
168 // exec_multi drains every result set so the connection stays usable.
169 results := db.exec_multi('SELECT 1 AS a; SELECT 2 AS b; SELECT 3 AS c')!
170 assert results.len == 3
171 assert results[0][0].val(0) == '1'
172 assert results[1][0].val(0) == '2'
173 assert results[2][0].val(0) == '3'
174
175 // The connection must remain reusable afterwards: regression test for #18061.
176 follow_up := db.query('SELECT 42')!
177 rows := follow_up.rows()
178 assert rows[0].val(0) == '42'
179
180 // Low-level drain via more_results/next_result/store_result also works.
181 first := db.query('SELECT 10; SELECT 20')!
182 assert first.rows()[0].val(0) == '10'
183 unsafe { first.free() }
184 assert db.more_results() == true
185 assert db.next_result()! == true
186 second := db.store_result()!
187 assert second.rows()[0].val(0) == '20'
188 unsafe { second.free() }
189 assert db.next_result()! == false
190 // After draining, new queries succeed (no "Commands out of sync" error).
191 final := db.query('SELECT 99')!
192 assert final.rows()[0].val(0) == '99'
193
194 // Regression test for #18063: every statement in a multi-statement query
195 // must complete on the server before exec_multi() returns, so that the
196 // next query can immediately rely on its side effects (e.g. tables).
197 _ := db.exec_multi('DROP TABLE IF EXISTS multi_a;
198 DROP TABLE IF EXISTS multi_b;
199 CREATE TABLE multi_a (id INT PRIMARY KEY);
200 CREATE TABLE multi_b (id INT PRIMARY KEY);
201 INSERT INTO multi_a (id) VALUES (1), (2);
202 INSERT INTO multi_b (id) VALUES (10), (20), (30);')!
203 count_a := db.query('SELECT COUNT(*) FROM multi_a')!.rows()
204 count_b := db.query('SELECT COUNT(*) FROM multi_b')!.rows()
205 assert count_a[0].val(0) == '2'
206 assert count_b[0].val(0) == '3'
207 db.exec_none('DROP TABLE IF EXISTS multi_a')
208 db.exec_none('DROP TABLE IF EXISTS multi_b')
209}
210
211fn mysql_query_count_from_shared_connection(db mysql.DB) !int {
212 result := db.query('SELECT COUNT(*) as table_count FROM information_schema.tables')!
213 rows := result.maps()
214 return rows[0]['table_count'].int()
215}
216
217fn test_query_is_serialized_for_shared_connections() {
218 $if !network ? {
219 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
220 eprintln('> This test requires a working mysql server running on localhost.')
221 return
222 }
223 config := mysql.Config{
224 host: '127.0.0.1'
225 port: 3306
226 username: 'root'
227 password: '12345678'
228 dbname: 'mysql'
229 }
230
231 mut db := mysql.connect(config)!
232 defer {
233 db.close() or {}
234 }
235
236 threads := [
237 spawn mysql_query_count_from_shared_connection(db),
238 spawn mysql_query_count_from_shared_connection(db),
239 spawn mysql_query_count_from_shared_connection(db),
240 spawn mysql_query_count_from_shared_connection(db),
241 ]
242 results := threads.wait()!
243 assert results.len == 4
244 for count in results {
245 assert count > 0
246 }
247}
248