Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose sqlstate in the connection and stmt APIs. #42

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bindings/ffi_bindings.ml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ module Bindings (F : Cstubs.FOREIGN) = struct
let mysql_ping = foreign "mysql_ping"
(mysql @-> returning int)

let mysql_sqlstate = foreign "mysql_sqlstate"
(mysql @-> returning string)

let mysql_stmt_prepare = foreign "mysql_stmt_prepare"
(stmt @-> ptr char @-> ulong @-> returning int)

Expand All @@ -317,6 +320,9 @@ module Bindings (F : Cstubs.FOREIGN) = struct
let mysql_stmt_fetch = foreign "mysql_stmt_fetch"
(stmt @-> returning int)

let mysql_stmt_sqlstate = foreign "mysql_stmt_sqlstate"
(stmt @-> returning string)

let mysql_stmt_close = foreign "mysql_stmt_close"
(stmt @-> returning my_bool)

Expand Down
32 changes: 32 additions & 0 deletions examples/blocking/blocking_example.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ let stream res =
try Ok (Stream.from next)
with F.E e -> Error e

let test_sqlstate mariadb =
assert (M.sqlstate mariadb = "00000");
(match M.prepare mariadb "SELECT * FROM inexistent_table" with
| Error _ -> assert (M.sqlstate mariadb <> "00000") (* actually "42S02" *)
| Ok _ -> assert false);
begin
let stmt =
M.prepare mariadb
"CREATE TEMPORARY TABLE test_sqlstate (i integer PRIMARY KEY)"
|> or_die "prepare CREATE TABLE test_sqlstate"
in
let _ =
M.Stmt.execute stmt [||]
|> or_die "exec CREATE TABLE test_sqlstate"
in
M.Stmt.close stmt |> or_die "stmt close CREATE TABLE test_sqlstate"
end;
for i = 0 to 1 do
let stmt =
M.prepare mariadb "INSERT INTO test_sqlstate VALUES (?)"
|> or_die "prepare in test_sqlstate"
in
(match M.Stmt.execute stmt [|`Int 1|] with
| Error (_, msg) ->
assert (i = 1);
assert (M.Stmt.sqlstate stmt <> "00000") (* actually "23000" *)
| Ok _ -> assert (i = 0));

M.Stmt.close stmt |> or_die "stmt close in test_sqlstate"
done

let main () =
let mariadb = connect () |> or_die "connect" in
let query = env "OCAML_MARIADB_QUERY"
Expand All @@ -59,6 +90,7 @@ let main () =
let s = stream res |> or_die "stream" in
Stream.iter print_row s;
M.Stmt.close stmt |> or_die "stmt close";
test_sqlstate mariadb;
M.close mariadb;
M.library_end ();
printf "done\n%!"
Expand Down
4 changes: 4 additions & 0 deletions lib/blocking.ml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ let prepare mariadb query =
| Some raw -> build_stmt raw
| None -> Error (2008, "out of memory")

let sqlstate = Common.sqlstate

module Res = struct
type t = [`Blocking] Common.Res.t

Expand Down Expand Up @@ -198,6 +200,8 @@ module Stmt = struct
else
Error (Common.Stmt.error stmt)

let sqlstate = Common.Stmt.sqlstate

let close stmt =
let raw = stmt.Common.Stmt.raw in
if B.mysql_stmt_free_result raw && B.mysql_stmt_close raw then
Expand Down
6 changes: 6 additions & 0 deletions lib/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ type error = int * string
let error mariadb =
(B.mysql_errno mariadb.raw, B.mysql_error mariadb.raw)

let sqlstate mariadb =
B.mysql_sqlstate mariadb.raw

let int_of_server_option = function
| Multi_statements true -> T.Server_options.multi_statements_on
| Multi_statements false -> T.Server_options.multi_statements_off
Expand Down Expand Up @@ -280,6 +283,9 @@ module Stmt = struct
let error stmt =
(B.mysql_stmt_errno stmt.raw, B.mysql_stmt_error stmt.raw)

let sqlstate stmt =
B.mysql_stmt_sqlstate stmt.raw

let fetch_field res i =
coerce (ptr void) (ptr T.Field.t) (B.mysql_fetch_field_direct res i)

Expand Down
2 changes: 2 additions & 0 deletions lib/mariadb.ml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ module type S = sig

val execute : t -> Field.value array -> Res.t result
val reset : t -> unit result
val sqlstate : t -> string
val close : t -> unit result
end

Expand Down Expand Up @@ -162,6 +163,7 @@ module type S = sig
val commit : t -> unit result
val rollback : t -> unit result
val prepare : t -> string -> Stmt.t result
val sqlstate : t -> string
end

module B = Binding_wrappers
Expand Down
10 changes: 10 additions & 0 deletions lib/mariadb.mli
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ module type S = sig
were after [stmt] was prepared, and frees up any {!Res.t} produced by
[stmt]. *)

val sqlstate : t -> string
(** [sqlstate stmt] is the SQLSTATE with MariaDB extensions indicating the
status of the previous execution of the statement. The string
["00000"] is returned if no error occurred or if the statement has not
been executed. *)

val close : t -> unit result
(** [close stmt] closes the prepapred statement [stmt] and frees
any allocated memory associated with it and its result. *)
Expand Down Expand Up @@ -275,6 +281,10 @@ module type S = sig
(** [prepare mariadb query] creates a prepared statement for [query].
The query may contain [?] as placeholders for parameters that
can be bound by calling [Stmt.execute]. *)

val sqlstate : t -> string
(* [sqlstate mariadb] is the SQLSTATE with MariaDB extensions of the last
* operation on [mariadb]. Returns ["00000"] if no error occurred. *)
end

(** The module for blocking MariaDB API calls. It should be possible to call
Expand Down
4 changes: 4 additions & 0 deletions lib/nonblocking.ml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ let prepare mariadb query =
`Ok (prepare_start mariadb stmt query, prepare_cont mariadb stmt)
| None -> `Error (Common.error mariadb)

let sqlstate = Common.sqlstate

module Res = struct
type t = [`Nonblocking] Common.Res.t

Expand Down Expand Up @@ -344,6 +346,8 @@ module Stmt = struct

let next_result_cont stmt status =
handle_next stmt (B.mysql_stmt_next_result_cont stmt.Common.Stmt.raw status)

let sqlstate = Common.Stmt.sqlstate
end

module type Wait = sig
Expand Down