Skip to content

Commit cac2de9

Browse files
committed
fix C genomicsqlite_open and add smoke test
1 parent 5066f85 commit cac2de9

7 files changed

Lines changed: 116 additions & 67 deletions

File tree

.github/workflows/build.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ jobs:
8383
/usr/local/bin/pip3 install $PIP_DEPS
8484
- name: build
8585
run: |
86-
CFLAGS="-I$(brew --prefix)/include -I$(brew --prefix)/opt/sqlite/include" CXXFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib \
86+
CFLAGS="-I$(brew --prefix)/include -I$(brew --prefix)/opt/sqlite/include -march=sandybridge" \
87+
CXXFLAGS="-I$(brew --prefix)/include -march=sandybridge" \
88+
LDFLAGS="-L$(brew --prefix)/lib -L$(brew --prefix)/opt/sqlite/lib" \
8789
cmake -DCMAKE_BUILD_TYPE=Release \
8890
-DCMAKE_PREFIX_PATH=$(brew --prefix)/opt/sqlite \
8991
-B build .
@@ -95,6 +97,7 @@ jobs:
9597
export PREFIX=$(brew --prefix)
9698
export PATH=${PREFIX}/opt/python@3.8/bin:${PREFIX}/opt/sqlite/bin:$PATH
9799
cd build
100+
otool -L test/capi_smoke_test
98101
ctest -V
99102
- name: prepare artifacts
100103
run: cp build/libgenomicsqlite.dylib include/genomicsqlite.h .

CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ else()
4848
target_link_libraries(genomicsqlite PRIVATE libsqlite3.so.0 SQLiteCpp zstd)
4949
endif()
5050

51-
52-
add_subdirectory(loaders)
53-
5451
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
52+
add_subdirectory(loaders)
53+
add_subdirectory(test)
5554
include(CTest)
5655
enable_testing()
5756
set(GENOMICSQLITE_TEST_ENV env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/bindings/python:${PYTHONPATH} LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:${LD_LIBRARY_PATH} GENOMICSQLITE_SYSTEM_LIBRARY=1)
58-
add_test(NAME smoketest COMMAND ${GENOMICSQLITE_TEST_ENV} python3 ${CMAKE_CURRENT_SOURCE_DIR}/test/genomicsqlite_smoke_test.py)
57+
add_test(NAME smoke_test COMMAND ${GENOMICSQLITE_TEST_ENV} python3 ${CMAKE_CURRENT_SOURCE_DIR}/test/genomicsqlite_smoke_test.py)
58+
add_test(NAME capi_smoke_test COMMAND ${GENOMICSQLITE_TEST_ENV} ${CMAKE_BINARY_DIR}/test/capi_smoke_test)
5959
add_test(NAME pytest COMMAND ${GENOMICSQLITE_TEST_ENV} python3 -m pytest -xv -n 4 --tb=short ${CMAKE_CURRENT_SOURCE_DIR}/test)
6060
endif()

bindings/python/release.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ if grep dirty <(git describe --always --dirty); then
99
>&2 echo "Cannot release dirty working tree"
1010
exit 1
1111
fi
12-
if [[ ! -f genomicsqlite/libgenomicsqlite.so ]]; then
13-
>&2 echo "Download the portable libgenomicsqlite.so to ${HERE}/genomicsqlite/"
12+
if [[ ! -f genomicsqlite/libgenomicsqlite.so ]] || [[ ! -f genomicsqlite/libgenomicsqlite.dylib ]]; then
13+
>&2 echo "Download the portable libgenomicsqlite.{so,dylib} to ${HERE}/genomicsqlite/"
1414
exit 1
1515
fi
1616
function cleanup {
17-
# force us to put it there each time; ensures a stale version can't be left behind
18-
rm -f genomicsqlite/libgenomicsqlite.so
17+
# force us to put libs on each attempt; ensures a stale version can't be left behind
18+
rm -f genomicsqlite/libgenomicsqlite.*
1919
}
2020
trap cleanup EXIT
2121

include/genomicsqlite.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
#ifndef SQLITE3EXT_H
12
#include <sqlite3.h>
3+
#endif
24

35
/*
46
* C bindings

src/genomicsqlite.cc

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,7 @@ using namespace std;
2323
* connection & tuning helpers
2424
**************************************************************************************************/
2525

