Skip to content

Commit 2a66fa6

Browse files
committed
Add send_describe_prepared and send_describe_portal and test.
1 parent fd9c672 commit 2a66fa6

File tree

7 files changed

+171
-4
lines changed

7 files changed

+171
-4
lines changed

_oasis

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ Flag examples
4444
Description: Build examples
4545
Default: true
4646

47+
Executable async
48+
Path: examples
49+
MainIs: async.ml
50+
Build$: flag(examples)
51+
BuildDepends: postgresql
52+
Install: false
53+
CompiledObject: best
54+
4755
Executable cursor
4856
Path: examples
4957
MainIs: cursor.ml

_tags

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# OASIS_START
2-
# DO NOT EDIT (digest: 13a07b9ae83498d4d812e34d9fb75898)
2+
# DO NOT EDIT (digest: d32380a8a5d9af5342a2f383d8fb4575)
33
# Ignore VCS directories, you can use the same kind of rule outside
44
# OASIS_START/STOP if you want to exclude directories that contains
55
# useless stuff for the build process
@@ -27,6 +27,10 @@
2727
<lib/*.ml{,i}>: pkg_threads
2828
"lib/postgresql_stubs.c": pkg_bigarray
2929
"lib/postgresql_stubs.c": pkg_threads
30+
# Executable async
31+
<examples/async.{native,byte}>: pkg_bigarray
32+
<examples/async.{native,byte}>: pkg_threads
33+
<examples/async.{native,byte}>: use_postgresql
3034
# Executable cursor
3135
<examples/cursor.{native,byte}>: pkg_bigarray
3236
<examples/cursor.{native,byte}>: pkg_threads

examples/async.ml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
open Postgresql
2+
3+
let _ =
4+
if Array.length Sys.argv <> 2 then (
5+
Printf.printf "\
6+
Usage: async conninfo\n\
7+
Connect to PostgreSQL with [conninfo] (e.g. \"host=localhost\"),\n\
8+
and run async tests on a temporary table\n";
9+
exit 1)
10+
11+
let wait_for_result c =
12+
c#consume_input;
13+
while c#is_busy do
14+
ignore (Unix.select [Obj.magic c#socket] [] [] (-.1.0));
15+
c#consume_input
16+
done
17+
18+
let fetch_result c = wait_for_result c; c#get_result
19+
20+
let fetch_single_result c =
21+
match fetch_result c with
22+
| None -> assert false
23+
| Some r -> assert (fetch_result c = None); r
24+
25+
let main () =
26+
let c = new connection ~conninfo:Sys.argv.(1) () in
27+
c#set_nonblocking true;
28+
c#send_query "\
29+
CREATE TEMPORARY TABLE postgresql_ocaml_async \
30+
(id SERIAL PRIMARY KEY, a INTEGER NOT NULL, b TEXT NOT NULL)";
31+
assert ((fetch_single_result c)#status = Command_ok);
32+
c#send_prepare "test_ins"
33+
"INSERT INTO postgresql_ocaml_async (a, b) VALUES ($1, $2)";
34+
assert ((fetch_single_result c)#status = Command_ok);
35+
c#send_query_prepared ~params:[|"2"; "two"|] "test_ins";
36+
assert ((fetch_single_result c)#status = Command_ok);
37+
c#send_query_prepared ~params:[|"3"; "three"|] "test_ins";
38+
assert ((fetch_single_result c)#status = Command_ok);
39+
c#send_prepare "test_sel" "SELECT * FROM postgresql_ocaml_async";
40+
assert ((fetch_single_result c)#status = Command_ok);
41+
c#send_describe_prepared "test_sel";
42+
let r = fetch_single_result c in
43+
assert (r#status = Command_ok);
44+
assert (r#nfields = 3);
45+
assert (r#fname 0 = "id");
46+
assert (r#fname 1 = "a");
47+
assert (r#fname 2 = "b");
48+
c#send_query_prepared "test_sel";
49+
let r = fetch_single_result c in
50+
assert (r#status = Tuples_ok);
51+
assert (r#ntuples = 2);
52+
assert (r#nfields = 3);
53+
for i = 0 to r#ntuples - 1 do
54+
Printf.printf "%s %s %s\n"
55+
(r#getvalue i 0) (r#getvalue i 1) (r#getvalue i 2)
56+
done
57+
58+
let _ =
59+
try main () with
60+
| Error e -> prerr_endline (string_of_error e)
61+
| e -> prerr_endline (Printexc.to_string e)

lib/postgresql.ml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,12 @@ module Stub = struct
400400
connection -> string -> string array -> bool array -> int
401401
= "PQsendQueryPrepared_stub"
402402

403+
external send_describe_prepared : connection -> string -> int
404+
= "PQsendDescribePrepared_stub"
405+
406+
external send_describe_portal : connection -> string -> int
407+
= "PQsendDescribePortal_stub"
408+
403409
external get_result : connection -> result = "PQgetResult_stub"
404410
external consume_input : connection -> int = "PQconsumeInput_stub" "noalloc"
405411
external is_busy : connection -> bool = "PQisBusy_stub" "noalloc"
@@ -803,6 +809,16 @@ object (self)
803809
if Stub.send_query_prepared conn stm_name params binary_params <> 1 then
804810
signal_error conn)
805811

812+
method send_describe_prepared stm_name =
813+
wrap_conn (fun conn ->
814+
if Stub.send_describe_prepared conn stm_name <> 1 then
815+
signal_error conn)
816+
817+
method send_describe_portal portal_name =
818+
wrap_conn (fun conn ->
819+
if Stub.send_describe_portal conn portal_name <> 1 then
820+
signal_error conn)
821+
806822
method get_result =
807823
let res = wrap_conn Stub.get_result in
808824
if Stub.result_isnull res then None else Some (new result res)

lib/postgresql.mli

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,20 @@ object
617617
618618
@raise Error if there is a connection error. *)
619619

620+
method send_describe_prepared : string -> unit
621+
(** [#send_describe_prepared stm_name] sends an request for a description of
622+
a prepared query without waiting for the result. The result must be
623+
fetched with {!get_result} when it becomes available, otherwise does the
624+
same as {!describe_prepared}.
625+
626+
@raise Error if there is a connection error. *)
627+
628+
method send_describe_portal : string -> unit
629+
(** [#send_describe_portal portal_name] send a request for a description of
630+
the named portal. The result must be fetched with {!get_result}.
631+
632+
@raise Error if there is a connection error. *)
633+
620634
method get_result : result option
621635
(** [get_result] @return [Some result] of an asynchronous query if
622636
available or [None].

lib/postgresql_stubs.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,42 @@ CAMLprim value PQsendQueryPrepared_stub(
781781
return Val_int(res);
782782
}
783783

784+
#ifdef PG_OCAML_8_2
785+
CAMLprim value PQsendDescribePrepared_stub(value v_conn, value v_stm_name)
786+
{
787+
PGconn *conn = get_conn(v_conn);
788+
const char *stm_name = String_val(v_stm_name);
789+
int res;
790+
res = PQsendDescribePrepared(conn, stm_name);
791+
return Val_int(res);
792+
}
793+
#else
794+
CAMLprim value
795+
PQsendDescribePrepared_stub(value __unused v_conn, value __unused v_stm_name)
796+
{
797+
caml_failwith("Postgresql.send_describe_prepared: not supported");
798+
return Val_unit;
799+
}
800+
#endif
801+
802+
#ifdef PG_OCAML_8_2
803+
CAMLprim value PQsendDescribePortal_stub(value v_conn, value v_portal_name)
804+
{
805+
PGconn *conn = get_conn(v_conn);
806+
const char *portal_name = String_val(v_portal_name);
807+
int res;
808+
res = PQsendDescribePortal(conn, portal_name);
809+
return Val_int(res);
810+
}
811+
#else
812+
CAMLprim value
813+
PQsendDescribePortal_stub(value __unused v_conn, value __unused v_portal_name)
814+
{
815+
caml_failwith("Postgresql.send_describe_portal: not supported");
816+
return Val_unit;
817+
}
818+
#endif
819+
784820
CAMLprim value PQgetResult_stub(value v_conn)
785821
{
786822
CAMLparam1(v_conn);

setup.ml

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(* setup.ml generated for the first time by OASIS v0.3.0 *)
22

33
(* OASIS_START *)
4-
(* DO NOT EDIT (digest: d41f7ff08798140dc9456eed5004bfce) *)
4+
(* DO NOT EDIT (digest: aa122ef477f44c66f8a7e36890f9c528) *)
55
(*
66
Regenerated by OASIS v0.4.4
77
Visit http://oasis.forge.ocamlcore.org for more information and
@@ -6791,6 +6791,34 @@ let setup_t =
67916791
flag_description = Some "Build examples";
67926792
flag_default = [(OASISExpr.EBool true, true)]
67936793
});
6794+
Executable
6795+
({
6796+
cs_name = "async";
6797+
cs_data = PropList.Data.create ();
6798+
cs_plugin_data = []
6799+
},
6800+
{
6801+
bs_build =
6802+
[
6803+
(OASISExpr.EBool true, false);
6804+
(OASISExpr.EFlag "examples", true)
6805+
];
6806+
bs_install = [(OASISExpr.EBool true, false)];
6807+
bs_path = "examples";
6808+
bs_compiled_object = Best;
6809+
bs_build_depends = [InternalLibrary "postgresql"];
6810+
bs_build_tools =
6811+
[ExternalTool "ocamldoc"; ExternalTool "ocamlbuild"];
6812+
bs_c_sources = [];
6813+
bs_data_files = [];
6814+
bs_ccopt = [(OASISExpr.EBool true, [])];
6815+
bs_cclib = [(OASISExpr.EBool true, [])];
6816+
bs_dlllib = [(OASISExpr.EBool true, [])];
6817+
bs_dllpath = [(OASISExpr.EBool true, [])];
6818+
bs_byteopt = [(OASISExpr.EBool true, [])];
6819+
bs_nativeopt = [(OASISExpr.EBool true, [])]
6820+
},
6821+
{exec_custom = false; exec_main_is = "async.ml"});
67946822
Executable
67956823
({
67966824
cs_name = "cursor";
@@ -7035,14 +7063,14 @@ let setup_t =
70357063
};
70367064
oasis_fn = Some "_oasis";
70377065
oasis_version = "0.4.4";
7038-
oasis_digest = Some "Ö%uûfÂ$¦\157c>Ä8Þ+æ";
7066+
oasis_digest = Some "\207)\157;|\179\018\"\237OJ\209\030\208f\158";
70397067
oasis_exec = None;
70407068
oasis_setup_args = [];
70417069
setup_update = false
70427070
};;
70437071

70447072
let setup () = BaseSetup.setup setup_t;;
70457073

7046-
# 7047 "setup.ml"
7074+
# 7075 "setup.ml"
70477075
(* OASIS_STOP *)
70487076
let () = setup ();;

0 commit comments

Comments
 (0)