github.com/tailscale/sqlite@v0.0.0-20240515181108-c667cbe57c66/cgosqlite/cgosqlite.h (about) 1 #include <stdint.h> 2 #include <time.h> 3 4 // uintptr versions of sqlite3 pointer types, to avoid allocations 5 // in cgo code. (go/corp/9919) 6 typedef uintptr_t handle_sqlite3_stmt; // a *sqlite3_stmt 7 typedef uintptr_t handle_sqlite3; // a *sqlite3 (DB conn) 8 9 // Helper methods to deal with int <-> pointer pain. 10 11 static int bind_text64(handle_sqlite3_stmt stmt, int col, const char* str, sqlite3_uint64 len) { 12 return sqlite3_bind_text64((sqlite3_stmt*)(stmt), col, str, len, free, SQLITE_UTF8); 13 } 14 15 static int bind_text64_empty(handle_sqlite3_stmt stmt, int col) { 16 return sqlite3_bind_text64((sqlite3_stmt*)(stmt), col, "", 0, SQLITE_STATIC, SQLITE_UTF8); 17 } 18 19 static int bind_blob64(handle_sqlite3_stmt stmt, int col, char* str, sqlite3_uint64 n) { 20 return sqlite3_bind_blob64((sqlite3_stmt*)(stmt), col, str, n, SQLITE_TRANSIENT); 21 } 22 23 static int ts_sqlite3_bind_double(handle_sqlite3_stmt stmt, int col, double v) { 24 return sqlite3_bind_double((sqlite3_stmt*)(stmt), col, v); 25 } 26 27 static int ts_sqlite3_bind_int64(handle_sqlite3_stmt stmt, int col, sqlite3_int64 v) { 28 return sqlite3_bind_int64((sqlite3_stmt*)(stmt), col, v); 29 } 30 31 static int ts_sqlite3_bind_null(handle_sqlite3_stmt stmt, int col) { 32 return sqlite3_bind_null((sqlite3_stmt*)(stmt), col); 33 } 34 35 // We only need the Go string's memory for the duration of the call, 36 // and the GC pins it for us if we pass the gostring_t to C, so we 37 // do the conversion here instead of with C.CString. 38 static int bind_parameter_index(handle_sqlite3_stmt stmt, _GoString_ s) { 39 size_t n = _GoStringLen(s); 40 const char *p = (const char *)_GoStringPtr(s); 41 42 // Start with zeroed zName to provide NUL-terminated string. 43 char zName[256] = {0}; 44 if (n >= sizeof zName) { 45 return 0; 46 } 47 memmove(zName, p, n); 48 return sqlite3_bind_parameter_index((sqlite3_stmt*)(stmt), zName); 49 } 50 51 static void monotonic_clock_gettime(struct timespec* t) { 52 clock_gettime(CLOCK_MONOTONIC, t); 53 } 54 55 static int64_t ns_since(const struct timespec t1) 56 { 57 struct timespec t2; 58 monotonic_clock_gettime(&t2); 59 return ((int64_t)t2.tv_sec - (int64_t)t1.tv_sec) * (int64_t)1000000000 + 60 ((int64_t)t2.tv_nsec - (int64_t)t1.tv_nsec); 61 } 62 63 // step_result combines several cgo calls to save overhead. 64 static int step_result(handle_sqlite3_stmt stmth, sqlite3_int64* rowid, sqlite3_int64* changes, int64_t* duration_ns) { 65 sqlite3_stmt* stmt = (sqlite3_stmt*)(stmth); 66 struct timespec t1; 67 if (duration_ns) { 68 monotonic_clock_gettime(&t1); 69 } 70 int ret = sqlite3_step(stmt); 71 sqlite3* db = sqlite3_db_handle(stmt); 72 *rowid = sqlite3_last_insert_rowid(db); 73 *changes = sqlite3_changes(db); 74 sqlite3_reset(stmt); 75 sqlite3_clear_bindings(stmt); 76 if (duration_ns) { 77 *duration_ns = ns_since(t1); 78 } 79 return ret; 80 } 81 82 // reset_and_clear combines two cgo calls to save overhead. 83 static int reset_and_clear(handle_sqlite3_stmt stmth, struct timespec* start, int64_t* duration_ns) { 84 sqlite3_stmt* stmt = (sqlite3_stmt*)(stmth); 85 int ret = sqlite3_reset(stmt); 86 int ret2 = sqlite3_clear_bindings(stmt); 87 if (duration_ns) { 88 *duration_ns = ns_since(*start); 89 } 90 if (ret != SQLITE_OK) { 91 return ret; 92 } 93 return ret2; 94 } 95 96 int walCallbackGo(sqlite3 *db, char *dbName, int dbNameLen, int pages); 97 98 static int wal_callback_into_go(void *userData, sqlite3 *db, const char *dbName, 99 int pages) { 100 return walCallbackGo(db, (char *)dbName, strlen(dbName), pages); 101 } 102 103 // ts_sqlite3_wal_hook_go makes db's WAL hook call into Go. 104 // 105 // It must already be registered on Go's side first. 106 static void ts_sqlite3_wal_hook_go(sqlite3* db) { 107 sqlite3_wal_hook(db, wal_callback_into_go, 0); 108 } 109 110 static int ts_sqlite3_step(handle_sqlite3_stmt stmth, char* outType , int outTypeLen) { 111 sqlite3_stmt* stmt = (sqlite3_stmt*)(stmth); 112 int res = sqlite3_step(stmt); 113 if (res == SQLITE_ROW && outTypeLen > 0) { 114 int cols = sqlite3_column_count(stmt); 115 for (int i = 0; i < cols && i < outTypeLen; i++) { 116 outType[i] = (char) sqlite3_column_type(stmt, i); 117 } 118 } 119 return res; 120 } 121 122 static const unsigned char *ts_sqlite3_column_text(handle_sqlite3_stmt stmt, int iCol) { 123 return sqlite3_column_text((sqlite3_stmt*)(stmt), iCol); 124 } 125 126 static const unsigned char *ts_sqlite3_column_blob(handle_sqlite3_stmt stmt, int iCol) { 127 return sqlite3_column_blob((sqlite3_stmt*)(stmt), iCol); 128 } 129 130 static int ts_sqlite3_column_type(handle_sqlite3_stmt stmt, int iCol) { 131 return sqlite3_column_type((sqlite3_stmt*)(stmt), iCol); 132 } 133 134 static int ts_sqlite3_column_bytes(handle_sqlite3_stmt stmt, int iCol) { 135 return sqlite3_column_bytes((sqlite3_stmt*)(stmt), iCol); 136 } 137 138 static double ts_sqlite3_column_double(handle_sqlite3_stmt stmt, int iCol) { 139 return sqlite3_column_double((sqlite3_stmt*)(stmt), iCol); 140 } 141 142 static sqlite3_int64 ts_sqlite3_column_int64(handle_sqlite3_stmt stmt, int iCol) { 143 return sqlite3_column_int64((sqlite3_stmt*)(stmt), iCol); 144 }