26-
std::string GenomicSQLiteVersion() {
27-
// The newest SQLite feature currently required is "Generated Columns"
28-
const int MIN_SQLITE_VERSION_NUMBER = 3031000;
29-
const string MIN_SQLITE_VERSION = "3.31.0";
30-
if (sqlite3_libversion_number() < MIN_SQLITE_VERSION_NUMBER) {
31-
string version_msg = "SQLite library version (" + string(sqlite3_libversion()) +
32-
") is older than required by the GenomicSQLite extension (" +
33-
MIN_SQLITE_VERSION + ")";
34-
throw std::runtime_error(version_msg);
35-
}
36-
return string(GIT_REVISION);
37-
}
26+
std::string GenomicSQLiteVersion() { return string(GIT_REVISION); }
3827

3928
// boilerplate for C bindings to C++ functions
4029
#define C_WRAPPER(call) \
@@ -268,50 +257,37 @@ static void sqlfn_genomicsqlite_tuning_sql(sqlite3_context *ctx, int argc, sqlit
268257
SQL_WRAPPER(GenomicSQLiteTuningSQL(config_json, schema))
269258
}
270259

271-
bool _ext_loaded = false;
260+
static void ensure_ext_loaded() {
261+
// for C/C++ GenomicSQLiteOpen
262+
static bool ext_loaded = false;
263+
if (!ext_loaded) {
264+
SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
265+
db.loadExtension("libgenomicsqlite", nullptr);
266+
ext_loaded = true;
267+
}
268+
}
269+
272270
int GenomicSQLiteOpen(const string &dbfile, sqlite3 **ppDb, string &errmsg_out, int flags,
273271
const string &config_json) noexcept {
274-
// ensure extension is registered
275-
int ret;
276-
char *zErrmsg = nullptr;
277-
*ppDb = nullptr;
278-
if (!_ext_loaded) {
279-
ret =
280-
sqlite3_open_v2(":memory:", ppDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
281-
if (ret != SQLITE_OK) {
282-
errmsg_out = sqlite3_errstr(ret);
283-
return ret;
284-
}
285-
ret = sqlite3_load_extension(*ppDb, "libgenomicsqlite", nullptr, &zErrmsg);
286-
if (ret != SQLITE_OK) {
287-
errmsg_out = "failed loading libgenomicsqlite shared library: ";
288-
if (zErrmsg) {
289-
errmsg_out += zErrmsg;
290-
sqlite3_free(zErrmsg);
291-
} else {
292-
errmsg_out += sqlite3_errmsg(*ppDb);
293-
}
294-
sqlite3_close_v2(*ppDb);
295-
*ppDb = nullptr;
296-
return ret;
297-
}
298-
ret = sqlite3_close_v2(*ppDb);
299-
*ppDb = nullptr;
300-
if (ret != SQLITE_OK) {
301-
errmsg_out = sqlite3_errstr(ret);
302-
return ret;
303-
}
304-
_ext_loaded = true;
272+
try {
273+
ensure_ext_loaded();
274+
} catch (SQLite::Exception &exn) {
275+
errmsg_out = "failed loading libgenomicsqlite shared library: " + string(exn.what());
276+
return exn.getErrorCode();
277+
} catch (std::exception &exn) {
278+
errmsg_out = "failed loading libgenomicsqlite shared library: " + string(exn.what());
279+
return SQLITE_ERROR;
305280
}
306281

307282
// open as requested
308283
try {
309-
ret = sqlite3_open_v2(GenomicSQLiteURI(dbfile, config_json).c_str(), ppDb,
310-
SQLITE_OPEN_URI | flags, nullptr);
284+
int ret = sqlite3_open_v2(GenomicSQLiteURI(dbfile, config_json).c_str(), ppDb,
285+
SQLITE_OPEN_URI | flags, nullptr);
311286
if (ret != SQLITE_OK) {
312287
errmsg_out = sqlite3_errstr(ret);
313288
return ret;
314289
}
290+
char *zErrmsg = nullptr;
315291
ret = sqlite3_exec(*ppDb, GenomicSQLiteTuningSQL(config_json).c_str(), nullptr, nullptr,
316292
&zErrmsg);
317293
if (ret != SQLITE_OK) {
@@ -327,8 +303,10 @@ int GenomicSQLiteOpen(const string &dbfile, sqlite3 **ppDb, string &errmsg_out,
327303
}
328304
return SQLITE_OK;
329305
} catch (SQLite::Exception &exn) {
306+
errmsg_out = exn.what();
330307
return exn.getErrorCode();
331308
} catch (std::exception &exn) {
309+
errmsg_out = exn.what();
332310
return SQLITE_ERROR;
333311
}
334312
}
@@ -347,18 +325,9 @@ extern "C" int genomicsqlite_open(const char *filename, sqlite3 **ppDb, char **p
347325

348326
unique_ptr<SQLite::Database> GenomicSQLiteOpen(const string &dbfile, int flags,
349327
const string &config_json) {
350-
unique_ptr<SQLite::Database> db;
351-
if (!_ext_loaded) {
352-
db.reset(new SQLite::Database(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE));
353-
try {
354-
db->loadExtension("libgenomicsqlite", nullptr);
355-
} catch (std::exception &exn) {
356-
throw std::runtime_error("failed loading libgenomicsqlite shared library: " +
357-
string(exn.what()));
358-
}
359-
_ext_loaded = true;
360-
}
361-
db.reset(new SQLite::Database(GenomicSQLiteURI(dbfile, config_json), SQLITE_OPEN_URI | flags));
328+
ensure_ext_loaded();
329+
unique_ptr<SQLite::Database> db(
330+
new SQLite::Database(GenomicSQLiteURI(dbfile, config_json), SQLITE_OPEN_URI | flags));
362331
db->exec(GenomicSQLiteTuningSQL(config_json));
363332
return db;
364333
}

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_executable(capi_smoke_test capi_smoke_test.c)
2+
target_link_libraries(capi_smoke_test PRIVATE sqlite3 genomicsqlite)

test/capi_smoke_test.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "genomicsqlite.h"
2+
#include <errno.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
int sql_callback(void *ctx, int nCol, char **values, char **names) {
8+
fprintf(stderr, "sql_callback(%d,\"%s\")\n", nCol, values[0] ? values[0] : "");
9+
char *ans = (char *)ctx;
10+
if (!ans || !nCol || !values[0]) {
11+
return -1;
12+
}
13+
strcpy(ans, values[0]);
14+
return 0;
15+
}
16+
17+
int main(int argc, char **argv) {
18+
fprintf(stderr, "tempnam()\n");
19+
char *dbfilename = tempnam("/tmp", "gsqlt");
20+
if (!dbfilename) {
21+
fprintf(stderr, "tempnam -> %d\n", errno);
22+
return 1;
23+
}
24+
sqlite3 *pDb = 0;
25+
char *zErrMsg = 0;
26+
fprintf(stderr, "genomicsqlite_open()\n");
27+
int rc = genomicsqlite_open(dbfilename, &pDb, &zErrMsg,
28+
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, "{}");
29+
if (rc != SQLITE_OK) {
30+
fprintf(stderr, "genomicsqlite_open -> %d // %s\n", rc,
31+
zErrMsg ? zErrMsg : sqlite3_errstr(rc));
32+
return 1;
33+
}
34+
35+
fprintf(stderr, "genomicsqlite_version()\n");
36+
char *version1 = genomicsqlite_version();
37+
printf("%s\n", version1);
38+
fprintf(stderr, "sqlite3_free()\n");
39+
sqlite3_free(version1);
40+
41+
char version[1024];
42+
version[0] = 0;
43+
fprintf(stderr, "sqlite3_exec()\n");
44+
rc = sqlite3_exec(pDb, "SELECT genomicsqlite_version()", &sql_callback, version, &zErrMsg);
45+
if (rc != SQLITE_OK) {
46+
fprintf(stderr, "sqlite3_exec(\"SELECT genomicsqlite_version()\") -> %d // %s\n", rc,
47+
zErrMsg ? zErrMsg : sqlite3_errstr(rc));
48+
return 1;
49+
}
50+
if (!version[0]) {
51+
fprintf(stderr, "no result from sqlite3_exec(\"SELECT genomicsqlite_version()\")\n");
52+
return 1;
53+
}
54+
printf("%s\n", version);
55+
56+
fprintf(stderr, "create_genomic_range_index_sql()\n");
57+
char *sql = create_genomic_range_index_sql("test", "rid", "beg", "end", -1);
58+
if (!sql) {
59+
fprintf(stderr, "create_genomic_range_index_sql -> null\n");
60+
return 1;
61+
}
62+
printf("%s\n", sql);
63+
fprintf(stderr, "sqlite3_free()\n");
64+
sqlite3_free(sql);
65+
66+
fprintf(stderr, "sqlite3_close()\n");
67+
rc = sqlite3_close(pDb);
68+
if (rc != SQLITE_OK) {
69+
fprintf(stderr, "sqlite3_close -> %d %s\n", rc, sqlite3_errstr(rc));
70+
return 1;
71+
}
72+
return 0;
73+
}

0 commit comments

Comments
 (0)