This is an automated email from the git hooks/post-receive script. glondu pushed a commit to branch master in repository ocaml-sqlite3.
commit 3aa4faffb1ecee264af5c649ad36dec67a483f79 Author: Stephane Glondu <st...@glondu.net> Date: Wed Aug 3 15:37:19 2016 +0200 Imported Upstream version 4.0.0 --- CHANGES.txt | 10 ++++++++ _oasis | 4 +-- lib/META | 4 +-- lib/sqlite3.ml | 4 +-- lib/sqlite3.mli | 1 - lib/sqlite3_stubs.c | 70 ++++++++++++++++++++++++++++++++++++++++++++--------- myocamlbuild.ml | 11 ++++++--- setup.ml | 11 +++++---- test/test_error.ml | 16 ++---------- 9 files changed, 88 insertions(+), 43 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7677443..31a102a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +2015-09-02: Major API change that is compatible with major release series 2: + + It is now possible to return errors from user-defined SQL-functions + by simply raising (arbitrary) exceptions. This somewhat + tricky internal change eliminates the need for Data.ERROR and + reestablishes compatibility with major release series 2. + + Sorry for the churn, but the more elegant solution was not + quite obvious! + 2015-08-29: Added user function error handling (major API change). Thanks to Joseph Young for this patch! diff --git a/_oasis b/_oasis index ecdfa45..89fc385 100644 --- a/_oasis +++ b/_oasis @@ -1,6 +1,6 @@ OASISFormat: 0.4 Name: sqlite3 -Version: 3.0.0 +Version: 4.0.0 Synopsis: sqlite3-ocaml - SQLite3 bindings Description: sqlite3-ocaml is an OCaml library with bindings to the SQLite3 client API. Sqlite3 is a self-contained, serverless, @@ -41,7 +41,7 @@ Library sqlite3 CCOpt: -g -O2 -fPIC -DPIC if flag(strict) && ccomp_type(cc) CCOpt+: -Wall -pedantic -Wextra -Wunused -Wno-long-long - CCLib: -lsqlite3 + CCLib: -lsqlite3 -lpthread # Tests diff --git a/lib/META b/lib/META index 83b8d13..2360e7e 100644 --- a/lib/META +++ b/lib/META @@ -1,6 +1,6 @@ # OASIS_START -# DO NOT EDIT (digest: fc7db74acb0529e253896e714e0a428b) -version = "3.0.0" +# DO NOT EDIT (digest: 5c96ba55072fdd9b0770a2d5872a8c6d) +version = "4.0.0" description = "sqlite3-ocaml - SQLite3 bindings" archive(byte) = "sqlite3.cma" archive(byte, plugin) = "sqlite3.cma" diff --git a/lib/sqlite3.ml b/lib/sqlite3.ml index 1eb25be..4f5013a 100644 --- a/lib/sqlite3.ml +++ b/lib/sqlite3.ml @@ -112,13 +112,12 @@ module Data = struct | FLOAT of float | TEXT of string | BLOB of string - | ERROR of string let to_string = function | NONE | NULL -> "" | INT i -> Int64.to_string i | FLOAT f -> string_of_float f - | TEXT t | BLOB t | ERROR t -> t + | TEXT t | BLOB t -> t let to_string_debug = function | NONE -> "NONE" @@ -127,7 +126,6 @@ module Data = struct | FLOAT f -> sprintf "FLOAT <%f>" f | TEXT t -> sprintf "TEXT <%S>" t | BLOB b -> sprintf "BLOB <%d>" (String.length b) - | ERROR e -> sprintf "ERROR <%S>" e end type header = string diff --git a/lib/sqlite3.mli b/lib/sqlite3.mli index 0cc7c6a..aa0749a 100644 --- a/lib/sqlite3.mli +++ b/lib/sqlite3.mli @@ -142,7 +142,6 @@ module Data : sig | FLOAT of float | TEXT of string | BLOB of string - | ERROR of string val to_string : t -> string (** [to_string data] converts [data] to a string. Both [NONE] and diff --git a/lib/sqlite3_stubs.c b/lib/sqlite3_stubs.c index 2abcedb..f34d90d 100644 --- a/lib/sqlite3_stubs.c +++ b/lib/sqlite3_stubs.c @@ -37,6 +37,7 @@ #include <caml/signals.h> #include <sqlite3.h> +#include <pthread.h> #if __GNUC__ >= 3 # define inline inline __attribute__ ((always_inline)) @@ -105,6 +106,46 @@ typedef struct stmt_wrap { } stmt_wrap; +/* Handling of exceptions in user-defined SQL-functions */ + +/* For propagating exceptions from user-defined SQL-functions */ +static pthread_key_t user_exception_key; + +typedef struct user_exception { value exn; } user_exception; + +static inline void create_user_exception(value v_exn) +{ + user_exception *user_exn = caml_stat_alloc(sizeof(user_exception)); + user_exn->exn = v_exn; + caml_register_global_root(&user_exn->exn); + pthread_setspecific(user_exception_key, user_exn); +} + +static inline void destroy_user_exception(void *user_exc_) +{ + user_exception *user_exn = user_exc_; + caml_remove_global_root(&user_exn->exn); + free(user_exn); +} + +static inline void maybe_raise_user_exception(int rc) +{ + if (rc == SQLITE_ERROR) { + user_exception *user_exn = pthread_getspecific(user_exception_key); + + if (user_exn != NULL) { + CAMLparam0(); + CAMLlocal1(v_exn); + v_exn = user_exn->exn; + destroy_user_exception(user_exn); + pthread_setspecific(user_exception_key, NULL); + caml_raise(v_exn); + CAMLnoreturn; + } + } +} + + /* Macros to access the wrapper structures stored in the custom blocks */ #define Sqlite3_val(x) (*((db_wrap **) (Data_custom_val(x)))) @@ -120,11 +161,11 @@ static value *caml_sqlite3_RangeError = NULL; static inline void raise_with_two_args(value v_tag, value v_arg1, value v_arg2) { CAMLparam3(v_tag, v_arg1, v_arg2); - value v_exc = caml_alloc_small(3, 0); - Field(v_exc, 0) = v_tag; - Field(v_exc, 1) = v_arg1; - Field(v_exc, 2) = v_arg2; - caml_raise(v_exc); + value v_exn = caml_alloc_small(3, 0); + Field(v_exn, 0) = v_tag; + Field(v_exn, 1) = v_arg1; + Field(v_exn, 2) = v_arg2; + caml_raise(v_exn); CAMLnoreturn; } @@ -215,6 +256,7 @@ CAMLprim value caml_sqlite3_init(value __unused v_unit) caml_sqlite3_InternalError = caml_named_value("Sqlite3.InternalError"); caml_sqlite3_Error = caml_named_value("Sqlite3.Error"); caml_sqlite3_RangeError = caml_named_value("Sqlite3.RangeError"); + pthread_key_create(&user_exception_key, destroy_user_exception); return Val_unit; } @@ -521,6 +563,7 @@ CAMLprim value caml_sqlite3_exec(value v_db, value v_maybe_cb, value v_sql) caml_leave_blocking_section(); if (rc == SQLITE_ABORT) caml_raise(*cbx.exn); + maybe_raise_user_exception(rc); CAMLreturn(Val_rc(rc)); } @@ -570,6 +613,7 @@ CAMLprim value caml_sqlite3_exec_no_headers(value v_db, value v_cb, value v_sql) caml_leave_blocking_section(); if (rc == SQLITE_ABORT) caml_raise(*cbx.exn); + maybe_raise_user_exception(rc); CAMLreturn(Val_rc(rc)); } @@ -633,6 +677,8 @@ CAMLprim value caml_sqlite3_exec_not_null(value v_db, value v_cb, value v_sql) if (*cbx.exn != 0) caml_raise(*cbx.exn); else raise_sqlite3_Error("Null element in row"); } + maybe_raise_user_exception(rc); + CAMLreturn(Val_rc(rc)); } @@ -692,6 +738,8 @@ CAMLprim value caml_sqlite3_exec_not_null_no_headers( if (*cbx.exn != 0) caml_raise(*cbx.exn); else raise_sqlite3_Error("Null element in row"); } + maybe_raise_user_exception(rc); + CAMLreturn(Val_rc(rc)); } @@ -847,7 +895,6 @@ CAMLprim value caml_sqlite3_bind(value v_stmt, value v_index, value v_data) String_val(v_field), caml_string_length(v_field), SQLITE_TRANSIENT)); - case 4 : return Val_rc(SQLITE_ERROR); } } return Val_rc(SQLITE_ERROR); @@ -1002,14 +1049,16 @@ static inline value caml_sqlite3_wrap_values(int argc, sqlite3_value **args) } } -static inline void exception_result(sqlite3_context *ctx) +static inline void exception_result(sqlite3_context *ctx, value v_res) { + value v_exn = Extract_exception(v_res); + create_user_exception(v_exn); sqlite3_result_error(ctx, "OCaml callback raised an exception", -1); } static inline void set_sqlite3_result(sqlite3_context *ctx, value v_res) { - if (Is_exception_result(v_res)) exception_result(ctx); + if (Is_exception_result(v_res)) exception_result(ctx, v_res); else if (Is_long(v_res)) sqlite3_result_null(ctx); else { value v = Field(v_res, 0); @@ -1024,9 +1073,6 @@ static inline void set_sqlite3_result(sqlite3_context *ctx, value v_res) sqlite3_result_blob( ctx, String_val(v), caml_string_length(v), SQLITE_TRANSIENT); break; - case 4 : - sqlite3_result_error(ctx, String_val(v), caml_string_length(v)); - break; default : sqlite3_result_error(ctx, "unknown value returned by callback", -1); } @@ -1064,7 +1110,7 @@ static inline void caml_sqlite3_user_function_step( } v_args = caml_sqlite3_wrap_values(argc, argv); v_res = caml_callback2_exn(Field(data->v_fun, 2), agg_ctx->v_acc, v_args); - if (Is_exception_result(v_res)) exception_result(ctx); + if (Is_exception_result(v_res)) exception_result(ctx, v_res); else agg_ctx->v_acc = v_res; caml_enter_blocking_section(); } diff --git a/myocamlbuild.ml b/myocamlbuild.ml index 6e97ca5..ae55ac0 100644 --- a/myocamlbuild.ml +++ b/myocamlbuild.ml @@ -1,5 +1,5 @@ (* OASIS_START *) -(* DO NOT EDIT (digest: 8856c7fbdf56cf3b352c8f24a59be7a0) *) +(* DO NOT EDIT (digest: 1308fb3d48472c2edc4cc51c862b6705) *) module OASISGettext = struct (* # 22 "src/oasis/OASISGettext.ml" *) @@ -651,9 +651,12 @@ let package_default = ]) ]); (["oasis_library_sqlite3_cclib"; "link"], - [(OASISExpr.EBool true, S [A "-cclib"; A "-lsqlite3"])]); + [ + (OASISExpr.EBool true, + S [A "-cclib"; A "-lsqlite3"; A "-cclib"; A "-lpthread"]) + ]); (["oasis_library_sqlite3_cclib"; "ocamlmklib"; "c"], - [(OASISExpr.EBool true, S [A "-lsqlite3"])]) + [(OASISExpr.EBool true, S [A "-lsqlite3"; A "-lpthread"])]) ]; includes = [("test", ["lib"])] } @@ -663,7 +666,7 @@ let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false} let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; -# 667 "myocamlbuild.ml" +# 670 "myocamlbuild.ml" (* OASIS_STOP *) let read_lines_from_cmd ~max_lines cmd = diff --git a/setup.ml b/setup.ml index 19c2d02..5e395db 100644 --- a/setup.ml +++ b/setup.ml @@ -1,7 +1,7 @@ (* setup.ml generated for the first time by OASIS v0.3.0 *) (* OASIS_START *) -(* DO NOT EDIT (digest: 51146b2c34f38bae10732375ae42aa0e) *) +(* DO NOT EDIT (digest: 1b6fe2a99f7d4b7e0a8fcaf32a49dc1a) *) (* Regenerated by OASIS v0.4.5 Visit http://oasis.forge.ocamlcore.org for more information and @@ -6981,7 +6981,7 @@ let setup_t = alpha_features = []; beta_features = []; name = "sqlite3"; - version = "3.0.0"; + version = "4.0.0"; license = OASISLicense.DEP5License (OASISLicense.DEP5Unit @@ -7097,7 +7097,8 @@ let setup_t = "-Wno-long-long" ]) ]; - bs_cclib = [(OASISExpr.EBool true, ["-lsqlite3"])]; + bs_cclib = + [(OASISExpr.EBool true, ["-lsqlite3"; "-lpthread"])]; bs_dlllib = [(OASISExpr.EBool true, [])]; bs_dllpath = [(OASISExpr.EBool true, [])]; bs_byteopt = [(OASISExpr.EBool true, [])]; @@ -7511,7 +7512,7 @@ let setup_t = }; oasis_fn = Some "_oasis"; oasis_version = "0.4.5"; - oasis_digest = Some "��]]�\1486t\133\000&�� M�"; + oasis_digest = Some "�7�\022\139Ku�e��_��\019?"; oasis_exec = None; oasis_setup_args = []; setup_update = false @@ -7519,6 +7520,6 @@ let setup_t = let setup () = BaseSetup.setup setup_t;; -# 7523 "setup.ml" +# 7524 "setup.ml" (* OASIS_STOP *) let () = setup ();; diff --git a/test/test_error.ml b/test/test_error.ml index 2b805f8..048e8e6 100644 --- a/test/test_error.ml +++ b/test/test_error.ml @@ -3,18 +3,6 @@ open Sqlite3 (* Tests our ability to return an error from a user defined function *) let () = let db = db_open "t" in - create_fun0 db "MYERROR" (fun () -> Data.ERROR "This function always errors"); + create_fun0 db "MYERROR" (fun () -> failwith "This function always errors"); let res = exec db "SELECT MYERROR();" in - match res with - | Rc.ERROR -> print_endline (errmsg db) - | x -> prerr_endline ("Should have thrown an error: " ^ Rc.to_string x) - -(* Insures that we can't bind an error to a query *) -let () = - let db = db_open "t" in - let _ : Rc.t = exec db "CREATE TABLE foo (val text);" in - let s = Sqlite3.prepare db "INSERT INTO foo values (?);" in - let res = Sqlite3.bind s 1 (Sqlite3.Data.ERROR "Should be impossible") in - match res with - | Rc.ERROR -> print_endline ("Bind threw an error") - | x -> prerr_endline ("Should have thrown an error: " ^ Rc.to_string x) + prerr_endline ("Should have thrown an error: " ^ Rc.to_string res) -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ocaml-maint/packages/ocaml-sqlite3.git _______________________________________________ Pkg-ocaml-maint-commits mailing list Pkg-ocaml-maint-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-ocaml-maint-commits