get column values
This commit is contained in:
@@ -47,3 +47,27 @@ pub extern step(^stmt: any): int32
|
|||||||
|
|
||||||
pub extern reset(^stmt: any): int32
|
pub extern reset(^stmt: any): int32
|
||||||
c "kk_sqlite3_reset"
|
c "kk_sqlite3_reset"
|
||||||
|
|
||||||
|
pub extern column-count(^stmt: any): int
|
||||||
|
c "kk_sqlite3_column_count"
|
||||||
|
|
||||||
|
pub extern column-type(^stmt: any, col: int32): int32
|
||||||
|
c "kk_sqlite3_column_type"
|
||||||
|
pub extern int32/integer(): int32 { c inline "SQLITE_INTEGER" }
|
||||||
|
pub extern int32/float(): int32 { c inline "SQLITE_FLOAT" }
|
||||||
|
pub extern int32/blob(): int32 { c inline "SQLITE_BLOB" }
|
||||||
|
pub extern int32/null(): int32 { c inline "SQLITE_NULL" }
|
||||||
|
pub extern int32/text(): int32 { c inline "SQLITE_TEXT" }
|
||||||
|
|
||||||
|
//TODO(zephyr): waiting on a proper bytes type in koka
|
||||||
|
// pub extern column-blob(^stmt: any, col: int32): maybe<bytes>
|
||||||
|
// c "kk_sqlite3_column_blob"
|
||||||
|
|
||||||
|
pub extern column-double(^stmt: any, col: int32): float64
|
||||||
|
c "kk_sqlite3_column_double"
|
||||||
|
|
||||||
|
pub extern column-integer(^stmt: any, col: int32): int
|
||||||
|
c "kk_sqlite3_column_integer"
|
||||||
|
|
||||||
|
pub extern column-text(^stmt: any, col: int32): string
|
||||||
|
c "kk_sqlite3_column_text"
|
||||||
|
|||||||
@@ -81,3 +81,37 @@ int32_t kk_sqlite3_reset(kk_box_t cref, kk_context_t *_ctx) {
|
|||||||
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
return (int32_t)sqlite3_reset(stmt);
|
return (int32_t)sqlite3_reset(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kk_integer_t kk_sqlite3_column_count(kk_box_t cref, kk_context_t *_ctx) {
|
||||||
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
|
int r = sqlite3_column_count(stmt);
|
||||||
|
return kk_integer_from_int(r, _ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t kk_sqlite3_column_type(kk_box_t cref, int32_t col, kk_context_t *_ctx) {
|
||||||
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
|
return (int32_t)sqlite3_column_type(stmt, (int)col);
|
||||||
|
}
|
||||||
|
|
||||||
|
double kk_sqlite3_column_double(kk_box_t cref, int32_t col, kk_context_t *_ctx) {
|
||||||
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
|
return sqlite3_column_double(stmt, (int)col);
|
||||||
|
}
|
||||||
|
|
||||||
|
kk_integer_t kk_sqlite3_column_integer(kk_box_t cref, int32_t col, kk_context_t *_ctx) {
|
||||||
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
|
sqlite3_int64 r = sqlite3_column_int64(stmt, (int)col);
|
||||||
|
return kk_integer_from_int64((int64_t)r, _ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
kk_string_t kk_sqlite3_column_text(kk_box_t cref, int32_t col, kk_context_t *_ctx) {
|
||||||
|
sqlite3_stmt *stmt = borrow_stmt(cref, _ctx);
|
||||||
|
const unsigned char *text = sqlite3_column_text(stmt, (int)col);
|
||||||
|
if (text == NULL) {
|
||||||
|
// The column value is NULL, but we can't put that in a Koka string.
|
||||||
|
// Since a string was requested, return an empty string instead.
|
||||||
|
return kk_string_empty();
|
||||||
|
}
|
||||||
|
int len = sqlite3_column_bytes(stmt, (int)col);
|
||||||
|
return kk_string_alloc_from_qutf8n((kk_ssize_t)len, (const char *)text, _ctx);
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,6 +95,10 @@ pub fun close(db: sqlite3): sqlite-result
|
|||||||
abstract struct statement
|
abstract struct statement
|
||||||
cref: any
|
cref: any
|
||||||
|
|
||||||
|
// Prepare a statement.
|
||||||
|
// The Right value contains the prepared statement and the portion of `sql`
|
||||||
|
// remaining after parsing the first statement.
|
||||||
|
// Once use is finished, the statement must be `finalize`d.
|
||||||
pub fun prepare(db: sqlite3, sql: sslice, persistent: bool = False, disable-vtab: bool = False, disable-log: bool = False): either<sqlite-result, (statement, sslice)>
|
pub fun prepare(db: sqlite3, sql: sslice, persistent: bool = False, disable-vtab: bool = False, disable-log: bool = False): either<sqlite-result, (statement, sslice)>
|
||||||
val flags = 0.i32
|
val flags = 0.i32
|
||||||
.or(persistent.int32 * 0x01.i32)
|
.or(persistent.int32 * 0x01.i32)
|
||||||
@@ -106,11 +110,61 @@ pub fun prepare(db: sqlite3, sql: sslice, persistent: bool = False, disable-vtab
|
|||||||
else
|
else
|
||||||
Left(r.trusted-result(capi/error-offset(db.cref)))
|
Left(r.trusted-result(capi/error-offset(db.cref)))
|
||||||
|
|
||||||
|
// Release resources associated with a statement.
|
||||||
|
// Once finalized, a statement can no longer be used.
|
||||||
|
// Every statement must be finalized.
|
||||||
pub fun statement/finalize(stmt: statement): sqlite-result
|
pub fun statement/finalize(stmt: statement): sqlite-result
|
||||||
capi/finalize(stmt.cref).trusted-result
|
capi/finalize(stmt.cref).trusted-result
|
||||||
|
|
||||||
|
// Perform one evaluation step of the statement.
|
||||||
|
// If the result is `Row`, values are available.
|
||||||
|
// If the result is `Done`, the statement has finished executing, and it should
|
||||||
|
// be either `reset` or `finalize`d.
|
||||||
pub fun statement/step(stmt: statement): sqlite-result
|
pub fun statement/step(stmt: statement): sqlite-result
|
||||||
capi/step(stmt.cref).trusted-result
|
capi/step(stmt.cref).trusted-result
|
||||||
|
|
||||||
|
// Reset a statement so that it can be evaluated again.
|
||||||
pub fun statement/reset(stmt: statement): sqlite-result
|
pub fun statement/reset(stmt: statement): sqlite-result
|
||||||
capi/reset(stmt.cref).trusted-result
|
capi/reset(stmt.cref).trusted-result
|
||||||
|
|
||||||
|
// Get the number of columns available in the statement's result.
|
||||||
|
pub fun statement/column-count(stmt: statement): int
|
||||||
|
capi/column-count(stmt.cref)
|
||||||
|
|
||||||
|
// Datatype codes for query results.
|
||||||
|
pub type sqlite3-type
|
||||||
|
Integer
|
||||||
|
Float
|
||||||
|
Text
|
||||||
|
Blob
|
||||||
|
Null
|
||||||
|
|
||||||
|
// Get the result affinity of a column in the statement's result.
|
||||||
|
// The leftmost column is numbered 0.
|
||||||
|
pub fun statment/column-type(stmt: statement, col: int): sqlite3-type
|
||||||
|
val t = capi/column-type(stmt.cref, col.int32)
|
||||||
|
if t == int32/integer() then Integer
|
||||||
|
else if t == int32/float() then Float
|
||||||
|
else if t == int32/blob() then Blob
|
||||||
|
else if t == int32/text() then Text
|
||||||
|
// If the DB gives us something unimaginable, pretend it's nothing.
|
||||||
|
else Null
|
||||||
|
|
||||||
|
// Get the result value of a column as a float64.
|
||||||
|
// If the result does not have float64 affinity, it is converted.
|
||||||
|
// The leftmost column is numbered 0.
|
||||||
|
pub fun statement/float64(stmt: statement, col: int): float64
|
||||||
|
capi/column-double(stmt.cref, col.int32)
|
||||||
|
|
||||||
|
// Get the result value of a column as an integer.
|
||||||
|
// If the result does not have integer affinity, it is converted.
|
||||||
|
// The leftmust column is numbered 0.
|
||||||
|
pub fun statement/int(stmt: statement, col: int): int
|
||||||
|
capi/column-integer(stmt.cref, col.int32)
|
||||||
|
|
||||||
|
// Get the result value of a column as a string.
|
||||||
|
// If the actual result is NULL, the result is the empty string.
|
||||||
|
// Otherwise, if the result does not have text affinity, it is converted.
|
||||||
|
// The leftmost column is numbeered 0.
|
||||||
|
pub fun statement/text(stmt: statement, col: int): string
|
||||||
|
capi/column-text(stmt.cref, col.int32)
|
||||||
|
|||||||
23
test/test.kk
23
test/test.kk
@@ -5,14 +5,26 @@ import sqlite/sqlite3
|
|||||||
// TODO(zephyr): For now, we're just doing a very basic test to estimate whether
|
// TODO(zephyr): For now, we're just doing a very basic test to estimate whether
|
||||||
// I'm doing Koka FFI correctly. An actual test suite would be excellent.
|
// I'm doing Koka FFI correctly. An actual test suite would be excellent.
|
||||||
|
|
||||||
fun stmt(db: sqlite3, text: string)
|
tail fun do-while(f: () -> <div|e> maybe<a>): <div|e> a
|
||||||
println(text)
|
match f()
|
||||||
match db.prepare(text.slice)
|
Nothing -> do-while(f)
|
||||||
|
Just(r) -> r
|
||||||
|
|
||||||
|
fun stmt(db: sqlite3, sql: string)
|
||||||
|
println(sql)
|
||||||
|
match db.prepare(sql.slice)
|
||||||
Left(r-prep) -> println(" prepare result: " ++ r-prep.show)
|
Left(r-prep) -> println(" prepare result: " ++ r-prep.show)
|
||||||
Right((stmt, rest)) ->
|
Right((stmt, rest)) ->
|
||||||
println(" prepare remainder: " ++ rest.show)
|
println(" prepare remainder: " ++ rest.show)
|
||||||
val r-step = stmt.step
|
val r-step = do-while
|
||||||
println(" step result: " ++ r-step.show)
|
val r = stmt.step
|
||||||
|
match r
|
||||||
|
Row ->
|
||||||
|
for(stmt.column-count) fn(i)
|
||||||
|
println(" col " ++ i.show ++ ": " ++ stmt.text(i))
|
||||||
|
Nothing
|
||||||
|
r -> Just(r)
|
||||||
|
println(" final step result: " ++ r-step.show)
|
||||||
val r-fin = stmt.finalize
|
val r-fin = stmt.finalize
|
||||||
println(" finalize result: " ++ r-fin.show)
|
println(" finalize result: " ++ r-fin.show)
|
||||||
|
|
||||||
@@ -23,5 +35,6 @@ pub fun main()
|
|||||||
stmt(db, "DROP TABLE IF EXISTS koka; -- reset previous test runs")
|
stmt(db, "DROP TABLE IF EXISTS koka; -- reset previous test runs")
|
||||||
stmt(db, "CREATE TABLE koka(v TEXT NOT NULL)")
|
stmt(db, "CREATE TABLE koka(v TEXT NOT NULL)")
|
||||||
stmt(db, "INSERT INTO koka VALUES ('value inserted from koka');")
|
stmt(db, "INSERT INTO koka VALUES ('value inserted from koka');")
|
||||||
|
stmt(db, "SELECT * FROM koka")
|
||||||
val r-close = db.close
|
val r-close = db.close
|
||||||
println("close result: " ++ r-close.show)
|
println("close result: " ++ r-close.show)
|
||||||
|
|||||||
Reference in New Issue
Block a user