diff --git a/sqlite/capi.kk b/sqlite/capi.kk index 3124760..098a441 100644 --- a/sqlite/capi.kk +++ b/sqlite/capi.kk @@ -80,20 +80,29 @@ pub extern column-text(^stmt: any, col: int32): string // pub extern bind-blob(^stmt: any, col: int32, ^value: bytes): int32 // c "kk_sqlite3_bind_blob" -pub extern bind-double(^stmt: any, col: int32, ^value: float64): int32 +pub extern bind-double(^stmt: any, param: int32, ^value: float64): int32 c "kk_sqlite3_bind_double" -pub extern bind-int64(^stmt: any, col: int32, value: int64): int32 +pub extern bind-int64(^stmt: any, param: int32, value: int64): int32 c "kk_sqlite3_bind_int64" -pub extern bind-null(^stmt: any, col: int32): int32 +pub extern bind-null(^stmt: any, param: int32): int32 c "kk_sqlite3_bind_null" -pub extern bind-text(^stmt: any, col: int32, ^value: string): int32 +pub extern bind-text(^stmt: any, param: int32, ^value: string): int32 c "kk_sqlite3_bind_text" -pub extern bind-zeroblob(^stmt: any, col: int32, length: int64): int32 +pub extern bind-zeroblob(^stmt: any, param: int32, length: int64): int32 c "kk_sqlite3_bind_zeroblob" pub extern clear-bindings(^stmt: any): int32 c "kk_sqlite3_clear_bindings" + +pub extern parameter-count(^stmt: any): int32 + c "kk_sqlite3_parameter_count" + +pub extern parameter-name(^stmt: any, param: int32): string + c "kk_sqlite3_parameter_name" + +pub extern parameter-index(^stmt: any, name: string): int32 + c "kk_sqlite3_parameter_index" diff --git a/sqlite/sqlite-inline.c b/sqlite/sqlite-inline.c index 0c22e5b..569e600 100644 --- a/sqlite/sqlite-inline.c +++ b/sqlite/sqlite-inline.c @@ -7,6 +7,8 @@ static inline sqlite3 *borrow_db(kk_box_t cref, kk_context_t *_ctx) { kk_string_t kk_sqlite3_errstr(int32_t x, kk_context_t *_ctx) { const char *s = sqlite3_errstr((int)x); + // NOTE(zephyr): kk_string_alloc_from_utf8 calls C stdlib strlen(), + // which is not guaranteed to handle a NULL pointer. if (s == NULL) { return kk_string_empty(); } @@ -116,34 +118,54 @@ kk_string_t kk_sqlite3_column_text(kk_box_t cref, int32_t col, kk_context_t *_ct return kk_string_alloc_from_qutf8n((kk_ssize_t)len, (const char *)text, _ctx); } -int32_t kk_sqlite3_bind_double(kk_box_t cref, int32_t col, double value, kk_context_t *_ctx) { +int32_t kk_sqlite3_bind_double(kk_box_t cref, int32_t param, double value, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); - return sqlite3_bind_double(stmt, col, value); + return sqlite3_bind_double(stmt, param, value); } -int32_t kk_sqlite3_bind_int64(kk_box_t cref, int32_t col, int64_t value, kk_context_t *_ctx) { +int32_t kk_sqlite3_bind_int64(kk_box_t cref, int32_t param, int64_t value, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); - return sqlite3_bind_int64(stmt, col, (sqlite3_int64)value); + return sqlite3_bind_int64(stmt, param, (sqlite3_int64)value); } -int32_t kk_sqlite3_bind_null(kk_box_t cref, int32_t col, kk_context_t *_ctx) { +int32_t kk_sqlite3_bind_null(kk_box_t cref, int32_t param, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); - return sqlite3_bind_null(stmt, col); + return sqlite3_bind_null(stmt, param); } -int32_t kk_sqlite3_bind_text(kk_box_t cref, int32_t col, kk_string_t value, kk_context_t *_ctx) { +int32_t kk_sqlite3_bind_text(kk_box_t cref, int32_t param, kk_string_t value, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); kk_ssize_t len = 0; const char *text = kk_string_cbuf_borrow(value, &len, _ctx); - return sqlite3_bind_text64(stmt, col, text, (sqlite3_uint64)len, SQLITE_TRANSIENT, SQLITE_UTF8); + return sqlite3_bind_text64(stmt, param, text, (sqlite3_uint64)len, SQLITE_TRANSIENT, SQLITE_UTF8); } -int32_t kk_sqlite3_bind_zeroblob(kk_box_t cref, int32_t col, int64_t length, kk_context_t *_ctx) { +int32_t kk_sqlite3_bind_zeroblob(kk_box_t cref, int32_t param, int64_t length, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); - return sqlite3_bind_zeroblob64(stmt, col, (sqlite3_uint64)length); + return sqlite3_bind_zeroblob64(stmt, param, (sqlite3_uint64)length); } int32_t kk_sqlite3_clear_bindings(kk_box_t cref, kk_context_t *_ctx) { sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); return sqlite3_clear_bindings(stmt); } + +int32_t kk_sqlite3_parameter_count(kk_box_t cref, kk_context_t *_ctx) { + sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); + return (int32_t)sqlite3_bind_parameter_count(stmt); +} + +kk_string_t kk_sqlite3_parameter_name(kk_box_t cref, int32_t param, kk_context_t *_ctx) { + sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); + const char *name = sqlite3_bind_parameter_name(stmt, (int)param); + if (name == NULL) { + return kk_string_empty(); + } + return kk_string_alloc_from_utf8(name, _ctx); +} + +int32_t kk_sqlite3_parameter_index(kk_box_t cref, kk_string_t name, kk_context_t *_ctx) { + sqlite3_stmt *stmt = borrow_stmt(cref, _ctx); + const char *s = kk_string_cbuf_borrow(name, NULL, _ctx); + return (int32_t)sqlite3_bind_parameter_index(stmt, s); +} diff --git a/sqlite/sqlite3.kk b/sqlite/sqlite3.kk index 66023ba..d717cf4 100644 --- a/sqlite/sqlite3.kk +++ b/sqlite/sqlite3.kk @@ -197,3 +197,17 @@ pub fun statement/bind-zeroblob(stmt: statement, param: int, length: int64): sql // Set all bound parameters to NULL. pub fun statement/clear-bindings(stmt: statement): sqlite-result capi/clear-bindings(stmt.cref).trusted-result + +// Get the number of bindable parameters in the statement. +pub fun statement/param-count(stmt: statement): int + capi/parameter-count(stmt.cref).int + +// Get the name of a parameter. +// The first parameter number is 1. +pub fun statement/param-name(stmt: statement, param: int): string + capi/parameter-name(stmt.cref, param.int32) + +// Get the index of the parameter with the given name. +// The result is suitable to pass to bind functions. +pub fun statement/param-index(stmt: statement, name: string): int + capi/parameter-index(stmt.cref, name).int diff --git a/test/test.kk b/test/test.kk index cc8da20..b158cfb 100644 --- a/test/test.kk +++ b/test/test.kk @@ -10,17 +10,17 @@ tail fun do-while(f: () ->