#pragma once #include "tlibc/tlibc.h" #include "tlibc/string/StringBuilder.h" #include Result(void) tsqlite_init(); void tsqlite_deinit(); ErrorCodePage_declare(SQLITE); #define RESULT_ERROR_SQLITE_CODE(CONN, SHORT_CODE) RESULT_ERROR_CODE(SQLITE, SHORT_CODE, tsqlite_error_toStr(CONN, SHORT_CODE), true) #define _try_sqlite3(CONN, CALL, N) do {\ i32 _rname(N) = CALL;\ if((_rname(N) & 0xff) != SQLITE_OK){\ return RESULT_ERROR_SQLITE_CODE(CONN, _rname(N));\ }\ } while(0) #define try_sqlite3(CONN, CALL) _try_sqlite3(CONN, CALL, __LINE__) typedef sqlite3 tsqlite_connection; /// @param file_path sqlite file /// @return new sqlite connection Result(tsqlite_connection*) tsqlite_connection_open(cstr file_path); /// all statements and blobs must be destroyed before calling this Result(void) tsqlite_connection_close(tsqlite_connection* db); /// @param conn a database connection with error code and error message /// @return heap-allocated string str tsqlite_error_toStr(tsqlite_connection* conn, i32 short_code); void tsqlite_resultCode_append(StringBuilder* sb, i32 short_code, i32 extended_code); void tsqlite_resultCodeAndMsg_append(StringBuilder* sb, i32 short_code, i32 extended_code, str msg); typedef struct tsqlite_statement { tsqlite_connection* conn; sqlite3_stmt* st; i32 result_row; i32 result_col; } tsqlite_statement; /// @brief Compile SQL statement to bytecode. Documentation: https://sqlite.org/c3ref/prepare.html /// @param conn a database connection /// @param sql_code SQL statement code. May contain placeholders. /// **PLACEHOLDERS FORMAT**: `:name`, `@name`, `$name`, `$(some name)` /// @return compiled statement Result(tsqlite_statement*) tsqlite_statement_compile(tsqlite_connection* conn, str sql_code); void tsqlite_statement_free(tsqlite_statement* st); /// @brief execute statement or move to next result row. /// Documentation: https://sqlite.org/c3ref/step.html /// /// USAGE: /// ``` /// while(true){ /// try(bool has_result, i, tsqlite_statement_execNext(st)); /// if(!has_result) /// break; /// /* get result columns */ /// } /// ``` /// @return is result row avaliable Result(bool) tsqlite_statement_execNext(tsqlite_statement* self); /// call this after executing a compiled statement to use it again Result(void) tsqlite_statement_reset(tsqlite_statement* st); /// Bind value to a placeholder Result(void) tsqlite_statement_bind_null(tsqlite_statement* self, cstr key); Result(void) tsqlite_statement_bind_i64(tsqlite_statement* self, cstr key, i64 v); Result(void) tsqlite_statement_bind_f64(tsqlite_statement* self, cstr key, f64 v); Result(void) tsqlite_statement_bind_str(tsqlite_statement* self, cstr key, str v, NULLABLE(Destructor_t) d); Result(void) tsqlite_statement_bind_blob(tsqlite_statement* self, cstr key, Array(u8) v, NULLABLE(Destructor_t) d); Result(void) tsqlite_statement_bind_zeroblob(tsqlite_statement* self, cstr key, i32 size); /// Get value at `self->result_col`. Increases `self->result_col` on success. Result(i64) tsqlite_statement_getResult_i64(tsqlite_statement* self); Result(i64) tsqlite_statement_getResult_f64(tsqlite_statement* self); Result(void) tsqlite_statement_getResult_str(tsqlite_statement* self, str* out_v); Result(void) tsqlite_statement_getResult_blob(tsqlite_statement* self, Array(u8)* out_v);