Skip to content

Commit c45933f

Browse files
committed
Expose sqlstate in the connection and stmt APIs.
1 parent 572396b commit c45933f

File tree

7 files changed

+75
-0
lines changed

7 files changed

+75
-0
lines changed

Diff for: bindings/ffi_bindings.ml

+6
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ module Functions (F : Ctypes.FOREIGN) = struct
320320
let mysql_get_proto_info = foreign "mysql_get_proto_info"
321321
(mysql @-> returning uint)
322322

323+
let mysql_sqlstate = foreign "mysql_sqlstate"
324+
(mysql @-> returning string)
325+
323326
let mysql_stmt_prepare = foreign "mysql_stmt_prepare"
324327
(stmt @-> ptr char @-> ulong @-> returning int)
325328

@@ -332,6 +335,9 @@ module Functions (F : Ctypes.FOREIGN) = struct
332335
let mysql_stmt_fetch = foreign "mysql_stmt_fetch"
333336
(stmt @-> returning int)
334337

338+
let mysql_stmt_sqlstate = foreign "mysql_stmt_sqlstate"
339+
(stmt @-> returning string)
340+
335341
let mysql_stmt_close = foreign "mysql_stmt_close"
336342
(stmt @-> returning my_bool)
337343

Diff for: lib/blocking.ml

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ let prepare mariadb query =
158158
let start_txn mariadb =
159159
wrap_unit mariadb (B.mysql_real_query mariadb.Common.raw "START TRANSACTION")
160160

