v/vlib/sqlite/sqlite.v

185 lines
4.2 KiB
V
Raw Normal View History

2019-10-27 21:32:15 +01:00
module sqlite
#flag darwin -lsqlite3
#flag linux -lsqlite3
#flag solaris -lsqlite3
#flag freebsd -I/usr/local/include
2019-12-15 04:18:14 +01:00
#flag freebsd -Wl -L/usr/local/lib -lsqlite3
#flag windows -I@VROOT/thirdparty/sqlite
#flag windows -L@VROOT/thirdparty/sqlite
#flag windows @VROOT/thirdparty/sqlite/sqlite3.o
2020-10-19 20:11:04 +02:00
// #flag linux -I @VROOT/thirdparty/sqlite
// #flag @VROOT/thirdparty/sqlite/sqlite.c
2019-10-27 21:32:15 +01:00
#include "sqlite3.h"
//
2020-10-19 20:11:04 +02:00
struct C.sqlite3 {
}
struct C.sqlite3_stmt {
}
//
pub struct DB {
pub mut:
is_open bool
2019-10-27 21:32:15 +01:00
mut:
2021-01-20 09:30:26 +01:00
conn &C.sqlite3
2019-10-27 21:32:15 +01:00
}
pub fn (db DB) str() string {
return 'sqlite.DB{ conn: ' + ptr_str(db.conn) + ' }'
}
pub struct Row {
2019-10-27 21:32:15 +01:00
pub mut:
vals []string
}
2020-10-19 20:11:04 +02:00
//
fn C.sqlite3_open(charptr, &&C.sqlite3) int
2020-10-19 20:11:04 +02:00
fn C.sqlite3_close(&C.sqlite3) int
2020-10-19 20:11:04 +02:00
//
fn C.sqlite3_prepare_v2(&C.sqlite3, charptr, int, &&sqlite3_stmt, &charptr) int
2020-10-19 20:11:04 +02:00
fn C.sqlite3_step(&C.sqlite3_stmt) int
2020-10-19 20:11:04 +02:00
fn C.sqlite3_finalize(&C.sqlite3_stmt) int
2020-10-19 20:11:04 +02:00
//
fn C.sqlite3_column_name(&C.sqlite3_stmt, int) charptr
2020-10-19 20:11:04 +02:00
fn C.sqlite3_column_text(&C.sqlite3_stmt, int) byteptr
2020-10-19 20:11:04 +02:00
fn C.sqlite3_column_int(&C.sqlite3_stmt, int) int
2020-10-19 20:11:04 +02:00
fn C.sqlite3_column_int64(&C.sqlite3_stmt, int) int64
2020-10-19 20:11:04 +02:00
fn C.sqlite3_column_double(&C.sqlite3_stmt, int) f64
2020-10-19 20:11:04 +02:00
fn C.sqlite3_column_count(&C.sqlite3_stmt) int
2020-10-19 20:11:04 +02:00
//
fn C.sqlite3_errstr(int) charptr
2020-10-19 20:11:04 +02:00
fn C.sqlite3_free(voidptr)
// connect Opens the connection with a database.
2020-06-16 12:14:22 +02:00
pub fn connect(path string) ?DB {
2019-12-04 11:08:28 +01:00
db := &C.sqlite3(0)
2020-06-16 12:14:22 +02:00
if C.sqlite3_open(path.str, &db) != 0 {
return error('sqlite db error')
}
return DB{
conn: db
is_open: true
}
}
// close Closes the DB.
// TODO: For all functions, determine whether the connection is
// closed first, and determine what to do if it is
pub fn (mut db DB) close() ?bool {
code := C.sqlite3_close(db.conn)
if code == 0 {
db.is_open = false
} else {
return error('sqlite db error: failed to close with code: $code')
}
return true // successfully closed
2019-10-27 21:32:15 +01:00
}
2020-06-17 00:59:33 +02:00
// Only for V ORM
fn (db DB) init_stmt(query string) &C.sqlite3_stmt {
stmt := &C.sqlite3_stmt(0)
C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0)
return stmt
}
// Only for V ORM
fn get_int_from_stmt(stmt &C.sqlite3_stmt) int {
x := C.sqlite3_step(stmt)
if x != C.SQLITE_OK && x != C.SQLITE_DONE {
2020-07-16 00:48:10 +02:00
C.puts(C.sqlite3_errstr(x))
}
2020-06-17 00:59:33 +02:00
res := C.sqlite3_column_int(stmt, 0)
C.sqlite3_finalize(stmt)
return res
}
// Returns a single cell with value int.
2019-10-27 21:32:15 +01:00
pub fn (db DB) q_int(query string) int {
2019-12-04 11:08:28 +01:00
stmt := &C.sqlite3_stmt(0)
C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0)
2019-10-27 21:32:15 +01:00
C.sqlite3_step(stmt)
res := C.sqlite3_column_int(stmt, 0)
C.sqlite3_finalize(stmt)
return res
}
// Returns a single cell with value string.
2019-10-27 21:32:15 +01:00
pub fn (db DB) q_string(query string) string {
2019-12-04 11:08:28 +01:00
stmt := &C.sqlite3_stmt(0)
C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0)
2019-10-27 21:32:15 +01:00
C.sqlite3_step(stmt)
res := tos_clone(C.sqlite3_column_text(stmt, 0))
C.sqlite3_finalize(stmt)
return res
}
// Execute the query on db, return an array of all the results, alongside any result code.
// Result codes: https://www.sqlite.org/rescode.html
2020-10-19 20:11:04 +02:00
pub fn (db DB) exec(query string) ([]Row, int) {
2019-12-04 11:08:28 +01:00
stmt := &C.sqlite3_stmt(0)
C.sqlite3_prepare_v2(db.conn, query.str, -1, &stmt, 0)
2019-10-27 21:32:15 +01:00
nr_cols := C.sqlite3_column_count(stmt)
mut res := 0
2020-04-26 16:25:54 +02:00
mut rows := []Row{}
2019-10-27 21:32:15 +01:00
for {
res = C.sqlite3_step(stmt)
2020-04-26 16:25:54 +02:00
// Result Code SQLITE_ROW; Another row is available
if res != 100 {
2020-10-19 20:11:04 +02:00
// C.puts(C.sqlite3_errstr(res))
2019-10-27 21:32:15 +01:00
break
2019-12-04 11:08:28 +01:00
}
2019-10-27 21:32:15 +01:00
mut row := Row{}
for i in 0 .. nr_cols {
2019-10-27 21:32:15 +01:00
val := tos_clone(C.sqlite3_column_text(stmt, i))
row.vals << val
}
rows << row
}
2020-11-09 08:22:16 +01:00
C.sqlite3_finalize(stmt)
2020-10-19 20:11:04 +02:00
return rows, res
2019-10-27 21:32:15 +01:00
}
// Execute a query, handle error code
// Return the first row from the resulting table
2019-10-27 21:32:15 +01:00
pub fn (db DB) exec_one(query string) ?Row {
2020-10-19 20:11:04 +02:00
rows, code := db.exec(query)
if rows.len == 0 || code != 101 {
return error('SQL Error: Rows #$rows.len Return code $code')
}
2019-10-27 21:32:15 +01:00
return rows[0]
}
// In case you don't expect any result, but still want an error code
// e.g. INSERT INTO ... VALUES (...)
pub fn (db DB) exec_none(query string) int {
2020-10-19 20:11:04 +02:00
_, code := db.exec(query)
return code
}
2020-10-19 20:11:04 +02:00
/*
TODO
2019-10-27 21:32:15 +01:00
pub fn (db DB) exec_param(query string, param string) []Row {
}
*/
2020-06-17 20:18:48 +02:00
pub fn (db DB) insert<T>(x T) {
}
2021-01-20 09:30:26 +01:00
pub fn (db DB) create_table(table_name string, columns []string) {
db.exec('create table $table_name (' + columns.join(',\n') + ')')
2021-01-20 09:30:26 +01:00
}