Skip to content
This repository was archived by the owner on Dec 17, 2018. It is now read-only.

Commit 538085f

Browse files
connor rigbyConnorRigby
authored andcommitted
Pull in mmzeeman#31
1 parent c269397 commit 538085f

File tree

8 files changed

+103
-18
lines changed

8 files changed

+103
-18
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- run: mix dialyzer --halt-exit-status
2727
- run: mix credo --strict --ignore linelength -a
2828
- run:
29-
command: mix coveralls.circle
29+
command: mix coveralls.circle --include bench
3030
environment:
3131
MIX_ENV: test
3232
- run:

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ OBJ=$(SRC:.c=.o)
1111

1212
LDFLAGS ?= -fPIC -shared -pedantic
1313
CFLAGS ?= -fPIC -O2
14+
SQLITE_CFLAGS = -DSQLITE_THREADSAFE=1 -DSQLITE_USE_URI -DSQLITE_ENABLE_FTS3 \
15+
-DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_JSON1 \
16+
-DSQLITE_ENABLE_RTREE
1417

1518
NIF=priv/esqlite3_nif.so
1619

@@ -20,7 +23,7 @@ priv:
2023
mkdir -p priv
2124

2225
%.o: %.c
23-
$(CC) -c $(ERL_CFLAGS) $(CFLAGS) -o $@ $<
26+
$(CC) -c $(ERL_CFLAGS) $(CFLAGS) $(SQLITE_CFLAGS) -o $@ $<
2427

2528
$(NIF): $(OBJ)
2629
$(CC) $^ $(ERL_LDFLAGS) $(LDFLAGS) -o $@

c_src/esqlite3_nif.c

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,28 @@ do_open(ErlNifEnv *env, esqlite_connection *db, const ERL_NIF_TERM arg)
244244
{
245245
char filename[MAX_PATHNAME];
246246
unsigned int size;
247-
int rc;
247+
int rc, count_args, flag_number;
248248
ERL_NIF_TERM error;
249+
const ERL_NIF_TERM *args;
250+
251+
/*
252+
unpack the arg, the first argument is the filename, the second is the flag count
253+
*/
254+
if(!enif_get_tuple(env, arg, &count_args, &args))
255+
return make_error_tuple(env, "wrong_unpack_of_args_from_open");
256+
if(count_args != 2)
257+
return make_error_tuple(env, "wrong_number_of_args_from_open");
249258

250-
size = enif_get_string(env, arg, filename, MAX_PATHNAME, ERL_NIF_LATIN1);
259+
size = enif_get_string(env, args[0], filename, MAX_PATHNAME, ERL_NIF_LATIN1);
251260
if(size <= 0)
252261
return make_error_tuple(env, "invalid_filename");
253262

263+
if(!enif_get_int(env, args[1], &flag_number))
264+
return make_error_tuple(env, "unable_to_get_flag_number_from_open");
265+
254266
/* Open the database.
255267
*/
256-
rc = sqlite3_open(filename, &db->db);
268+
rc = sqlite3_open_v2(filename, &db->db, flag_number, NULL);
257269
if(rc != SQLITE_OK) {
258270
error = make_sqlite3_error_tuple(env, rc, db->db);
259271
sqlite3_close_v2(db->db);
@@ -738,6 +750,41 @@ esqlite_start(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
738750
return make_ok_tuple(env, db_conn);
739751
}
740752

753+
int
754+
count_flag(ErlNifEnv *env, const ERL_NIF_TERM array[], int tuple_count)
755+
{
756+
char flag[30];
757+
int i, flag_count=0;
758+
unsigned int flag_len=0;
759+
760+
for(i = 0; i < tuple_count; i++)
761+
{
762+
enif_get_atom_length(env, array[i], &flag_len, ERL_NIF_LATIN1);
763+
enif_get_atom(env, array[i], flag, flag_len + 1, ERL_NIF_LATIN1);
764+
if (strcmp(flag, "readonly") == 0)
765+
flag_count = flag_count | SQLITE_OPEN_READONLY;
766+
else if (strcmp(flag, "readwrite") == 0)
767+
flag_count = flag_count | SQLITE_OPEN_READWRITE;
768+
else if (strcmp(flag, "create") == 0)
769+
flag_count = flag_count | SQLITE_OPEN_CREATE;
770+
else if (strcmp(flag, "uri") == 0)
771+
flag_count = flag_count | SQLITE_OPEN_URI;
772+
else if (strcmp(flag, "memory") == 0)
773+
flag_count = flag_count | SQLITE_OPEN_MEMORY;
774+
else if (strcmp(flag, "nomutex") == 0)
775+
flag_count = flag_count | SQLITE_OPEN_NOMUTEX;
776+
else if (strcmp(flag, "fullmutex") == 0)
777+
flag_count = flag_count | SQLITE_OPEN_FULLMUTEX;
778+
else if (strcmp(flag, "sharedcache") == 0)
779+
flag_count = flag_count | SQLITE_OPEN_SHAREDCACHE;
780+
else if (strcmp(flag, "privatecache") == 0)
781+
flag_count = flag_count | SQLITE_OPEN_PRIVATECACHE;
782+
else
783+
return -1;
784+
}
785+
return flag_count;
786+
}
787+
741788
/*
742789
* Open the database
743790
*/
@@ -747,18 +794,27 @@ esqlite_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
747794
esqlite_connection *db;
748795
esqlite_command *cmd = NULL;
749796
ErlNifPid pid;
797+
const ERL_NIF_TERM *array;
798+
int tuple_count, flag_count;
750799

751-
if(argc != 4)
800+
if(argc != 5)
752801
return enif_make_badarg(env);
753802
if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db))
754803
return enif_make_badarg(env);
755804
if(!enif_is_ref(env, argv[1]))
756805
return make_error_tuple(env, "invalid_ref");
757806
if(!enif_get_local_pid(env, argv[2], &pid))
758807
return make_error_tuple(env, "invalid_pid");
759-
760808
if(!sqlite3_threadsafe())
761809
return make_error_tuple(env, "sqlite3 not thread safe.");
810+
if(!enif_get_tuple(env, argv[4], &tuple_count, &array))
811+
return make_error_tuple(env, "invalid_tuple");
812+
813+
flag_count = count_flag(env, array, tuple_count);
814+
815+
if (flag_count == -1)
816+
return make_error_tuple(env, "unrecognize_flag");
817+
762818

