Skip to content

Commit

Permalink
Mysql.Prepared.execute_null (Gregory Bellier)
Browse files Browse the repository at this point in the history
  • Loading branch information
ygrek committed Nov 16, 2013
1 parent a73fbd0 commit e713d62
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 23 deletions.
3 changes: 3 additions & 0 deletions CHANGES
@@ -1,3 +1,6 @@
* ?
* Mysql.Prepared.execute_null (Gregory Bellier)

* Sat May 19 2012 (1.1.1)
* Support build with ocaml/msvc and ocaml/mingw (Dmitry Grebeniuk)
* Update build tools (Dmitry Grebeniuk)
Expand Down
24 changes: 13 additions & 11 deletions demo2.ml
Expand Up @@ -9,19 +9,22 @@ module P = Mysql.Prepared
Verify safe GC interaction (see CAML_TEST_GC_SAFE in mysql_stubs.c)
For such test need strings on heap, not statically allocated atoms, hence String.copy
*)
let _ = Thread.create (fun () ->
let (_:Thread.t) = Thread.create (fun () ->
let i = ref 0 in
while true do Gc.compact(); incr i; if !i mod 100 = 0 then (print_char '.'; flush stdout) done) ()

let s = String.copy

let db = Mysql.quick_connect ~database:(s "test") ~user:(s "root") ()

let _ = Mysql.exec db (s "CREATE TABLE IF NOT EXISTS test(id INT) ENGINE=MEMORY")
let (_:Mysql.result) = Mysql.exec db (s "CREATE TABLE test(id INT, v VARCHAR(10)) ENGINE=MEMORY")
let () =
let insert = P.create db (s "INSERT INTO test VALUES (?)") in
for i = 10 to 20 do
ignore (P.execute insert [|string_of_int i|])
let insert = P.create db (s "INSERT INTO test VALUES (?,?)") in
for i = 10 to 15 do
ignore (P.execute insert [|string_of_int i; sprintf "value %d" i|])
done;
for i = 16 to 20 do
ignore (P.execute_null insert [|Some (string_of_int i); None|])
done;
P.close insert

Expand All @@ -32,17 +35,16 @@ let () =
| None -> ()
in
let select = P.create db (s "SELECT * FROM test WHERE id > ?") in
print_endline "> 15";
loop (P.execute select [|s "15"|]);
print_endline "> 20";
loop (P.execute select [|s "20"|]);
print_endline "> 13";
loop (P.execute select [|s "13"|]);
print_endline "> 19";
loop (P.execute select [|s "19"|]);
print_endline "> 20";
loop (P.execute select [|s "20"|]);
P.close select;
print_endline "done all";
()

let _ = Mysql.exec db (s "DROP TABLE test")
let (_:Mysql.result) = Mysql.exec db (s "DROP TABLE test")

let () = Mysql.disconnect db

1 change: 1 addition & 0 deletions mysql.ml
Expand Up @@ -638,6 +638,7 @@ type stmt_result

external create : dbd -> string -> stmt = "caml_mysql_stmt_prepare"
external execute : stmt -> string array -> stmt_result = "caml_mysql_stmt_execute"
external execute_null : stmt -> string option array -> stmt_result = "caml_mysql_stmt_execute_null"
external affected : stmt -> int64 = "caml_mysql_stmt_affected"
external insert_id : stmt -> int64 = "caml_mysql_stmt_insert_id"
external real_status : stmt -> int = "caml_mysql_stmt_status"
Expand Down
3 changes: 3 additions & 0 deletions mysql.mli
Expand Up @@ -377,6 +377,9 @@ val create : dbd -> string -> stmt
(** Execute the prepared statement with the specified values for parameters. *)
val execute : stmt -> string array -> stmt_result

(** Same as {!execute}, but with support for NULL values. *)
val execute_null : stmt -> string option array -> stmt_result

(** @return Number of rows affected by the last execution of this statement. *)
val affected : stmt -> int64

Expand Down
46 changes: 34 additions & 12 deletions mysql_stubs.c
Expand Up @@ -965,15 +965,25 @@ row_t* create_row(MYSQL_STMT* stmt, size_t count)
return row;
}

void set_param(row_t *r, char* str, size_t len, int index)
void set_param_string(row_t *r, value v, int index)
{
MYSQL_BIND* bind = &r->bind[index];
size_t len = caml_string_length(v);

r->length[index] = len;
bind->length = &r->length[index];
bind->buffer_length = len;
bind->buffer_type = MYSQL_TYPE_STRING;
bind->buffer = (void*)str;
bind->buffer = malloc(len);
memcpy(bind->buffer, String_val(v), len);
}

void set_param_null(row_t *r, int index)
{
MYSQL_BIND* bind = &r->bind[index];

bind->buffer_type = MYSQL_TYPE_NULL;
bind->buffer = NULL;
}

void bind_result(row_t* r, int index)
Expand Down Expand Up @@ -1044,45 +1054,47 @@ struct custom_operations stmt_result_ops = {
#endif
};

EXTERNAL value
caml_mysql_stmt_execute(value v_stmt, value v_params)
value
caml_mysql_stmt_execute_gen(value v_stmt, value v_params, int with_null)
{
CAMLparam2(v_stmt,v_params);
CAMLlocal2(res,v);
unsigned int i = 0;
unsigned int len = Wosize_val(v_params);
int err = 0;
char* bufs[256];
row_t* row = NULL;
MYSQL_STMT* stmt = STMTval(v_stmt);
check_stmt(stmt,"execute");
if (len != mysql_stmt_param_count(stmt))
mysqlfailmsg("Prepared.execute : Got %i parameters, but expected %i", len, mysql_stmt_param_count(stmt));
if (len > 256)
mysqlfailwith("Prepared.execute : too many parameters");
row = create_row(stmt, len);
if (!row)
mysqlfailwith("Prepared.execute : create_row for params");
for (i = 0; i < len; i++)
{
v = Field(v_params,i);
bufs[i] = malloc(caml_string_length(v));
memcpy(bufs[i],String_val(v),caml_string_length(v));
set_param(row,bufs[i],caml_string_length(v),i);
if (with_null)
if (Val_none == v)
set_param_null(row, i);
else
set_param_string(row, Some_val(v), i);
else
set_param_string(row, v, i);
}
err = mysql_stmt_bind_param(stmt, row->bind);
if (err)
{
for (i = 0; i < len; i++) free(row->bind[i].buffer);
destroy_row(row);
for (i = 0; i < len; i++) free(bufs[i]);
mysqlfailmsg("Prepared.execute : mysql_stmt_bind_param = %i",err);
}
caml_enter_blocking_section();
err = mysql_stmt_execute(stmt);
caml_leave_blocking_section();

for (i = 0; i < len; i++) free(row->bind[i].buffer);
destroy_row(row);
for (i = 0; i < len; i++) free(bufs[i]);

if (err)
{
mysqlfailmsg("Prepared.execute : mysql_stmt_execute = %i, %s",err,mysql_stmt_error(stmt));
Expand All @@ -1109,6 +1121,16 @@ caml_mysql_stmt_execute(value v_stmt, value v_params)
CAMLreturn(res);
}

EXTERNAL value caml_mysql_stmt_execute(value v_stmt, value v_param)
{
return caml_mysql_stmt_execute_gen(v_stmt, v_param, 0);
}

EXTERNAL value caml_mysql_stmt_execute_null(value v_stmt, value v_param)
{
return caml_mysql_stmt_execute_gen(v_stmt, v_param, 1);
}

EXTERNAL value
caml_mysql_stmt_fetch(value result)
{
Expand Down

0 comments on commit e713d62

Please sign in to comment.