161+
let sqlstate = Common.sqlstate
162+
161163
module Res = struct
162164
type t = [`Blocking] Common.Res.t
163165

@@ -208,6 +210,8 @@ module Stmt = struct
208210
else
209211
Error (Common.Stmt.error stmt)
210212

213+
let sqlstate = Common.Stmt.sqlstate
214+
211215
let close stmt =
212216
Common.Stmt.free_meta stmt;
213217
let raw = stmt.Common.Stmt.raw in

Diff for: lib/common.ml

+6
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ type error = int * string
8585
let error mariadb =
8686
(B.mysql_errno mariadb.raw, B.mysql_error mariadb.raw)
8787

88+
let sqlstate mariadb =
89+
B.mysql_sqlstate mariadb.raw
90+
8891
let int_of_server_option = function
8992
| Multi_statements true -> T.Server_options.multi_statements_on
9093
| Multi_statements false -> T.Server_options.multi_statements_off
@@ -295,6 +298,9 @@ module Stmt = struct
295298
let error stmt =
296299
(B.mysql_stmt_errno stmt.raw, B.mysql_stmt_error stmt.raw)
297300

301+
let sqlstate stmt =
302+
B.mysql_stmt_sqlstate stmt.raw
303+
298304
let fetch_field res i =
299305
coerce (ptr void) (ptr T.Field.t) (B.mysql_fetch_field_direct res i)
300306

Diff for: lib/mariadb.ml

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ module type S = sig
8080

8181
val execute : t -> Field.value array -> Res.t result
8282
val reset : t -> unit result
83+
val sqlstate : t -> string
8384
val close : t -> unit result
8485
end
8586

@@ -168,6 +169,7 @@ module type S = sig
168169
val commit : t -> unit result
169170
val rollback : t -> unit result
170171
val prepare : t -> string -> Stmt.t result
172+
val sqlstate : t -> string
171173
end
172174

173175
module B = Binding_wrappers

Diff for: lib/mariadb.mli

+12
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ module type S = sig
160160
were after [stmt] was prepared, and frees up any {!Res.t} produced by
161161
[stmt]. *)
162162

163+
val sqlstate : t -> string
164+
(** [sqlstate stmt] is the SQLSTATE with MariaDB extensions indicating the
165+
status of the previous execution of the statement. The string
166+
["00000"] is returned if no error occurred or if the statement has not
167+
been executed. *)
168+
163169
val close : t -> unit result
164170
(** [close stmt] closes the prepapred statement [stmt] and frees any
165171
allocated memory associated with it and its result. *)
@@ -294,6 +300,10 @@ module type S = sig
294300
(** [prepare mariadb query] creates a prepared statement for [query]. The
295301
query may contain [?] as placeholders for parameters that can be bound
296302
by calling [Stmt.execute]. *)
303+
304+
val sqlstate : t -> string
305+
(* [sqlstate mariadb] is the SQLSTATE with MariaDB extensions of the last
306+
* operation on [mariadb]. Returns ["00000"] if no error occurred. *)
297307
end
298308

299309
(** The module for blocking MariaDB API calls. It should be possible to call
@@ -449,6 +459,7 @@ module Nonblocking : sig
449459

450460
val execute : t -> Field.value array -> Res.t result future
451461
val reset : t -> unit result future
462+
val sqlstate : t -> string
452463
val close : t -> unit result future
453464
end
454465

@@ -538,6 +549,7 @@ module Nonblocking : sig
538549
val commit : t -> unit result future
539550
val rollback : t -> unit result future
540551
val prepare : t -> string -> Stmt.t result future
552+
val sqlstate : t -> string
541553
end
542554

543555
(** Functor that generates a nonblocking database interface, given a

Diff for: lib/nonblocking.ml

+6
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ module type S = sig
449449

450450
val execute : t -> Field.value array -> Res.t result future
451451
val reset : t -> unit result future
452+
val sqlstate : t -> string
452453
val close : t -> unit result future
453454
end
454455

@@ -537,6 +538,7 @@ module type S = sig
537538
val commit : t -> unit result future
538539
val rollback : t -> unit result future
539540
val prepare : t -> string -> Stmt.t result future
541+
val sqlstate : t -> string
540542
end
541543

542544
module Make (W : Wait) : S with type 'a future = 'a W.IO.future = struct
@@ -676,6 +678,8 @@ module Make (W : Wait) : S with type 'a future = 'a W.IO.future = struct
676678
>>= function
677679
| Ok () -> nonblocking stmt.Common.Stmt.mariadb (Stmt.close stmt)
678680
| Error _ as e -> return e
681+
682+
let sqlstate = Common.Stmt.sqlstate
679683
end
680684

681685
let connect ?host ?user ?pass ?db ?(port=0) ?socket ?(flags=[]) ?(options=[]) () =
@@ -742,4 +746,6 @@ module Make (W : Wait) : S with type 'a future = 'a W.IO.future = struct
742746
match prepare m q with
743747
| `Ok nb -> nonblocking m nb
744748
| `Error e -> return (Error e)
749+
750+
let sqlstate = Common.sqlstate
745751
end

Diff for: tests/nonblocking/nonblocking_testsuite.ml

+39
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ struct
2222
| Ok r -> return r
2323
| Error (i, e) -> eprintf "%s: (%d) %s\n%!" where i e; exit 2
2424

25+
let then_die where = function
26+
| Ok _ -> eprintf "unexpected ok: %s" where; exit 2
27+
| Error _ -> return ()
28+
2529
let rec iter_s_list f = function
2630
| [] -> return ()
2731
| x :: xs -> f x >>= fun () -> iter_s_list f xs
@@ -154,6 +158,40 @@ struct
154158
assert (proto >= 0 && proto < 10000); (* it's 10 for MariaDB 10.11.8 *)
155159
return ()
156160

161+
let test_sqlstate () =
162+
connect () >>= or_die "connect" >>= fun dbh ->
163+
assert (M.sqlstate dbh = "00000");
164+
165+
(* Test select from missing table. *)
166+
(M.prepare dbh "SELECT * FROM inexistent_table" >|= function
167+
| Error _ -> assert (M.sqlstate dbh <> "00000") (* actually "42S02" *)
168+
| Ok _ -> assert false) >>= fun () ->
169+
170+
(* Prepare table for testing. *)
171+
M.prepare dbh
172+
"CREATE TEMPORARY TABLE test_sqlstate (i integer PRIMARY KEY)"
173+
>>= or_die "prepare CREATE TABLE test_sqlstate"
174+
>>= fun stmt ->
175+
M.Stmt.execute stmt [||]
176+
>>= or_die "exec CREATE TABLE test_sqlstate"
177+
>>= fun _ ->
178+
M.Stmt.close stmt
179+
>>= or_die "stmt close CREATE TABLE test_sqlstate"
180+
>>= fun () ->
181+
182+
(* Test duplicate insertion of unique key. *)
183+
M.prepare dbh "INSERT INTO test_sqlstate VALUES (?)"
184+
>>= or_die "prepare in test_sqlstate"
185+
>>= fun stmt ->
186+
M.Stmt.execute stmt [|`Int 1|]
187+
>>= or_die "first insert in test_sqlstate"
188+
>>= fun _ ->
189+
M.Stmt.execute stmt [|`Int 1|]
190+
>>= then_die "second insert in test_sqlstate"
191+
>>= fun () ->
192+
assert (M.Stmt.sqlstate stmt <> "00000"); (* actually "23000" *)
193+
M.Stmt.close stmt >>= or_die "stmt close in test_sqlstate"
194+
157195
let test_insert_id () =
158196
connect () >>= or_die "connect" >>= fun dbh ->
159197
M.prepare dbh
@@ -344,6 +382,7 @@ struct
344382

345383
let main () =
346384
test_server_properties () >>= fun () ->
385+
test_sqlstate () >>= fun () ->
347386
test_insert_id () >>= fun () ->
348387
test_txn () >>= fun () ->
349388
test_many_select () >>= fun () ->

0 commit comments

Comments
 (0)