Skip to content

Commit 7039081

Browse files
authored
db: modify mysql/pg/sqlite interface for pool working (#24780)
1 parent f62b5fd commit 7039081

15 files changed

Lines changed: 214 additions & 21 deletions

File tree

‎examples/database/mysql.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ fn main() {
1313
for row in res.rows() {
1414
println(row.vals.join(', '))
1515
}
16-
conn.close()
16+
conn.close()!
1717
}

‎examples/database/mysql_pool.v‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// vtest build: !(macos || windows)
2+
import db.mysql
3+
import pool
4+
import time
5+
6+
// Define your connection factory function
7+
fn create_conn() !&pool.ConnectionPoolable {
8+
config := mysql.Config{
9+
host: '127.0.0.1'
10+
port: 3306
11+
username: 'root'
12+
password: '12345678'
13+
dbname: 'mysql'
14+
}
15+
db := mysql.connect(config)!
16+
return &db
17+
}
18+
19+
fn main() {
20+
// Configure pool parameters
21+
config := pool.ConnectionPoolConfig{
22+
max_conns: 50
23+
min_idle_conns: 5
24+
max_lifetime: 2 * time.hour
25+
idle_timeout: 30 * time.minute
26+
get_timeout: 5 * time.second
27+
}
28+
29+
// Create connection pool
30+
mut my_pool := pool.new_connection_pool(create_conn, config)!
31+
defer {
32+
// When application exits
33+
my_pool.close()
34+
}
35+
36+
// Acquire connection
37+
mut conn := my_pool.get()!
38+
defer {
39+
// Return connection to pool
40+
my_pool.put(conn) or { println(err) }
41+
}
42+
43+
// Convert `conn` to a `mysql.DB` object
44+
mut db := conn as mysql.DB
45+
46+
assert db.validate()!
47+
48+
mut response := db.exec('drop table if exists users')!
49+
assert response == []mysql.Row{}
50+
51+
response = db.exec('create table if not exists users (
52+
id INT PRIMARY KEY AUTO_INCREMENT,
53+
username TEXT,
54+
last_name TEXT NULL DEFAULT NULL
55+
)')!
56+
assert response == []mysql.Row{}
57+
58+
mut result_code := db.exec_none('insert into users (username) values ("jackson")')
59+
assert result_code == 0
60+
result_code = db.exec_none('insert into users (username) values ("shannon")')
61+
assert result_code == 0
62+
result_code = db.exec_none('insert into users (username) values ("bailey")')
63+
assert result_code == 0
64+
result_code = db.exec_none('insert into users (username) values ("blaze")')
65+
assert result_code == 0
66+
rows := db.exec_param('insert into users (username) values (?)', 'Hi')!
67+
assert rows == []mysql.Row{}
68+
69+
// Regression testing to ensure the query and exec return the same values
70+
res := db.query('select * from users')!
71+
response = res.rows()
72+
assert response[0].vals[1] == 'jackson'
73+
response = db.exec('select * from users')!
74+
assert response[0].vals[1] == 'jackson'
75+
76+
response = db.exec('select * from users where id = 400')!
77+
assert response.len == 0
78+
79+
single_row := db.exec_one('select * from users')!
80+
assert single_row.vals[1] == 'jackson'
81+
82+
response = db.exec_param_many('select * from users where username = ?', [
83+
'jackson',
84+
])!
85+
assert response[0] == mysql.Row{
86+
vals: ['1', 'jackson', '']
87+
}
88+
89+
response = db.exec_param_many('select * from users where username = ? and id = ?',
90+
['bailey', '3'])!
91+
assert response[0] == mysql.Row{
92+
vals: ['3', 'bailey', '']
93+
}
94+
95+
response = db.exec_param_many('select * from users', [''])!
96+
assert response == [
97+
mysql.Row{
98+
vals: ['1', 'jackson', '']
99+
},
100+
mysql.Row{
101+
vals: ['2', 'shannon', '']
102+
},
103+
mysql.Row{
104+
vals: ['3', 'bailey', '']
105+
},
106+
mysql.Row{
107+
vals: ['4', 'blaze', '']
108+
},
109+
mysql.Row{
110+
vals: ['5', 'Hi', '']
111+
},
112+
]
113+
114+
response = db.exec_param('select * from users where username = ?', 'blaze')!
115+
assert response[0] == mysql.Row{
116+
vals: ['4', 'blaze', '']
117+
}
118+
119+
// transaction test
120+
// turn off `autocommit` first
121+
db.autocommit(false)!
122+
// begin a new transaction
123+
db.begin()!
124+
result_code = db.exec_none('insert into users (username) values ("tom")')
125+
assert result_code == 0
126+
// make a savepoint
127+
db.savepoint('savepoint1')!
128+
result_code = db.exec_none('insert into users (username) values ("kitty")')
129+
assert result_code == 0
130+
// rollback to `savepoint1`
131+
db.rollback_to('savepoint1')!
132+
result_code = db.exec_none('insert into users (username) values ("mars")')
133+
assert result_code == 0
134+
db.commit()!
135+
response = db.exec_param_many('select * from users', [''])!
136+
assert response == [
137+
mysql.Row{
138+
vals: ['1', 'jackson', '']
139+
},
140+
mysql.Row{
141+
vals: ['2', 'shannon', '']
142+
},
143+
mysql.Row{
144+
vals: ['3', 'bailey', '']
145+
},
146+
mysql.Row{
147+
vals: ['4', 'blaze', '']
148+
},
149+
mysql.Row{
150+
vals: ['5', 'Hi', '']
151+
},
152+
mysql.Row{
153+
vals: ['6', 'tom', '']
154+
},
155+
mysql.Row{
156+
vals: ['8', 'mars', '']
157+
},
158+
]
159+
}

‎examples/database/orm.v‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn msql_array() ! {
110110
sql db {
111111
drop table Parent
112112
} or {}
113-
db.close()
113+
db.close() or {}
114114
}
115115

116116
db.query('drop table if exists Parent')!
@@ -144,7 +144,7 @@ fn psql_array() ! {
144144
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
145145
defer {
146146
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
147-
db.close()
147+
db.close() or {}
148148
}
149149
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
150150

@@ -219,7 +219,7 @@ fn msql() ! {
219219
defer {
220220
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
221221
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
222-
conn.close()
222+
conn.close() or {}
223223
}
224224
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
225225
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
@@ -253,7 +253,7 @@ fn psql() ! {
253253
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
254254
defer {
255255
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
256-
db.close()
256+
db.close() or {}
257257
}
258258
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
259259
sql db {

‎vlib/db/mysql/mysql.c.v‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,10 @@ pub fn (mut db DB) refresh(options u32) !bool {
330330
}
331331

332332
// reset resets the connection, and clear the session state.
333-
pub fn (mut db DB) reset() !bool {
333+
pub fn (mut db DB) reset() ! {
334334
if C.mysql_reset_connection(db.conn) != 0 {
335335
db.throw_mysql_error()!
336336
}
337-
338-
return true
339337
}
340338

341339
// ping pings a server connection, or tries to reconnect if the connection
@@ -348,8 +346,14 @@ pub fn (mut db DB) ping() !bool {
348346
return true
349347
}
350348

349+
// validate pings a server connection, or tries to reconnect if the connection
350+
// has gone down.
351+
pub fn (mut db DB) validate() !bool {
352+
return db.ping()!
353+
}
354+
351355
// close closes the connection.
352-
pub fn (mut db DB) close() {
356+
pub fn (mut db DB) close() ! {
353357
C.mysql_close(db.conn)
354358
}
355359

‎vlib/db/mysql/mysql_orm_test.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn test_mysql_orm() {
5858
dbname: 'mysql'
5959
)!
6060
defer {
61-
db.close()
61+
db.close() or {}
6262
}
6363
table := orm.Table{
6464
name: 'Test'

‎vlib/db/mysql/mysql_test.v‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ fn test_mysql() {
1616
}
1717

1818
mut db := mysql.connect(config)!
19+
defer {
20+
db.close() or {}
21+
}
22+
23+
assert db.validate()!
1924

2025
mut response := db.exec('drop table if exists users')!
2126
assert response == []mysql.Row{}

‎vlib/db/mysql/pool.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ pub fn (mut pool ConnectionPool) release(conn DB) {
3333
pub fn (mut pool ConnectionPool) close() {
3434
for _ in 0 .. pool.connections.len {
3535
mut conn := <-pool.connections or { break }
36-
conn.close()
36+
conn.close() or { break }
3737
}
3838
}

‎vlib/db/pg/pg.c.v‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ fn res_to_rows(res voidptr) []Row {
224224
}
225225

226226
// close frees the underlying resource allocated by the database connection
227-
pub fn (db &DB) close() {
227+
pub fn (db &DB) close() ! {
228228
C.PQfinish(db.conn)
229229
}
230230

@@ -510,3 +510,13 @@ pub fn (db &DB) savepoint(savepoint string) ! {
510510
return error('pg exec error: "${e}"')
511511
}
512512
}
513+
514+
// validate checks if the connection is still usable
515+
pub fn (db &DB) validate() !bool {
516+
db.exec_one('SELECT 1')!
517+
return true
518+
}
519+
520+
// reset returns the connection to initial state for reuse
521+
pub fn (db &DB) reset() ! {
522+
}

‎vlib/db/pg/pg_double_test.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn test_float_field() {
1919
conn := 'host=localhost user=postgres password=12345678' // insert own connection string
2020
db := pg.connect_with_conninfo(conn)!
2121
defer {
22-
db.close()
22+
db.close() or {}
2323
}
2424

2525
sql db {

‎vlib/db/pg/pg_orm_test.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn test_pg_orm() {
5757
) or { panic(err) }
5858

5959
defer {
60-
db.close()
60+
db.close() or {}
6161
}
6262
table := orm.Table{
6363
name: 'Test'

0 commit comments

Comments
 (0)