Skip to content

Commit

Permalink
Adding new DuckDB Driver.
Browse files Browse the repository at this point in the history
  • Loading branch information
sparked435 committed Sep 26, 2024
1 parent fb0d2c7 commit 20cf843
Show file tree
Hide file tree
Showing 7 changed files with 869 additions and 13 deletions.
3 changes: 2 additions & 1 deletion DBI.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ local name_to_module = {
SQLite3 = 'dbd.sqlite3',
DB2 = 'dbd.db2',
Oracle = 'dbd.oracle',
ODBC = 'dbd.odbc'
ODBC = 'dbd.odbc',
DuckDB = 'dbd.duckdb'
}

local string = require('string')
Expand Down
32 changes: 25 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ MKDIR ?= mkdir -p
INSTALL ?= install
INSTALL_PROGRAM ?= $(INSTALL)
INSTALL_DATA ?= $(INSTALL) -m 644
LUA_V ?= 5.1
LUA_V ?= 5.4
LUA_LDIR ?= /usr/share/lua/$(LUA_V)
LUA_CDIR ?= /usr/lib/lua/$(LUA_V)

COMMON_CFLAGS ?= -g -pedantic -Wall -O2 -shared -fPIC -DPIC -std=c99
COMMON_CFLAGS ?= -g -pedantic -Wall -O2 -shared -fPIC -DPIC -std=c99
LUA_INC ?= -I/usr/include/lua$(LUA_V)
MYSQL_INC ?= -I/usr/include/mysql
PSQL_INC ?= -I/usr/include/postgresql
SQLITE3_INC ?= -I/usr/include
DUCKDB_INC ?= -I/usr/include
DB2_INC ?= -I/opt/ibm/db2exc/V9.5/include
ORACLE_INC ?= -I/usr/lib/oracle/xe/app/oracle/product/10.2.0/client/rdbms/public
CF = $(LUA_INC) $(COMMON_CFLAGS) $(CFLAGS) -I.
Expand All @@ -23,13 +24,15 @@ COMMON_LDFLAGS ?= -shared
MYSQL_LDFLAGS ?= -lmysqlclient
PSQL_LDFLAGS ?= -lpq
SQLITE3_LDFLAGS ?= -lsqlite3
DUCKDB_LDFLAGS ?= -lduckdb
DB2_LDFLAGS ?= -L/opt/ibm/db2exc/V9.5/lib64 -L/opt/ibm/db2exc/V9.5/lib32 -ldb2
ORACLE_LDFLAGS ?= -L/usr/lib/oracle/xe/app/oracle/product/10.2.0/client/lib/ -locixe
LF = $(COMMON_LDFLAGS) $(LDFLAGS)

MYSQL_FLAGS = $(CF) $(LF) $(MYSQL_INC) $(MYSQL_LDFLAGS)
PSQL_FLAGS = $(CF) $(LF) $(PSQL_INC) $(PSQL_LDFLAGS)
SQLITE3_FLAGS = $(CF) $(LF) $(SQLITE3_INC) $(SQLITE3_LDFLAGS)
DUCKDB_FLAGS = $(CF) $(LF) $(DUCKDB_INC) $(DUCKDB_LDFLAGS)
DB2_FLAGS = $(CF) $(LF) $(DB2_INC) $(DB2_LDFLAGS)
ORACLE_FLAGS = $(CF) $(LF) $(ORACLE_INC) $(ORACLE_LDFLAGS) -DORA_ENABLE_PING -DORA_ENABLE_TAF

Expand All @@ -39,19 +42,21 @@ BUILDDIR = build
DBDMYSQL = dbd/mysql.so
DBDPSQL = dbd/postgresql.so
DBDSQLITE3 = dbd/sqlite3.so
DBDDUCKDB = dbd/duckdb.so
DBDDB2 = dbd/db2.so
DBDORACLE = dbd/oracle.so

OBJS = build/dbd_common.o
MYSQL_OBJS = $(OBJS) build/dbd_mysql_main.o build/dbd_mysql_connection.o build/dbd_mysql_statement.o
PSQL_OBJS = $(OBJS) build/dbd_postgresql_main.o build/dbd_postgresql_connection.o build/dbd_postgresql_statement.o
SQLITE3_OBJS = $(OBJS) build/dbd_sqlite3_main.o build/dbd_sqlite3_connection.o build/dbd_sqlite3_statement.o
DUCKDB_OBJS = $(OBJS) build/dbd_duckdb_main.o build/dbd_duckdb_connection.o build/dbd_duckdb_statement.o
DB2_OBJS = $(OBJS) build/dbd_db2_main.o build/dbd_db2_connection.o build/dbd_db2_statement.o
ORACLE_OBJS = $(OBJS) build/dbd_oracle_main.o build/dbd_oracle_connection.o build/dbd_oracle_statement.o

