Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ EXTENSION_FUNCTIONS_URL = https://www.sqlite.org/contrib/download/extension-func
EXTENSION_FUNCTIONS_SHA3 = ee39ddf5eaa21e1d0ebcbceeab42822dd0c4f82d8039ce173fd4814807faabfa

# source files
# TODO: maybe use libtrace only in debug mode
CFILES = \
sqlite3.c \
extension-functions.c \
Expand All @@ -16,14 +17,16 @@ CFILES = \
libhook.c \
libprogress.c \
libvfs.c \
libtrace.c \
$(CFILES_EXTRA)

JSFILES = \
src/libauthorizer.js \
src/libfunction.js \
src/libhook.js \
src/libprogress.js \
src/libvfs.js
src/libvfs.js \
src/libtrace.js

vpath %.c src
vpath %.c deps
Expand Down Expand Up @@ -77,7 +80,8 @@ EMFLAGS_LIBRARIES = \
--post-js src/libfunction.js \
--post-js src/libhook.js \
--post-js src/libprogress.js \
--post-js src/libvfs.js
--post-js src/libvfs.js \
--post-js src/libtrace.js

EMFLAGS_ASYNCIFY_COMMON = \
-s ASYNCIFY \
Expand Down
1 change: 1 addition & 0 deletions src/libadapters.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ DECLARE(void, vppp, P, P, P);
DECLARE(I, ipppj, P, P, P, J);
DECLARE(I, ipppi, P, P, P, I);
DECLARE(I, ipppp, P, P, P, P);
DECLARE(I, ippipp, P, P, I, P, P);
DECLARE(I, ipppip, P, P, P, I, P);
DECLARE(void, vpppip, P, P, P, I, P);
DECLARE(I, ippppi, P, P, P, P, I);
Expand Down
1 change: 1 addition & 0 deletions src/libadapters.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const SIGNATURES = [
'ipppj', // xTruncate
'ipppi', // xSleep, xSync, xLock, xUnlock, xShmUnmap
'ipppp', // xFileSize, xCheckReservedLock, xCurrentTime, xCurrentTimeInt64
'ippipp', // xTrace
'ipppip', // xFileControl, xRandomness, xGetLastError
'vpppip', // xFunc, xStep
'ippppi', // xDelete
Expand Down
19 changes: 19 additions & 0 deletions src/libtrace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <emscripten.h>
#include <sqlite3.h>
#include <stdio.h>

#include "libadapters.h"

#define CALL_JS(SIGNATURE, KEY, ...) \
(asyncFlags ? SIGNATURE##_async(KEY, __VA_ARGS__) \
: SIGNATURE(KEY, __VA_ARGS__))

static int libtrace_xTrace(unsigned opCode, void *pApp, void *P, void *X) {
const int asyncFlags = pApp ? *(int *)pApp : 0;
return CALL_JS(ippipp, pApp, pApp, opCode, P, X);
}

void EMSCRIPTEN_KEEPALIVE libtrace_trace(sqlite3 *db, unsigned mTrace,
int xTrace, void *pApp) {
sqlite3_trace_v2(db, mTrace, xTrace ? &libtrace_xTrace : NULL, pApp);
}
28 changes: 28 additions & 0 deletions src/libtrace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2024 Roy T. Hashimoto. All Rights Reserved.
// This file should be included in the build with --post-js.
(function() {
const AsyncFunction = Object.getPrototypeOf(async function() { }).constructor;
let pAsyncFlags = 0;

Module['trace'] = function(db, mTrace, xTrace) {
if (pAsyncFlags) {
Module['deleteCallback'](pAsyncFlags);
Module['_sqlite3_free'](pAsyncFlags);
pAsyncFlags = 0;
}

pAsyncFlags = Module['_sqlite3_malloc'](4);
setValue(pAsyncFlags, xTrace instanceof AsyncFunction ? 1 : 0, 'i32');

ccall(
'libtrace_trace',
'void',
['number', 'number', 'number', 'number'],
[db, mTrace, xTrace ? 1 : 0, pAsyncFlags]);
if (xTrace) {
Module['setCallback'](pAsyncFlags, (_, opCode, pP, pX) => {
return xTrace(opCode, pP, pX)
});
}
};
})();
52 changes: 42 additions & 10 deletions src/sqlite-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export * from './sqlite-constants.js';
const MAX_INT64 = 0x7fffffffffffffffn;
const MIN_INT64 = -0x8000000000000000n;

const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const AsyncFunction = Object.getPrototypeOf(async function() { }).constructor;

export class SQLiteError extends Error {
constructor(message, code) {
Expand Down Expand Up @@ -248,7 +248,7 @@ export function Factory(Module) {
return check(fname, result, mapStmtToDB.get(stmt));
};
})();

sqlite3.close = (function() {
const fname = 'sqlite3_close';
const f = Module.cwrap(fname, ...decl('n:n'), { async });
Expand Down Expand Up @@ -388,7 +388,7 @@ export function Factory(Module) {

sqlite3.create_function = function(db, zFunctionName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) {
verifyDatabase(db);

// Convert SQLite callback arguments to JavaScript-friendly arguments.
function adapt(f) {
return f instanceof AsyncFunction ?
Expand Down Expand Up @@ -640,7 +640,7 @@ export function Factory(Module) {
const result = Module.set_authorizer(db, adapt(xAuth), pApp);
return check('sqlite3_set_authorizer', result, db);
};;

sqlite3.sql = (function() {
const fname = 'sqlite3_sql';
const f = Module.cwrap(fname, ...decl('n:s'));
Expand Down Expand Up @@ -673,7 +673,7 @@ export function Factory(Module) {
onFinally.push(() => Module._sqlite3_free(pzHead));
Module.HEAPU8.set(utf8, pzHead);
Module.HEAPU8[pzEnd - 1] = 0;

// Use extra space for the statement handle and SQL tail pointer.
const pStmt = pzHead + allocSize - 8;
const pzTail = pzHead + allocSize - 4;
Expand All @@ -687,7 +687,7 @@ export function Factory(Module) {
stmt = 0;
}
onFinally.push(maybeFinalize);

// Loop over statements.
Module.setValue(pzTail, pzHead, '*');
do {
Expand All @@ -710,7 +710,7 @@ export function Factory(Module) {
if (rc !== SQLite.SQLITE_OK) {
check('sqlite3_prepare_v3', rc, db);
}

stmt = Module.getValue(pStmt, '*');
if (stmt) {
mapStmtToDB.set(stmt, db);
Expand Down Expand Up @@ -752,7 +752,7 @@ export function Factory(Module) {
iUpdateType,
Module.UTF8ToString(dbName),
Module.UTF8ToString(tblName),
cvt32x2ToBigInt(lo32, hi32)
cvt32x2ToBigInt(lo32, hi32)
];
};
function adapt(f) {
Expand All @@ -762,7 +762,39 @@ export function Factory(Module) {
}

Module.update_hook(db, adapt(xUpdateHook));
};;
};

sqlite3.trace = function(db, mTrace, xTrace) {
verifyDatabase(db)

function cvtArgs(opCode, _pP, pX) {
// NOTE: only SQLITE_TRACE_STMT is currently implemented
switch (opCode) {
case SQLite.SQLITE_TRACE_STMT:
return [
opCode,
"SQLITE_TRACE_STMT",
Module.UTF8ToString(pX)
]
default:
// TODO: implement other variants
return [
opCode,
"UNSUPPORTED_OP",
null
]
}
}

function adapt(f) {
return f instanceof AsyncFunction ?
(async (opCode, pP, pX) => f(...cvtArgs(opCode, pP, pX))) :
((opCode, pP, pX) => f(...cvtArgs(opCode, pP, pX)))
}

Module.trace(db, mTrace, adapt(xTrace))
}


sqlite3.value = function(pValue) {
const type = sqlite3.value_type(pValue);
Expand Down Expand Up @@ -876,7 +908,7 @@ export function Factory(Module) {
await Promise.all(Module.retryOps);
Module.retryOps = [];
}

rc = await f();

// Retry on failure with new pending retry operations.
Expand Down
7 changes: 6 additions & 1 deletion src/sqlite-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,9 @@ export const SQLITE_LIMIT_WORKER_THREADS = 11;

export const SQLITE_PREPARE_PERSISTENT = 0x01;
export const SQLITE_PREPARE_NORMALIZED = 0x02;
export const SQLITE_PREPARE_NO_VTAB = 0x04;
export const SQLITE_PREPARE_NO_VTAB = 0x04;

export const SQLITE_TRACE_STMT = 0x01;
export const SQLITE_TRACE_PROFILE = 0x02;
export const SQLITE_TRACE_ROW = 0x04;
export const SQLITE_TRACE_CLOSE = 0x08;
5 changes: 5 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,11 @@ declare interface SQLiteAPI {
* @returns `SQLITE_OK` (throws exception on error)
*/
vfs_register(vfs: SQLiteVFS, makeDefault?: boolean): number;

trace(
db: number, mTrace: 1 | 2 | 3 | 4,
xTrace: (opCode: 1 | 2 | 3 | 4, opStr: string, sql?: string) => number
): void
}

/** @ignore */
Expand Down
Loading