From fa0ec71334334e6e689a2461c51a486f36c43155 Mon Sep 17 00:00:00 2001 From: Greg Nisbet Date: Sun, 10 Jun 2018 13:04:14 -0700 Subject: [PATCH] [hack] bare bones sqlite wrapper for use in OCaml code Summary: simple library that statically allocates a few dbs and prepared statements up to a hardcoded maximum it can be used to bind and extract ints and strings from sqlite. Reviewed By: dabek Differential Revision: D8325025 fbshipit-source-id: 37312532ab5f3da69e559d739bf13e2c1f275b02 --- hack/heap/dumbsqlite.ml | 62 +++++ hack/heap/lib_dumbsqlite.c | 475 +++++++++++++++++++++++++++++++++++++ 2 files changed, 537 insertions(+) create mode 100644 hack/heap/dumbsqlite.ml create mode 100644 hack/heap/lib_dumbsqlite.c diff --git a/hack/heap/dumbsqlite.ml b/hack/heap/dumbsqlite.ml new file mode 100644 index 00000000000..64803a2e800 --- /dev/null +++ b/hack/heap/dumbsqlite.ml @@ -0,0 +1,62 @@ +type sqlerr = int + +type sqlerr_t = { sqlerr : sqlerr } + +type classified_error = + | SqliteOk + | Row + | Done + | SqliteErr of int + | WrapperErr of int + +let classify_sqlerr {sqlerr} = + match sqlerr with + | 0 -> SqliteOk + | 100 -> Row + | 101 -> Done + | _ -> ( + if sqlerr > 0 then SqliteErr sqlerr + else WrapperErr sqlerr + ) + +external caml_dumb_sqlite_open : int -> string -> bool -> sqlerr = "caml_dumb_sqlite_open" +let caml_dumb_sqlite_open ~index ~path ~readonly = + {sqlerr = caml_dumb_sqlite_open index path readonly} + +external caml_dumb_sqlite_close : int -> sqlerr = "caml_dumb_sqlite_close" +let caml_dumb_sqlite_close ~index = + {sqlerr = caml_dumb_sqlite_close index} + +external caml_dumb_sqlite_prepare : int -> int -> string -> sqlerr = "caml_dumb_sqlite_prepare" +let caml_dumb_sqlite_prepare ~index ~s_index ~sql = + {sqlerr = caml_dumb_sqlite_prepare index s_index sql} + +external caml_dumb_sqlite_reset : int -> sqlerr = "caml_dumb_sqlite_reset" +let caml_dumb_sqlite_reset ~s_index = + {sqlerr = caml_dumb_sqlite_reset s_index} + +external caml_dumb_sqlite_step : int -> sqlerr = "caml_dumb_sqlite_step" +let caml_dumb_sqlite_step ~s_index = + {sqlerr = caml_dumb_sqlite_step s_index} + +external caml_dumb_sqlite_finalize : int -> sqlerr = "caml_dumb_sqlite_finalize" +let caml_dumb_sqlite_finalize ~s_index = + {sqlerr = caml_dumb_sqlite_finalize s_index} + +external caml_dumb_sqlite_bind_int64 : int -> int -> Int64.t -> sqlerr = "caml_dumb_sqlite_bind_int64" +let caml_dumb_sqlite_bind_int64 ~s_index ~param ~value = + {sqlerr = caml_dumb_sqlite_bind_int64 s_index param value} + +external caml_dumb_sqlite_bind_text : int -> int -> string -> sqlerr = "caml_dumb_sqlite_bind_text" +let caml_dumb_sqlite_bind_text ~s_index ~param ~value = + {sqlerr = caml_dumb_sqlite_bind_text s_index param value} + +external caml_dumb_sqlite_column_int64 : int -> int -> (sqlerr * Int64.t) = "caml_dumb_sqlite_column_int64" +let caml_dumb_sqlite_column_int64 ~s_index ~column = + let (sqlerr, res) = caml_dumb_sqlite_column_int64 s_index column in + ({sqlerr = sqlerr}, res) + +external caml_dumb_sqlite_column_text : int -> int -> (sqlerr * string) = "caml_dumb_sqlite_column_text" +let caml_dumb_sqlite_column_text ~s_index ~column = + let (sqlerr, res) = caml_dumb_sqlite_column_text s_index column in + ({sqlerr = sqlerr}, res) diff --git a/hack/heap/lib_dumbsqlite.c b/hack/heap/lib_dumbsqlite.c new file mode 100644 index 00000000000..1157bfd2858 --- /dev/null +++ b/hack/heap/lib_dumbsqlite.c @@ -0,0 +1,475 @@ +#ifdef NO_SQLITE3 +// nothing +#else +#include +#endif +#include +#include + +#define CAML_NAME_SPACE +#include +#include +#include + +#define SQLITE_DBS 100 +#define SQLITE_STMTS 1000 + +#define ERR_SLOT_TAKEN -100 +#define ERR_INDEX_OUT_OF_RANGE -101 +#define ERR_NULL_PTR -102 +#define ERR_INTERNAL -103 +#define ERR_DB_NOT_PRESENT -104 +#define ERR_STMT_INDEX_OUT_OF_RANGE -105 +#define ERR_STMT_SLOT_TAKEN -106 +#define ERR_STMT_NOT_PRESENT -107 +#define ERR_DB_ALLOC_FAILED -108 +#define ERR_PARAM_OUT_OF_RANGE -109 +#define ERR_COLUMN_OUT_OF_RANGE -110 +#define ERR_GOT_NULL_TEXT_COLUMN -111 +#define ERR_WOULD_CLOBBER -112 +#define ERR_NO_SQLITE3 -113 + +#ifdef NO_SQLITE3 +// nothing +#else +sqlite3 *dumb_sqlite_dbs[SQLITE_DBS] = { 0 }; +sqlite3_stmt *dumb_sqlite_stmts[SQLITE_STMTS] = { 0 }; +#endif + + +#ifdef NO_SQLITE3 +int dumb_sqlite_open(int index, const char *path, int readonly) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_open(int index, const char *path, int readonly) +{ + if (index < 0) + return ERR_INDEX_OUT_OF_RANGE; + if (index >= SQLITE_DBS) + return ERR_INDEX_OUT_OF_RANGE; + if (path == NULL) + return ERR_NULL_PTR; + if (dumb_sqlite_dbs[index] != NULL) + return ERR_SLOT_TAKEN; + int sqlerr = ERR_INTERNAL; + if (readonly) { + sqlerr = sqlite3_open_v2( + path, + &(dumb_sqlite_dbs[index]), + SQLITE_OPEN_READONLY, + NULL + ); + } else { + sqlerr = sqlite3_open( + path, + &(dumb_sqlite_dbs[index]) + ); + } + if (dumb_sqlite_dbs[index] == NULL) { + return ERR_DB_ALLOC_FAILED; + } + return sqlerr; +} +#endif //NO_SQLITE3 + + +CAMLprim value caml_dumb_sqlite_open( + value ml_index, value ml_path, value ml_readonly +) { + CAMLparam3(ml_index, ml_path, ml_readonly); + CAMLreturn( + Val_int( + dumb_sqlite_open( + Int_val(ml_index), + String_val(ml_path), + Bool_val(ml_readonly) + ) + ) + ); +} + + +#ifdef NO_SQLITE3 +int dumb_sqlite_close(int index) { + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_close(int index) { + if (index < 0) + return ERR_INDEX_OUT_OF_RANGE; + if (index >= SQLITE_DBS) + return ERR_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_dbs[index] == NULL) + return ERR_DB_NOT_PRESENT; + int sqlerr = sqlite3_close(dumb_sqlite_dbs[index]); + if (sqlerr == SQLITE_OK) { + dumb_sqlite_dbs[index] = NULL; + } + return sqlerr; +} +#endif //NO_SQLITE3 + + +CAMLprim value caml_dumb_sqlite_close( + value ml_index +) { + CAMLparam1(ml_index); + CAMLreturn( + Val_int( + dumb_sqlite_close( + Int_val(ml_index) + ) + ) + ); +} + +#ifdef NO_SQLITE3 +int dumb_sqlite_prepare(int index, int s_index, const char *sql) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_prepare(int index, int s_index, const char *sql) +{ + if (index < 0) + return ERR_INDEX_OUT_OF_RANGE; + if (index >= SQLITE_DBS) + return ERR_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_dbs[index] == NULL) + return ERR_DB_NOT_PRESENT; + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] != NULL) + return ERR_STMT_SLOT_TAKEN; + if (sql == NULL) + return ERR_NULL_PTR; + int sqlerr = sqlite3_prepare_v2( + dumb_sqlite_dbs[index], + sql, + -1, + &(dumb_sqlite_stmts[s_index]), + NULL + ); + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_prepare( + value ml_index, value ml_s_index, value ml_sql +) { + CAMLparam3(ml_index, ml_s_index, ml_sql); + CAMLreturn( + Val_int( + dumb_sqlite_prepare( + Int_val(ml_index), + Int_val(ml_s_index), + String_val(ml_sql) + ) + ) + ); +} + +#ifdef NO_SQLITE3 +int dumb_sqlite_reset(int s_index) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_reset(int s_index) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + int sqlerr = sqlite3_reset( + dumb_sqlite_stmts[s_index] + ); + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_reset( + value ml_s_index +) { + CAMLparam1(ml_s_index); + CAMLreturn( + Val_int( + dumb_sqlite_reset( + Int_val(ml_s_index) + ) + ) + ); +} + + +#ifdef NO_SQLITE3 +int dumb_sqlite_finalize(int s_index) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_finalize(int s_index) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + int sqlerr = sqlite3_finalize( + dumb_sqlite_stmts[s_index] + ); + if (sqlerr == SQLITE_OK) { + dumb_sqlite_stmts[s_index] = NULL; + } + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_finalize( + value ml_s_index +) { + CAMLparam1(ml_s_index); + CAMLreturn( + Val_int( + dumb_sqlite_finalize( + Int_val(ml_s_index) + ) + ) + ); +} + + +#ifdef NO_SQLITE3 +int dumb_sqlite_step(int s_index) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_step(int s_index) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + int sqlerr = sqlite3_step( + dumb_sqlite_stmts[s_index] + ); + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_step( + value ml_s_index +) { + CAMLparam1(ml_s_index); + CAMLreturn( + Val_int( + dumb_sqlite_step( + Int_val(ml_s_index) + ) + ) + ); +} + + +#ifdef NO_SQLITE3 +int dumb_sqlite_bind_int64(int s_index, int param, int64_t value_) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_bind_int64(int s_index, int param, int64_t value_) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + if (param < 1) + return ERR_PARAM_OUT_OF_RANGE; + int sqlerr = sqlite3_bind_int64( + dumb_sqlite_stmts[s_index], + param, + value_ + ); + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_bind_int64( + value ml_s_index, value ml_param, value ml_value +) { + CAMLparam3(ml_s_index, ml_param, ml_value); + CAMLreturn( + Val_int( + dumb_sqlite_bind_int64( + Int64_val(ml_s_index), + Int_val(ml_param), + Long_val(ml_value) + ) + ) + ); +} + + +#ifdef NO_SQLITE3 +int dumb_sqlite_bind_text(int s_index, int param, const char *value_) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_bind_text(int s_index, int param, const char *value_) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + if (param < 1) + return ERR_PARAM_OUT_OF_RANGE; + int sqlerr = sqlite3_bind_text( + dumb_sqlite_stmts[s_index], + param, + value_, + -1, + SQLITE_TRANSIENT + ); + return sqlerr; +} +#endif + + +CAMLprim value caml_dumb_sqlite_bind_text( + value ml_s_index, value ml_param, value ml_value +) +{ + CAMLparam3(ml_s_index, ml_param, ml_value); + CAMLreturn( + Val_int( + dumb_sqlite_bind_text( + Int_val(ml_s_index), + Int_val(ml_param), + String_val(ml_value) + ) + ) + ); +} + +#ifdef NO_SQLITE3 +int dumb_sqlite_column_int64(int s_index, int column, /*out*/ int64_t *out_value) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_column_int64(int s_index, int column, /*out*/ int64_t *out_value) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + if (column < 0) + return ERR_COLUMN_OUT_OF_RANGE; + if (out_value == NULL) + return ERR_NULL_PTR; + int64_t res = sqlite3_column_int64( + dumb_sqlite_stmts[s_index], + column + ); + *out_value = res; + return SQLITE_OK; +} +#endif + + +CAMLprim value caml_dumb_sqlite_column_int64( + value ml_s_index, value ml_column +) { + CAMLparam2(ml_s_index, ml_column); + CAMLlocal3(ml_pair, ml_first, ml_second); + int64_t out = 0; + ml_first = + Val_int( + dumb_sqlite_column_int64( + Int_val(ml_s_index), + Int_val(ml_column), + &out + ) + ); + ml_second = caml_copy_int64(out); + ml_pair = caml_alloc_tuple(2); + Store_field(ml_pair, 0, ml_first); + Store_field(ml_pair, 1, ml_second); + CAMLreturn(ml_pair); +} + +#ifdef NO_SQLITE3 +int dumb_sqlite_column_text(int s_index, int column, /*out*/ char **out_value) +{ + return ERR_NO_SQLITE3; +} +#else +int dumb_sqlite_column_text(int s_index, int column, /*out*/ char **out_value) +{ + if (s_index < 0) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (s_index >= SQLITE_DBS) + return ERR_STMT_INDEX_OUT_OF_RANGE; + if (dumb_sqlite_stmts[s_index] == NULL) + return ERR_STMT_NOT_PRESENT; + if (column < 0) + return ERR_COLUMN_OUT_OF_RANGE; + if (out_value == NULL) + return ERR_NULL_PTR; + if (*out_value != NULL) + return ERR_WOULD_CLOBBER; + char *res = (char *) sqlite3_column_text( + dumb_sqlite_stmts[s_index], + column + ); + *out_value = res; + return SQLITE_OK; +} +#endif + + +CAMLprim value caml_dumb_sqlite_column_text( + value ml_s_index, value ml_column +) { + CAMLparam2(ml_s_index, ml_column); + CAMLlocal3(ml_pair, ml_first, ml_second); + char *out = NULL; + ml_first = + Val_int( + dumb_sqlite_column_text( + Int_val(ml_s_index), + Int_val(ml_column), + &out + ) + ); + if (out == NULL) { + out = ""; + } + ml_second = caml_copy_string(out); + ml_pair = caml_alloc_tuple(2); + Store_field(ml_pair, 0, ml_first); + Store_field(ml_pair, 1, ml_second); + CAMLreturn(ml_pair); +}