free: mysql psql sqlite3
free: mysql psql sqlite3 duckdb

all: mysql psql sqlite3 db2 oracle
all: mysql psql sqlite3 duckdb db2 oracle

mysql: $(BUILDDIR) $(MYSQL_OBJS)
$(CC) $(MYSQL_OBJS) -o $(DBDMYSQL) $(MYSQL_FLAGS)
Expand All @@ -62,14 +67,17 @@ psql: $(BUILDDIR) $(PSQL_OBJS)
sqlite3: $(BUILDDIR) $(SQLITE3_OBJS)
$(CC) $(SQLITE3_OBJS) -o $(DBDSQLITE3) $(SQLITE3_FLAGS)

duckdb: $(BUILDDIR) $(DUCKDB_OBJS)
$(CC) $(DUCKDB_OBJS) -o $(DBDDUCKDB) $(DUCKDB_FLAGS)

db2: $(BUILDDIR) $(DB2_OBJS)
$(CC) $(DB2_OBJS) -o $(DBDDB2) $(DB2_FLAGS)

oracle: $(BUILDDIR) $(ORACLE_OBJS)
$(CC) $(ORACLE_OBJS) -o $(DBDORACLE) $(ORACLE_FLAGS)

clean:
$(RM) $(MYSQL_OBJS) $(PSQL_OBJS) $(SQLITE3_OBJS) $(DB2_OBJS) $(ORACLE_OBJS) $(DBDMYSQL) $(DBDPSQL) $(DBDSQLITE3) $(DBDDB2) $(DBDORACLE)
$(RM) $(MYSQL_OBJS) $(PSQL_OBJS) $(SQLITE3_OBJS) $(DB2_OBJS) $(ORACLE_OBJS) $(DBDMYSQL) $(DBDPSQL) $(DBDSQLITE3) $(DBDDB2) $(DBDORACLE) $(DUCKDB_OBJS)

build/dbd_common.o: dbd/common.c dbd/common.h
$(CC) -c -o $@ $< $(CF)
Expand All @@ -95,6 +103,13 @@ build/dbd_sqlite3_main.o: dbd/sqlite3/main.c dbd/sqlite3/dbd_sqlite3.h dbd/commo
build/dbd_sqlite3_statement.o: dbd/sqlite3/statement.c dbd/sqlite3/dbd_sqlite3.h dbd/common.h
$(CC) -c -o $@ $< $(SQLITE3_FLAGS)

build/dbd_duckdb_connection.o: dbd/duckdb/connection.c dbd/duckdb/dbd_duckdb.h dbd/common.h
$(CC) -c -o $@ $< $(DUCKDB_FLAGS)
build/dbd_duckdb_main.o: dbd/duckdb/main.c dbd/duckdb/dbd_duckdb.h dbd/common.h
$(CC) -c -o $@ $< $(DUCKDB_FLAGS)
build/dbd_duckdb_statement.o: dbd/duckdb/statement.c dbd/duckdb/dbd_duckdb.h dbd/common.h
$(CC) -c -o $@ $< $(DUCKDB_FLAGS)

build/dbd_db2_connection.o: dbd/db2/connection.c dbd/db2/dbd_db2.h dbd/common.h
$(CC) -c -o $@ $< $(DB2_FLAGS)
build/dbd_db2_main.o: dbd/db2/main.c dbd/db2/dbd_db2.h dbd/common.h
Expand Down Expand Up @@ -124,12 +139,15 @@ install_psql: psql install_lua
install_sqlite3: sqlite3 install_lua
$(INSTALL_PROGRAM) -D $(DBDSQLITE3) $(DESTDIR)$(LUA_CDIR)/$(DBDSQLITE3)

install_duckdb: duckdb install_lua
$(INSTALL_PROGRAM) -D $(DBDDUCKDB) $(DESTDIR)$(LUA_CDIR)/$DBDDUCKDB)

install_db2: db2 install_lua
$(INSTALL_PROGRAM) -D $(DBDDB2) $(DESTDIR)$(LUA_CDIR)/$(DBDDB2)

install_oracle: oracle install_lua
$(INSTALL_PROGRAM) -D $(DBDORACLE) $(DESTDIR)$(LUA_CDIR)/$(DBDORACLE)

install_free: install_lua install_mysql install_psql install_sqlite3
install_free: install_lua install_mysql install_psql install_sqlite3 install_duckdb

