diff --git a/c_src/wterl.c b/c_src/wterl.c index 068e871..233257a 100644 --- a/c_src/wterl.c +++ b/c_src/wterl.c @@ -57,15 +57,18 @@ static ERL_NIF_TERM ATOM_OK; static ERL_NIF_TERM wterl_conn_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_conn_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_cursor_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_np_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int next); static ERL_NIF_TERM wterl_cursor_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_prev(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM wterl_cursor_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_ret(ErlNifEnv* env, WT_CURSOR *cursor, int rc); static ERL_NIF_TERM wterl_cursor_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search_near(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_cursor_search_worker(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int near); +static ERL_NIF_TERM wterl_cursor_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM wterl_session_delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -85,12 +88,15 @@ static ErlNifFunc nif_funcs[] = {"conn_close", 1, wterl_conn_close}, {"conn_open", 2, wterl_conn_open}, {"cursor_close", 1, wterl_cursor_close}, + {"cursor_insert", 3, wterl_cursor_insert}, {"cursor_next", 1, wterl_cursor_next}, {"cursor_open", 2, wterl_cursor_open}, {"cursor_prev", 1, wterl_cursor_prev}, + {"cursor_remove", 3, wterl_cursor_remove}, {"cursor_reset", 1, wterl_cursor_reset}, {"cursor_search", 2, wterl_cursor_search}, {"cursor_search_near", 2, wterl_cursor_search_near}, + {"cursor_update", 3, wterl_cursor_update}, {"session_close", 1, wterl_session_close}, {"session_create", 3, wterl_session_create}, {"session_delete", 3, wterl_session_delete}, @@ -410,7 +416,8 @@ static ERL_NIF_TERM wterl_session_put(ErlNifEnv* env, int argc, const ERL_NIF_TE Uri uri; ErlNifBinary key, value; if (enif_get_string(env, argv[1], uri, sizeof uri, ERL_NIF_LATIN1) && - enif_inspect_binary(env, argv[2], &key) && enif_inspect_binary(env, argv[3], &value)) + enif_inspect_binary(env, argv[2], &key) && + enif_inspect_binary(env, argv[3], &value)) { WT_CURSOR* cursor; int rc = session->open_cursor(session, uri, NULL, "overwrite,raw", &cursor); @@ -576,6 +583,67 @@ static ERL_NIF_TERM wterl_cursor_reset(ErlNifEnv* env, int argc, const ERL_NIF_T return enif_make_badarg(env); } +#define WTERL_OP_CURSOR_INSERT 1 +#define WTERL_OP_CURSOR_UPDATE 2 +#define WTERL_OP_CURSOR_REMOVE 3 + +static inline ERL_NIF_TERM wterl_cursor_data_op(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], int op) +{ + wterl_cursor_handle *cursor_handle; + if (enif_get_resource(env, argv[0], wterl_cursor_RESOURCE, (void**)&cursor_handle)) + { + ErlNifBinary key, value; + int rc; + if (enif_inspect_binary(env, argv[1], &key) && + enif_inspect_binary(env, argv[2], &value)) { + WT_CURSOR* cursor = cursor_handle->cursor; + WT_ITEM raw_key, raw_value; + raw_key.data = key.data; + raw_key.size = key.size; + cursor->set_key(cursor, &raw_key); + raw_value.data = value.data; + raw_value.size = value.size; + cursor->set_value(cursor, &raw_value); + switch (op) { + case WTERL_OP_CURSOR_INSERT: + rc = cursor->insert(cursor); + break; + case WTERL_OP_CURSOR_UPDATE: + rc = cursor->update(cursor); + break; + default: + case WTERL_OP_CURSOR_REMOVE: + rc = cursor->remove(cursor); + break; + } + if (rc == 0) + { + return ATOM_OK; + } + else + { + return wterl_strerror(env, rc); + } + } + } + return enif_make_badarg(env); +} + +static ERL_NIF_TERM wterl_cursor_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_data_op(env, argc, argv, WTERL_OP_CURSOR_INSERT); +} + +static ERL_NIF_TERM wterl_cursor_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_data_op(env, argc, argv, WTERL_OP_CURSOR_UPDATE); +} + +static ERL_NIF_TERM wterl_cursor_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return wterl_cursor_data_op(env, argc, argv, WTERL_OP_CURSOR_REMOVE); +} + static void wterl_conn_resource_cleanup(ErlNifEnv* env, void* arg) { /* Delete any dynamically allocated memory stored in wterl_handle */ diff --git a/src/wterl.erl b/src/wterl.erl index df5ecc5..37c6282 100644 --- a/src/wterl.erl +++ b/src/wterl.erl @@ -25,12 +25,15 @@ -export([conn_open/2, conn_close/1, cursor_close/1, + cursor_insert/3, cursor_next/1, cursor_open/2, cursor_prev/1, + cursor_remove/3, cursor_reset/1, cursor_search/2, cursor_search_near/2, + cursor_update/3, session_close/1, session_create/2, session_create/3, @@ -157,6 +160,15 @@ cursor_search_near(_Cursor, _Key) -> cursor_reset(_Cursor) -> ?nif_stub. +cursor_insert(_Ref, _Key, _Value) -> + ?nif_stub. + +cursor_update(_Ref, _Key, _Value) -> + ?nif_stub. + +cursor_remove(_Ref, _Key, _Value) -> + ?nif_stub. + %% %% Configuration type information. %% @@ -325,6 +337,33 @@ basic_test() -> {ok, <<"apple">>} = cursor_next(Cursor), ok = cursor_close(Cursor), + %% Insert/overwrite an item using a cursor + io:put_chars(standard_error, "\tcursor insert/overwrite\n"), + {ok, Cursor} = cursor_open(SRef, "table:test"), + ok = cursor_insert(Cursor, <<"h">>, <<"huckleberry">>), + {ok, <<"huckleberry">>} = cursor_search(Cursor, <<"h">>), + ok = cursor_insert(Cursor, <<"g">>, <<"grapefruit">>), + {ok, <<"grapefruit">>} = cursor_search(Cursor, <<"g">>), + ok = cursor_close(Cursor), + {ok, <<"grapefruit">>} = session_get(SRef, "table:test", <<"g">>), + {ok, <<"huckleberry">>} = session_get(SRef, "table:test", <<"h">>), + + %% Update an item using a cursor + io:put_chars(standard_error, "\tcursor update\n"), + {ok, Cursor} = cursor_open(SRef, "table:test"), + ok = cursor_update(Cursor, <<"g">>, <<"goji berries">>), + {error, not_found} = cursor_update(Cursor, <<"k">>, <<"kumquat">>), + ok = cursor_close(Cursor), + {ok, <<"goji berries">>} = session_get(SRef, "table:test", <<"g">>), + + %% Remove an item using a cursor + io:put_chars(standard_error, "\tcursor remove\n"), + {ok, Cursor} = cursor_open(SRef, "table:test"), + ok = cursor_remove(Cursor, <<"g">>, <<"goji berries">>), + {error, not_found} = cursor_remove(Cursor, <<"l">>, <<"lemon">>), + ok = cursor_close(Cursor), + {error, not_found} = session_get(SRef, "table:test", <<"g">>), + %% Close the session/connection io:put_chars(standard_error, "\tsession/connection close\n"), ok = session_close(SRef),