763819
/* Note, no check is made for the type of the argument */
764820
cmd = command_create();
@@ -768,7 +824,7 @@ esqlite_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
768824
cmd->type = cmd_open;
769825
cmd->ref = enif_make_copy(cmd->env, argv[1]);
770826
cmd->pid = pid;
771-
cmd->arg = enif_make_copy(cmd->env, argv[3]);
827+
cmd->arg = enif_make_tuple2(cmd->env, enif_make_copy(cmd->env, argv[3]), enif_make_int(cmd->env, flag_count));
772828

773829
return push_command(env, db, cmd);
774830
}
@@ -1153,7 +1209,7 @@ static int on_upgrade(ErlNifEnv* env, void** priv, void** old_priv_data, ERL_NIF
11531209

11541210
static ErlNifFunc nif_funcs[] = {
11551211
{"start", 0, esqlite_start},
1156-
{"open", 4, esqlite_open},
1212+
{"open", 5, esqlite_open},
11571213
{"exec", 4, esqlite_exec},
11581214
{"changes", 3, esqlite_changes},
11591215
{"prepare", 4, esqlite_prepare},

lib/esqlite3/esqlite3.ex

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@ defmodule Esqlite3 do
2121

2222
@doc "Opens a sqlite3 database mentioned in filename."
2323
@spec open(filename) :: {:ok, connection} | error_tup2
24-
def open(filename), do: open(filename, @default_timeout)
24+
def open(filename), do: open(filename, {:readwrite, :create}, @default_timeout)
2525

26-
@doc "Opens a sqlite3 database mentioned in filename."
27-
@spec open(filename, timeout) :: {:ok, connection} | error_tup2
28-
def open(filename, timeout) do
26+
@doc "Opens a sqlite3 database mentioned in filename with flags."
27+
def open(filename, flags) when is_tuple(flags), do: open(filename, flags, @default_timeout)
28+
29+
@doc "Opens a sqlite3 database with a flags tuple and a timeout."
30+
@spec open(filename, tuple, timeout) :: {:ok, connection} | error_tup2
31+
def open(filename, flags, timeout) when is_tuple(flags) do
2932
filename = to_charlist(filename)
3033

3134
with {:ok, connection} <- Esqlite3Nif.start(),
3235
ref when is_reference(ref) <- make_ref(),
33-
:ok <- Esqlite3Nif.open(connection, ref, self(), filename),
36+
:ok <- Esqlite3Nif.open(connection, ref, self(), filename, flags),
3437
:ok <- receive_answer(ref, timeout) do
3538
{:ok, {:connection, make_ref(), connection}}
3639
else

lib/esqlite3/esqlite3_nif.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ defmodule Esqlite3Nif do
2727
def start, do: :erlang.nif_error(:nif_library_not_loaded)
2828

2929
@doc "Open the specified sqlite3 database."
30-
@spec open(connection, reference, pid, Path.t()) :: :ok | error_tup2
31-
def open(_db, _ref, _dest, _filename), do: :erlang.nif_error(:nif_library_not_loaded)
30+
@spec open(connection, reference, pid, Path.t(), tuple) :: :ok | error_tup2
31+
def open(_db, _ref, _dest, _filename, _flags), do: :erlang.nif_error(:nif_library_not_loaded)
3232

3333
@doc """
3434
Exec the query.

lib/sqlite.ex

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,29 @@ defmodule Sqlite do
3030
@opaque conn :: Connection.t()
3131

3232
@default_start_opts [
33-
timeout: Application.get_env(:esqlite, :default_timeout, 5000)
33+
timeout: Application.get_env(:esqlite, :default_timeout, 5000),
34+
flags: [:readwrite, :create]
3435
]
3536

3637
@doc """
3738
Start the connection process and connect to sqlite.
3839
## Options
3940
* `:database` -> Databse uri.
4041
* `:timeout` -> Max amount of time for commands to take. (default: 5000)
42+
* `:flags` -> List of flags to be passed to SQLite.
43+
## Flags
44+
Flags to be passed to Sqlite on `open`.
45+
See [here](https://www.sqlite.org/c3ref/c_open_autoproxy.html) for more
46+
details.
47+
* `:readwrite`
48+
* `:readonly`
49+
* `:create`
50+
* `:uri`
51+
* `:memory`
52+
* `:nomutex`
53+
* `:fullmutex`
54+
* `:sharedcache`
55+
* `:privatecache`
4156
## GenServer opts
4257
These get passed directly to [GenServer](GenServer.html)
4358
## Examples

lib/sqlite/server.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ defmodule Sqlite.Server do
1717
def init(opts) do
1818
filename = Keyword.fetch!(opts, :database)
1919
timeout = Keyword.fetch!(opts, :timeout)
20+
flags = Keyword.fetch!(opts, :flags)
2021

21-
case Esqlite3.open(filename, timeout) do
22+
case Esqlite3.open(filename, List.to_tuple(flags), timeout) do
2223
{:ok, db} ->
2324
{:ok, struct(State, database: db, filename: filename)}
2425

test/esqlite3/esqlite3_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ defmodule Esqlite3Test do
1616
assert match?({:ok, _c2}, Esqlite3.open("test2.db"))
1717
end
1818

19+
test "open with flags" do
20+
{:ok, db} = Esqlite3.open(":memory:", {:readonly})
21+
22+
{:error, {:readonly, 'attempt to write a readonly database'}} =
23+
Esqlite3.exec("create table test_table(one varchar(10), two int);", db)
24+
end
25+
1926
test "simple query" do
2027
{:ok, db} = Esqlite3.open(":memory:")
2128
:ok = Esqlite3.exec("begin;", db)

0 commit comments

Comments
 (0)