install_all: install_lua install_mysql install_psql install_sqlite3 install_db2 install_oracle
install_all: install_lua install_mysql install_psql install_sqlite3 install_duckdb install_db2 install_oracle
220 changes: 220 additions & 0 deletions dbd/duckdb/connection.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#include "dbd_duckdb.h"


int dbd_duckdb_statement_create(lua_State *L, connection_t *conn, const char *sql_query);


/*
* connection,err = DBD.DuckDB.New(dbfile)
*/
static int connection_new(lua_State *L) {
int n = lua_gettop(L);

char *errmessage;
const char *db = NULL;
connection_t *conn = NULL;

switch(n) {
default:
/*
* db is the only parameter for now
*/
db = luaL_checkstring(L, 1);
}

conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t));
conn->autocommit = 1;
conn->in_transaction = 0;

if (duckdb_open_ext( db, &(conn->db), NULL, &errmessage ) == DuckDBError) {
lua_pushnil(L);
lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, errmessage);

duckdb_free(errmessage);
return 2;
}

if (duckdb_connect( conn->db, &(conn->conn) ) == DuckDBError) {
duckdb_close( &(conn->db) );

lua_pushnil(L);
lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED);
return 2;
}

luaL_getmetatable(L, DBD_DUCKDB_CONNECTION);
lua_setmetatable(L, -2);

return 1;
}


static int connection_prepare(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

if (conn->conn) {
return dbd_duckdb_statement_create(L, conn, luaL_checkstring(L, 2));
}

lua_pushnil(L);
lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE);
return 2;
}


static int connection_commit(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

if (duckdb_query(conn->conn, "COMMIT;", NULL) == DuckDBError) {
lua_pushboolean(L, 0);
return 0;
}

conn->in_transaction = 0;
lua_pushboolean(L, 1);
return 1;
}


static int connection_rollback(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

if (duckdb_query(conn->conn, "ROLLBACK;", NULL) == DuckDBError) {
lua_pushboolean(L, 0);
return 0;
}

conn->in_transaction = 0;
lua_pushboolean(L, 1);
return 1;
}


static int connection_autocommit(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);
bool mode = lua_toboolean(L, 1);

// no change
if (conn->autocommit == mode) {
lua_pushboolean(L, 1);
return 1;
}

// enable autocommit while in a transaction means commit it
if (conn->in_transaction) {
if (mode) {
if (duckdb_query(conn->conn, "COMMIT;", NULL) == DuckDBError) {
lua_pushboolean(L, 0);
return 0;
}

conn->in_transaction = 0;
}
}

conn->autocommit = mode;
lua_pushboolean(L, 1);
return 1;
}

static int connection_ping(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

int ok = 1;

if (!conn->db) {
ok = 0;
} else if (!conn->conn) {
ok = 0;
}

lua_pushboolean(L, ok);
return 1;
}


static int connection_close(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

duckdb_disconnect(&(conn->conn));
conn->conn = NULL;

duckdb_close(&(conn->db));
conn->db = NULL;

lua_pushboolean(L, 1);
return 1;
}


/*
* last_id = connection:last_id()
*/
static int connection_lastid(lua_State *L) {
luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DUCKDB_CONNECTION, "last_id");
return 0;
}


/*
* num_rows = statement:rowcount()
*/
static int connection_quote(lua_State *L) {
luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DUCKDB_CONNECTION, "quote");
return 0;
}


/*
* __gc
*/
static int connection_gc(lua_State *L) {
/* always close the connection */
connection_close(L);

return 0;
}


/*
* __tostring
*/
static int connection_tostring(lua_State *L) {
connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DUCKDB_CONNECTION);

lua_pushfstring(L, "%s: %p", DBD_DUCKDB_CONNECTION, conn);

return 1;
}


int dbd_duckdb_connection(lua_State *L) {
/*
* instance methods
*/
static const luaL_Reg connection_methods[] = {
{"autocommit", connection_autocommit},
{"close", connection_close},
{"commit", connection_commit},
{"ping", connection_ping},
{"prepare", connection_prepare},
{"quote", connection_quote},
{"rollback", connection_rollback},
{"last_id", connection_lastid},
{NULL, NULL}
};

/*
* class methods
*/
static const luaL_Reg connection_class_methods[] = {
{"New", connection_new},
{NULL, NULL}
};

dbd_register(L, DBD_DUCKDB_CONNECTION,
connection_methods, connection_class_methods,
connection_gc, connection_tostring);

return 1;
}
Loading

0 comments on commit 20cf843

Please sign in to comment.