get column values
This commit is contained in:
@@ -47,3 +47,27 @@ pub extern step(^stmt: any): int32
|
||||
|
||||
pub extern reset(^stmt: any): int32
|
||||
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);
|
||||
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
|
||||
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)>
|
||||
val flags = 0.i32
|
||||
.or(persistent.int32 * 0x01.i32)
|
||||
@@ -106,11 +110,61 @@ pub fun prepare(db: sqlite3, sql: sslice, persistent: bool = False, disable-vtab
|
||||
else
|
||||
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
|
||||
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
|
||||
capi/step(stmt.cref).trusted-result
|
||||
|
||||
// Reset a statement so that it can be evaluated again.
|
||||
pub fun statement/reset(stmt: statement): sqlite-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
|
||||
// I'm doing Koka FFI correctly. An actual test suite would be excellent.
|
||||
|
||||
fun stmt(db: sqlite3, text: string)
|
||||
println(text)
|
||||
match db.prepare(text.slice)
|
||||
tail fun do-while(f: () -> <div|e> maybe<a>): <div|e> a
|
||||
match f()
|
||||
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)
|
||||
Right((stmt, rest)) ->
|
||||
println(" prepare remainder: " ++ rest.show)
|
||||
val r-step = stmt.step
|
||||
println(" step result: " ++ r-step.show)
|
||||
val r-step = do-while
|
||||
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
|
||||
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, "CREATE TABLE koka(v TEXT NOT NULL)")
|
||||
stmt(db, "INSERT INTO koka VALUES ('value inserted from koka');")
|
||||
stmt(db, "SELECT * FROM koka")
|
||||
val r-close = db.close
|
||||
println("close result: " ++ r-close.show)
|
||||
|
||||
Reference in New Issue
Block a user