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  }