mirror of
https://github.com/janet-lang/janet
synced 2024-11-17 14:14:49 +00:00
Remove direct interaction with prepared statements from sql.
This commit is contained in:
parent
63eff235b0
commit
6e45b96644
@ -25,16 +25,13 @@
|
|||||||
|
|
||||||
#define FLAG_CLOSED 1
|
#define FLAG_CLOSED 1
|
||||||
|
|
||||||
|
#define MSG_DB_CLOSED "database already closed"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sqlite3* handle;
|
sqlite3* handle;
|
||||||
int flags;
|
int flags;
|
||||||
} Db;
|
} Db;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
sqlite3_stmt* handle;
|
|
||||||
int flags;
|
|
||||||
} Stmt;
|
|
||||||
|
|
||||||
/* Close a db, noop if already closed */
|
/* Close a db, noop if already closed */
|
||||||
static void closedb(Db *db) {
|
static void closedb(Db *db) {
|
||||||
if (!(db->flags & FLAG_CLOSED)) {
|
if (!(db->flags & FLAG_CLOSED)) {
|
||||||
@ -43,14 +40,6 @@ static void closedb(Db *db) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close prepared statement, noop if already closed */
|
|
||||||
static void closestmt(Stmt *stmt) {
|
|
||||||
if (!(stmt->flags & FLAG_CLOSED)) {
|
|
||||||
stmt->flags |= FLAG_CLOSED;
|
|
||||||
sqlite3_finalize(stmt->handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called to garbage collect a sqlite3 connection */
|
/* Called to garbage collect a sqlite3 connection */
|
||||||
static int gcsqlite(void *p, size_t s) {
|
static int gcsqlite(void *p, size_t s) {
|
||||||
(void) s;
|
(void) s;
|
||||||
@ -59,27 +48,12 @@ static int gcsqlite(void *p, size_t s) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called to collect a sqlite3 prepared statement */
|
|
||||||
static int gcstmt(void *p, size_t s) {
|
|
||||||
(void) s;
|
|
||||||
Stmt *stmt = (Stmt *)p;
|
|
||||||
closestmt(stmt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const DstAbstractType sql_conn_type = {
|
static const DstAbstractType sql_conn_type = {
|
||||||
":sqlite3.connection",
|
":sqlite3.connection",
|
||||||
gcsqlite,
|
gcsqlite,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const DstAbstractType sql_stmt_type = {
|
|
||||||
":sqlite3.statement",
|
|
||||||
gcstmt,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Open a new database connection */
|
/* Open a new database connection */
|
||||||
static int sql_open(DstArgs args) {
|
static int sql_open(DstArgs args) {
|
||||||
sqlite3 *conn;
|
sqlite3 *conn;
|
||||||
@ -118,35 +92,6 @@ static int has_null(const uint8_t *str, int32_t len) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a prepared statement */
|
|
||||||
static int sql_prepare(DstArgs args) {
|
|
||||||
Db *db;
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
const uint8_t *zSql;
|
|
||||||
int status;
|
|
||||||
DST_FIXARITY(args, 2);
|
|
||||||
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
|
||||||
db = (Db *)dst_unwrap_abstract(args.v[0]);
|
|
||||||
DST_ARG_STRING(zSql, args, 1);
|
|
||||||
status = sqlite3_prepare_v2(db->handle, (const char *)zSql, -1, &stmt, NULL);
|
|
||||||
if (status == SQLITE_OK) {
|
|
||||||
Stmt *sp = (Stmt *)dst_abstract(&sql_stmt_type, sizeof(Stmt));
|
|
||||||
sp->handle = stmt;
|
|
||||||
sp->flags = 0;
|
|
||||||
DST_RETURN_ABSTRACT(args, sp);
|
|
||||||
}
|
|
||||||
DST_THROW(args, sqlite3_errmsg(db->handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finalize a prepared statement */
|
|
||||||
static int sql_finalize(DstArgs args) {
|
|
||||||
DST_FIXARITY(args, 1);
|
|
||||||
DST_CHECKABSTRACT(args, 0, &sql_stmt_type);
|
|
||||||
Stmt *stmt = (Stmt *) dst_unwrap_abstract(args.v[0]);
|
|
||||||
closestmt(stmt);
|
|
||||||
DST_RETURN_NIL(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bind a single parameter */
|
/* Bind a single parameter */
|
||||||
static const char *bind1(sqlite3_stmt *stmt, int index, Dst value) {
|
static const char *bind1(sqlite3_stmt *stmt, int index, Dst value) {
|
||||||
int res;
|
int res;
|
||||||
@ -249,7 +194,7 @@ static const char *bindmany(sqlite3_stmt *stmt, Dst params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Execute a statement but don't collect results */
|
/* Execute a statement but don't collect results */
|
||||||
static const char *execute_drop(sqlite3_stmt *stmt) {
|
static const char *execute(sqlite3_stmt *stmt) {
|
||||||
int status;
|
int status;
|
||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
do {
|
do {
|
||||||
@ -264,7 +209,7 @@ static const char *execute_drop(sqlite3_stmt *stmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Execute and return values from prepared statement */
|
/* Execute and return values from prepared statement */
|
||||||
static const char *execute(sqlite3_stmt *stmt, DstArray *rows) {
|
static const char *execute_collect(sqlite3_stmt *stmt, DstArray *rows) {
|
||||||
/* Count number of columns in result */
|
/* Count number of columns in result */
|
||||||
int ncol = sqlite3_column_count(stmt);
|
int ncol = sqlite3_column_count(stmt);
|
||||||
int status;
|
int status;
|
||||||
@ -326,29 +271,6 @@ static const char *execute(sqlite3_stmt *stmt, DstArray *rows) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run a prepared statement */
|
|
||||||
static int sql_exec(DstArgs args) {
|
|
||||||
DST_MINARITY(args, 1);
|
|
||||||
DST_MAXARITY(args, 2);
|
|
||||||
DST_CHECKABSTRACT(args, 0, &sql_stmt_type);
|
|
||||||
Stmt *stmt = (Stmt *)dst_unwrap_abstract(args.v[0]);
|
|
||||||
if (args.n == 2) {
|
|
||||||
const char *err = bindmany(stmt->handle, args.v[1]);
|
|
||||||
if (err) {
|
|
||||||
DST_THROW(args, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DstArray *rows = dst_array(10);
|
|
||||||
const char *err = execute(stmt->handle, rows);
|
|
||||||
/* Reset the statement */
|
|
||||||
sqlite3_reset(stmt->handle);
|
|
||||||
sqlite3_clear_bindings(stmt->handle);
|
|
||||||
if (err) {
|
|
||||||
DST_THROW(args, err);
|
|
||||||
}
|
|
||||||
DST_RETURN_ARRAY(args, rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Evaluate a string of sql */
|
/* Evaluate a string of sql */
|
||||||
static int sql_eval(DstArgs args) {
|
static int sql_eval(DstArgs args) {
|
||||||
const char *err;
|
const char *err;
|
||||||
@ -359,6 +281,9 @@ static int sql_eval(DstArgs args) {
|
|||||||
DST_MAXARITY(args, 3);
|
DST_MAXARITY(args, 3);
|
||||||
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||||
Db *db = (Db *)dst_unwrap_abstract(args.v[0]);
|
Db *db = (Db *)dst_unwrap_abstract(args.v[0]);
|
||||||
|
if (db->flags & FLAG_CLOSED) {
|
||||||
|
DST_THROW(args, MSG_DB_CLOSED);
|
||||||
|
}
|
||||||
DST_ARG_STRING(query, args, 1);
|
DST_ARG_STRING(query, args, 1);
|
||||||
if (has_null(query, dst_string_length(query))) {
|
if (has_null(query, dst_string_length(query))) {
|
||||||
err = "cannot have embedded NULL in sql statememts";
|
err = "cannot have embedded NULL in sql statememts";
|
||||||
@ -378,13 +303,13 @@ static int sql_eval(DstArgs args) {
|
|||||||
if (NULL == stmt_next) {
|
if (NULL == stmt_next) {
|
||||||
/* Execute current statement and collect results */
|
/* Execute current statement and collect results */
|
||||||
if (stmt) {
|
if (stmt) {
|
||||||
err = execute(stmt, rows);
|
err = execute_collect(stmt, rows);
|
||||||
if (err) goto error;
|
if (err) goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Execute and finalize current statement */
|
/* Execute current statement but don't collect results. */
|
||||||
if (stmt) {
|
if (stmt) {
|
||||||
err = execute_drop(stmt);
|
err = execute(stmt);
|
||||||
if (err) goto error;
|
if (err) goto error;
|
||||||
}
|
}
|
||||||
/* Bind params to next statement*/
|
/* Bind params to next statement*/
|
||||||
@ -434,6 +359,9 @@ static int sql_last_insert_rowid(DstArgs args) {
|
|||||||
DST_FIXARITY(args, 1);
|
DST_FIXARITY(args, 1);
|
||||||
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||||
Db *db = (Db *)dst_unwrap_abstract(args.v[0]);
|
Db *db = (Db *)dst_unwrap_abstract(args.v[0]);
|
||||||
|
if (db->flags & FLAG_CLOSED) {
|
||||||
|
DST_THROW(args, MSG_DB_CLOSED);
|
||||||
|
}
|
||||||
sqlite3_int64 id = sqlite3_last_insert_rowid(db->handle);
|
sqlite3_int64 id = sqlite3_last_insert_rowid(db->handle);
|
||||||
if (id >= INT32_MIN && id <= INT32_MAX) {
|
if (id >= INT32_MIN && id <= INT32_MAX) {
|
||||||
DST_RETURN_INTEGER(args, (int32_t) id);
|
DST_RETURN_INTEGER(args, (int32_t) id);
|
||||||
@ -442,10 +370,17 @@ static int sql_last_insert_rowid(DstArgs args) {
|
|||||||
DST_RETURN_STRING(args, coerce_int64(id));
|
DST_RETURN_STRING(args, coerce_int64(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Get the sqlite3 errcode */
|
||||||
static int sql_changes(DstArgs args) {}
|
static int sql_error_code(DstArgs args) {
|
||||||
static int sql_timeout(DstArgs args) {}
|
DST_FIXARITY(args, 1);
|
||||||
*/
|
DST_CHECKABSTRACT(args, 0, &sql_conn_type);
|
||||||
|
Db *db = (Db *)dst_unwrap_abstract(args.v[0]);
|
||||||
|
if (db->flags & FLAG_CLOSED) {
|
||||||
|
DST_THROW(args, MSG_DB_CLOSED);
|
||||||
|
}
|
||||||
|
int errcode = sqlite3_errcode(db->handle);
|
||||||
|
DST_RETURN_INTEGER(args, errcode);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
@ -453,13 +388,8 @@ static const DstReg cfuns[] = {
|
|||||||
{"open", sql_open},
|
{"open", sql_open},
|
||||||
{"close", sql_close},
|
{"close", sql_close},
|
||||||
{"eval", sql_eval},
|
{"eval", sql_eval},
|
||||||
{"prepare", sql_prepare},
|
|
||||||
{"exec", sql_exec},
|
|
||||||
{"finalize", sql_finalize},
|
|
||||||
{"last-insert-rowid", sql_last_insert_rowid},
|
{"last-insert-rowid", sql_last_insert_rowid},
|
||||||
/*{"changes", sql_changes},*/
|
{"error-code", sql_error_code},
|
||||||
/*{"timeout", sql_timeout},*/
|
|
||||||
/*{"rowid", sql_rowid},*/
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user