firebird-wasm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +120 -0
- package/dist/.tsbuildinfo.build +1 -0
- package/dist/browser/db-lock.d.ts +92 -0
- package/dist/browser/db-lock.d.ts.map +1 -0
- package/dist/browser/db-lock.js +163 -0
- package/dist/browser/db-lock.js.map +1 -0
- package/dist/browser/engine-transport.d.ts +94 -0
- package/dist/browser/engine-transport.d.ts.map +1 -0
- package/dist/browser/engine-transport.js +217 -0
- package/dist/browser/engine-transport.js.map +1 -0
- package/dist/browser/field-types.d.ts +19 -0
- package/dist/browser/field-types.d.ts.map +1 -0
- package/dist/browser/field-types.js +79 -0
- package/dist/browser/field-types.js.map +1 -0
- package/dist/browser/firebird-browser.d.ts +249 -0
- package/dist/browser/firebird-browser.d.ts.map +1 -0
- package/dist/browser/firebird-browser.js +401 -0
- package/dist/browser/firebird-browser.js.map +1 -0
- package/dist/browser/index.d.ts +31 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +39 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/indexeddb-vfs.d.ts +132 -0
- package/dist/browser/indexeddb-vfs.d.ts.map +1 -0
- package/dist/browser/indexeddb-vfs.js +285 -0
- package/dist/browser/indexeddb-vfs.js.map +1 -0
- package/dist/browser/params.d.ts +33 -0
- package/dist/browser/params.d.ts.map +1 -0
- package/dist/browser/params.js +92 -0
- package/dist/browser/params.js.map +1 -0
- package/dist/browser/sql-script.d.ts +27 -0
- package/dist/browser/sql-script.d.ts.map +1 -0
- package/dist/browser/sql-script.js +132 -0
- package/dist/browser/sql-script.js.map +1 -0
- package/dist/browser/worker-entry.d.ts +45 -0
- package/dist/browser/worker-entry.d.ts.map +1 -0
- package/dist/browser/worker-entry.js +79 -0
- package/dist/browser/worker-entry.js.map +1 -0
- package/dist/browser/worker-protocol.d.ts +37 -0
- package/dist/browser/worker-protocol.d.ts.map +1 -0
- package/dist/browser/worker-protocol.js +10 -0
- package/dist/browser/worker-protocol.js.map +1 -0
- package/dist/browser/worker-transport.d.ts +63 -0
- package/dist/browser/worker-transport.d.ts.map +1 -0
- package/dist/browser/worker-transport.js +133 -0
- package/dist/browser/worker-transport.js.map +1 -0
- package/dist/firebird.d.ts +73 -0
- package/dist/firebird.d.ts.map +1 -0
- package/dist/firebird.js +208 -0
- package/dist/firebird.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/wasm/firebird-embedded.js +2 -0
- package/dist/wasm/firebird-embedded.wasm +0 -0
- package/dist/wasm-loader.d.ts +162 -0
- package/dist/wasm-loader.d.ts.map +1 -0
- package/dist/wasm-loader.js +103 -0
- package/dist/wasm-loader.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* db-lock.ts – cross-tab exclusion for a single logical database.
|
|
4
|
+
*
|
|
5
|
+
* ## The hazard
|
|
6
|
+
*
|
|
7
|
+
* Every tab runs its own engine with its own complete copy of the database in
|
|
8
|
+
* Emscripten's in-memory filesystem, and `persist()` writes that **whole
|
|
9
|
+
* image** to IndexedDB. So two tabs on one database is not a
|
|
10
|
+
* write-interleaving problem that finer-grained locking would fix — it is
|
|
11
|
+
* last-writer-wins over the entire file:
|
|
12
|
+
*
|
|
13
|
+
* tab A: open (image v1) ─── write x ─────────────── persist (v1+x)
|
|
14
|
+
* tab B: open (image v1) ─── write y ─── persist (v1+y)
|
|
15
|
+
*
|
|
16
|
+
* B's `y` is gone. Not corrupted, not conflicted — silently absent, with both
|
|
17
|
+
* tabs showing a successful commit. `importDatabase()` being atomic does not
|
|
18
|
+
* help: each write is individually perfect and still wrong.
|
|
19
|
+
*
|
|
20
|
+
* ## Why the Web Locks API
|
|
21
|
+
*
|
|
22
|
+
* The property that matters is release-on-death. A lock built out of a flag
|
|
23
|
+
* in IndexedDB has to answer "the holder set this 40 seconds ago and stopped —
|
|
24
|
+
* crashed, or just busy?", and every answer is either a deadlock or a
|
|
25
|
+
* corruption window. Web Locks are held by the *agent*, so a closed tab, a
|
|
26
|
+
* crashed renderer or a killed background process releases immediately and
|
|
27
|
+
* exactly. There is no stale state to recover and no heartbeat to tune.
|
|
28
|
+
*
|
|
29
|
+
* Queueing is also free: a second tab waits for the first rather than
|
|
30
|
+
* spinning, and is granted the moment the first closes.
|
|
31
|
+
*/
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.DatabaseLockedError = void 0;
|
|
34
|
+
exports.databaseLockName = databaseLockName;
|
|
35
|
+
exports.acquireDatabaseLock = acquireDatabaseLock;
|
|
36
|
+
/** Thrown when another tab holds the database and did not release in time. */
|
|
37
|
+
class DatabaseLockedError extends Error {
|
|
38
|
+
constructor(
|
|
39
|
+
/** The logical database name that is held elsewhere. */
|
|
40
|
+
dbName,
|
|
41
|
+
/** How long we waited, in milliseconds. */
|
|
42
|
+
waitedMs) {
|
|
43
|
+
super(`Database "${dbName}" is already open in another tab or worker ` +
|
|
44
|
+
`(waited ${waitedMs}ms). Each tab keeps its own full copy of the ` +
|
|
45
|
+
`database, so allowing both would silently discard one tab's writes. ` +
|
|
46
|
+
`Close the other tab, or pass multiTab: 'allow-unsafe' if you are ` +
|
|
47
|
+
`certain only one of them writes.`);
|
|
48
|
+
this.dbName = dbName;
|
|
49
|
+
this.waitedMs = waitedMs;
|
|
50
|
+
this.name = 'DatabaseLockedError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.DatabaseLockedError = DatabaseLockedError;
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Implementation
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
58
|
+
/** Lock names are namespaced so they cannot collide with an app's own locks. */
|
|
59
|
+
function databaseLockName(dbName) {
|
|
60
|
+
return `firebird-wasm:db:${dbName}`;
|
|
61
|
+
}
|
|
62
|
+
/** Whether this environment can enforce cross-tab exclusion at all. */
|
|
63
|
+
function locksAvailable() {
|
|
64
|
+
return (typeof navigator !== 'undefined' &&
|
|
65
|
+
typeof navigator.locks?.request === 'function');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Take the exclusive lock for `dbName`, waiting up to `timeoutMs`.
|
|
69
|
+
*
|
|
70
|
+
* Call this *before* reading the stored image. A tab that loads the database
|
|
71
|
+
* and then waits for the lock resumes with a snapshot that the departing tab
|
|
72
|
+
* has since replaced, which is the very overwrite the lock exists to prevent.
|
|
73
|
+
*
|
|
74
|
+
* Where the Web Locks API is missing — Node, jsdom, a non-secure context —
|
|
75
|
+
* there is nothing to enforce exclusion with. Rather than refuse to run, this
|
|
76
|
+
* warns and returns a lock with `enforced: false`: the single-tab case that
|
|
77
|
+
* covers Node and tests is safe on its own, and failing there would break
|
|
78
|
+
* environments that never had the hazard.
|
|
79
|
+
*
|
|
80
|
+
* @throws {DatabaseLockedError} if another tab holds it past the timeout.
|
|
81
|
+
*/
|
|
82
|
+
async function acquireDatabaseLock(dbName, options = {}) {
|
|
83
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
84
|
+
if (!locksAvailable()) {
|
|
85
|
+
const warn = options.onUnavailable ?? ((m) => console.warn(m));
|
|
86
|
+
warn('[firebird-wasm] the Web Locks API is unavailable, so concurrent tabs ' +
|
|
87
|
+
'cannot be detected. Opening the same database in two places will ' +
|
|
88
|
+
'silently lose writes.');
|
|
89
|
+
return { enforced: false, release: async () => { } };
|
|
90
|
+
}
|
|
91
|
+
const name = databaseLockName(dbName);
|
|
92
|
+
const startedAt = nowMs();
|
|
93
|
+
// Two promises, because "granted" and "released" are different moments and
|
|
94
|
+
// the caller needs both. The lock is held for exactly as long as the
|
|
95
|
+
// callback's returned promise is pending, so `release` is what settles it.
|
|
96
|
+
let release;
|
|
97
|
+
const held = new Promise((resolve) => {
|
|
98
|
+
release = resolve;
|
|
99
|
+
});
|
|
100
|
+
let onGranted;
|
|
101
|
+
let onFailed;
|
|
102
|
+
const granted = new Promise((resolve, reject) => {
|
|
103
|
+
onGranted = resolve;
|
|
104
|
+
onFailed = reject;
|
|
105
|
+
});
|
|
106
|
+
// Aborting the signal cancels a *pending* request. Once granted it has no
|
|
107
|
+
// further effect, which is what makes it usable as an acquisition timeout.
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const timer = timeoutMs === Infinity
|
|
110
|
+
? null
|
|
111
|
+
: setTimeout(() => controller.abort(), timeoutMs);
|
|
112
|
+
const done = navigator.locks.request(name, { mode: 'exclusive', signal: controller.signal }, () => {
|
|
113
|
+
onGranted();
|
|
114
|
+
return held;
|
|
115
|
+
});
|
|
116
|
+
// Rejects only if the request was abandoned before the callback ran; after a
|
|
117
|
+
// grant `granted` has already settled and this is a no-op.
|
|
118
|
+
done.catch(onFailed);
|
|
119
|
+
try {
|
|
120
|
+
await granted;
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
if (timer !== null)
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
// AbortError is our own timeout firing; anything else is a real fault and
|
|
126
|
+
// should not be dressed up as contention.
|
|
127
|
+
if (isAbortError(err)) {
|
|
128
|
+
throw new DatabaseLockedError(dbName, Math.round(nowMs() - startedAt));
|
|
129
|
+
}
|
|
130
|
+
throw err;
|
|
131
|
+
}
|
|
132
|
+
if (timer !== null)
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
let released = false;
|
|
135
|
+
return {
|
|
136
|
+
enforced: true,
|
|
137
|
+
release: async () => {
|
|
138
|
+
if (released)
|
|
139
|
+
return;
|
|
140
|
+
released = true;
|
|
141
|
+
release();
|
|
142
|
+
// Await the request promise, so the lock is provably gone once this
|
|
143
|
+
// resolves: a caller that reopens immediately must not race itself.
|
|
144
|
+
await done.catch(() => { });
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Checked by `name`, not `instanceof`. The abort arrives as a `DOMException`,
|
|
150
|
+
* which inherits from `Error` in a browser but not in Node, and not across
|
|
151
|
+
* realms even in a browser — a Worker's exception reaching the main thread
|
|
152
|
+
* fails an `instanceof Error` test that has nothing wrong with it.
|
|
153
|
+
*/
|
|
154
|
+
function isAbortError(err) {
|
|
155
|
+
return (typeof err === 'object' &&
|
|
156
|
+
err !== null &&
|
|
157
|
+
err.name === 'AbortError');
|
|
158
|
+
}
|
|
159
|
+
/** Monotonic where available; only ever used for a human-facing duration. */
|
|
160
|
+
function nowMs() {
|
|
161
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=db-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-lock.js","sourceRoot":"","sources":["../../src/browser/db-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* engine-transport.ts – the boundary between `FirebirdBrowser` and the engine.
|
|
3
|
+
*
|
|
4
|
+
* There are two ways to reach the compiled engine, and they differ enough to
|
|
5
|
+
* be worth naming:
|
|
6
|
+
*
|
|
7
|
+
* • {@link DirectTransport} calls the WASM exports in this thread. Simple,
|
|
8
|
+
* and what Node uses.
|
|
9
|
+
* • {@link WorkerTransport} (see `worker-transport.ts`) forwards to a Web
|
|
10
|
+
* Worker. Browsers *must* use it: the build uses pthreads, Firebird
|
|
11
|
+
* blocks on mutexes while opening a database, and a browser main thread is
|
|
12
|
+
* not allowed to block — calling the engine directly from a page deadlocks.
|
|
13
|
+
*
|
|
14
|
+
* Both sides of that split need the same operations, including filesystem
|
|
15
|
+
* access: persistence copies the database between Emscripten's in-memory FS
|
|
16
|
+
* and IndexedDB, and in the Worker case that filesystem lives in the Worker.
|
|
17
|
+
*
|
|
18
|
+
* Every method is async so the two are interchangeable, even though the direct
|
|
19
|
+
* one never actually suspends.
|
|
20
|
+
*/
|
|
21
|
+
import type { Row, QueryResult, QueryParams } from '../types';
|
|
22
|
+
/** Opaque engine handle (database or transaction). 0 means "none". */
|
|
23
|
+
export type EngineHandle = number;
|
|
24
|
+
/**
|
|
25
|
+
* The operations `FirebirdBrowser` needs from the engine, wherever it runs.
|
|
26
|
+
*
|
|
27
|
+
* `txHandle` of 0 means "run this statement in its own transaction", matching
|
|
28
|
+
* the C API.
|
|
29
|
+
*/
|
|
30
|
+
export interface EngineTransport {
|
|
31
|
+
/** Initialise the engine. Safe to call more than once. */
|
|
32
|
+
init(): Promise<void>;
|
|
33
|
+
createDatabase(path: string): Promise<EngineHandle>;
|
|
34
|
+
attachDatabase(path: string): Promise<EngineHandle>;
|
|
35
|
+
detachDatabase(dbHandle: EngineHandle): Promise<void>;
|
|
36
|
+
/** Returns the number of rows the statement affected. */
|
|
37
|
+
execute(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<number>;
|
|
38
|
+
query<T extends Row = Row>(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
39
|
+
startTransaction(dbHandle: EngineHandle): Promise<EngineHandle>;
|
|
40
|
+
commit(txHandle: EngineHandle): Promise<void>;
|
|
41
|
+
rollback(txHandle: EngineHandle): Promise<void>;
|
|
42
|
+
mkdir(path: string): Promise<void>;
|
|
43
|
+
exists(path: string): Promise<boolean>;
|
|
44
|
+
readFile(path: string): Promise<Uint8Array>;
|
|
45
|
+
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
46
|
+
/** Release anything the transport owns. Does not detach databases. */
|
|
47
|
+
dispose(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/** Options accepted by {@link DirectTransport}. */
|
|
50
|
+
export interface DirectTransportOptions {
|
|
51
|
+
wasmBinary?: ArrayBuffer | string;
|
|
52
|
+
locateFile?: (filename: string) => string;
|
|
53
|
+
}
|
|
54
|
+
/** Decode the engine's JSON result set into rows keyed by column name. */
|
|
55
|
+
export declare function decodeResultSet<T extends Row>(json: string): QueryResult<T>;
|
|
56
|
+
/**
|
|
57
|
+
* Calls the engine in the current thread.
|
|
58
|
+
*
|
|
59
|
+
* Used by Node, by the Worker (which is where a browser's engine actually
|
|
60
|
+
* runs), and by tests that install a stub `createFirebirdModule`.
|
|
61
|
+
*/
|
|
62
|
+
export declare class DirectTransport implements EngineTransport {
|
|
63
|
+
private readonly options;
|
|
64
|
+
private mod;
|
|
65
|
+
private initPromise;
|
|
66
|
+
constructor(options?: DirectTransportOptions);
|
|
67
|
+
init(): Promise<void>;
|
|
68
|
+
private doInit;
|
|
69
|
+
private get module();
|
|
70
|
+
/** Run `fn` with `str` allocated on the WASM heap, freeing it afterwards. */
|
|
71
|
+
private withString;
|
|
72
|
+
createDatabase(path: string): Promise<EngineHandle>;
|
|
73
|
+
attachDatabase(path: string): Promise<EngineHandle>;
|
|
74
|
+
detachDatabase(dbHandle: EngineHandle): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Run `fn` with the packed parameters on the WASM heap.
|
|
77
|
+
*
|
|
78
|
+
* An empty list is passed as a null pointer rather than an empty buffer, so
|
|
79
|
+
* the C side takes its "no parameters" path and skips preparing an input
|
|
80
|
+
* message it would not use.
|
|
81
|
+
*/
|
|
82
|
+
private withParams;
|
|
83
|
+
execute(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<number>;
|
|
84
|
+
query<T extends Row = Row>(dbHandle: EngineHandle, txHandle: EngineHandle, sql: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
85
|
+
startTransaction(dbHandle: EngineHandle): Promise<EngineHandle>;
|
|
86
|
+
commit(txHandle: EngineHandle): Promise<void>;
|
|
87
|
+
rollback(txHandle: EngineHandle): Promise<void>;
|
|
88
|
+
mkdir(path: string): Promise<void>;
|
|
89
|
+
exists(path: string): Promise<boolean>;
|
|
90
|
+
readFile(path: string): Promise<Uint8Array>;
|
|
91
|
+
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
92
|
+
dispose(): Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=engine-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-transport.d.ts","sourceRoot":"","sources":["../../src/browser/engine-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* engine-transport.ts – the boundary between `FirebirdBrowser` and the engine.
|
|
4
|
+
*
|
|
5
|
+
* There are two ways to reach the compiled engine, and they differ enough to
|
|
6
|
+
* be worth naming:
|
|
7
|
+
*
|
|
8
|
+
* • {@link DirectTransport} calls the WASM exports in this thread. Simple,
|
|
9
|
+
* and what Node uses.
|
|
10
|
+
* • {@link WorkerTransport} (see `worker-transport.ts`) forwards to a Web
|
|
11
|
+
* Worker. Browsers *must* use it: the build uses pthreads, Firebird
|
|
12
|
+
* blocks on mutexes while opening a database, and a browser main thread is
|
|
13
|
+
* not allowed to block — calling the engine directly from a page deadlocks.
|
|
14
|
+
*
|
|
15
|
+
* Both sides of that split need the same operations, including filesystem
|
|
16
|
+
* access: persistence copies the database between Emscripten's in-memory FS
|
|
17
|
+
* and IndexedDB, and in the Worker case that filesystem lives in the Worker.
|
|
18
|
+
*
|
|
19
|
+
* Every method is async so the two are interchangeable, even though the direct
|
|
20
|
+
* one never actually suspends.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.DirectTransport = void 0;
|
|
24
|
+
exports.decodeResultSet = decodeResultSet;
|
|
25
|
+
const wasm_loader_1 = require("../wasm-loader");
|
|
26
|
+
const params_1 = require("./params");
|
|
27
|
+
const field_types_1 = require("./field-types");
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Shared helpers
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
/**
|
|
32
|
+
* Build an Error carrying whatever the engine reported.
|
|
33
|
+
*
|
|
34
|
+
* The C API returns only a numeric code; the readable Firebird message lives
|
|
35
|
+
* behind `_fb_last_error()` and is lost unless it is read immediately, before
|
|
36
|
+
* another call overwrites it.
|
|
37
|
+
*/
|
|
38
|
+
function engineError(mod, context, code) {
|
|
39
|
+
const detail = (0, wasm_loader_1.lastError)(mod);
|
|
40
|
+
const suffix = code === undefined ? '' : ` (code ${code})`;
|
|
41
|
+
return new Error(detail ? `${context}${suffix}: ${detail}` : `${context}${suffix}`);
|
|
42
|
+
}
|
|
43
|
+
/** Decode the engine's JSON result set into rows keyed by column name. */
|
|
44
|
+
function decodeResultSet(json) {
|
|
45
|
+
const parsed = JSON.parse(json);
|
|
46
|
+
const fields = parsed.columns.map((c) => ({
|
|
47
|
+
name: c.name.toUpperCase(),
|
|
48
|
+
type: c.type,
|
|
49
|
+
typeName: (0, field_types_1.firebirdTypeName)(c.type, c.scale),
|
|
50
|
+
subType: c.subType,
|
|
51
|
+
scale: c.scale,
|
|
52
|
+
length: c.length,
|
|
53
|
+
nullable: c.nullable,
|
|
54
|
+
}));
|
|
55
|
+
const rows = parsed.rows.map((cols) => Object.fromEntries(fields.map((f, i) => [f.name, cols[i]])));
|
|
56
|
+
return { rows, fields };
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// DirectTransport
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Calls the engine in the current thread.
|
|
63
|
+
*
|
|
64
|
+
* Used by Node, by the Worker (which is where a browser's engine actually
|
|
65
|
+
* runs), and by tests that install a stub `createFirebirdModule`.
|
|
66
|
+
*/
|
|
67
|
+
class DirectTransport {
|
|
68
|
+
constructor(options = {}) {
|
|
69
|
+
this.options = options;
|
|
70
|
+
this.mod = null;
|
|
71
|
+
this.initPromise = null;
|
|
72
|
+
}
|
|
73
|
+
async init() {
|
|
74
|
+
// Concurrent first calls must not each load the module.
|
|
75
|
+
if (!this.initPromise) {
|
|
76
|
+
this.initPromise = this.doInit();
|
|
77
|
+
}
|
|
78
|
+
await this.initPromise;
|
|
79
|
+
}
|
|
80
|
+
async doInit() {
|
|
81
|
+
this.mod = await (0, wasm_loader_1.loadFirebirdWasm)({
|
|
82
|
+
wasmBinary: this.options.wasmBinary,
|
|
83
|
+
locateFile: this.options.locateFile,
|
|
84
|
+
});
|
|
85
|
+
const rc = this.mod._fb_init();
|
|
86
|
+
if (rc !== 0) {
|
|
87
|
+
throw engineError(this.mod, 'Failed to initialise the Firebird engine', rc);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
get module() {
|
|
91
|
+
if (!this.mod) {
|
|
92
|
+
throw new Error('EngineTransport used before init()');
|
|
93
|
+
}
|
|
94
|
+
return this.mod;
|
|
95
|
+
}
|
|
96
|
+
/** Run `fn` with `str` allocated on the WASM heap, freeing it afterwards. */
|
|
97
|
+
withString(str, fn) {
|
|
98
|
+
const mod = this.module;
|
|
99
|
+
const ptr = (0, wasm_loader_1.allocString)(mod, str);
|
|
100
|
+
try {
|
|
101
|
+
return fn(ptr);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
mod._free(ptr);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async createDatabase(path) {
|
|
108
|
+
const mod = this.module;
|
|
109
|
+
const handle = this.withString(path, (p) => mod._fb_create_database(p));
|
|
110
|
+
if (handle === 0) {
|
|
111
|
+
throw engineError(mod, `Failed to create database "${path}"`);
|
|
112
|
+
}
|
|
113
|
+
return handle;
|
|
114
|
+
}
|
|
115
|
+
async attachDatabase(path) {
|
|
116
|
+
const mod = this.module;
|
|
117
|
+
const handle = this.withString(path, (p) => mod._fb_attach_database(p));
|
|
118
|
+
if (handle === 0) {
|
|
119
|
+
throw engineError(mod, `Failed to open database "${path}"`);
|
|
120
|
+
}
|
|
121
|
+
return handle;
|
|
122
|
+
}
|
|
123
|
+
async detachDatabase(dbHandle) {
|
|
124
|
+
this.module._fb_detach_database(dbHandle);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Run `fn` with the packed parameters on the WASM heap.
|
|
128
|
+
*
|
|
129
|
+
* An empty list is passed as a null pointer rather than an empty buffer, so
|
|
130
|
+
* the C side takes its "no parameters" path and skips preparing an input
|
|
131
|
+
* message it would not use.
|
|
132
|
+
*/
|
|
133
|
+
withParams(params, fn) {
|
|
134
|
+
if (!params || params.length === 0) {
|
|
135
|
+
return fn(0, 0);
|
|
136
|
+
}
|
|
137
|
+
const mod = this.module;
|
|
138
|
+
const packed = (0, params_1.encodeParams)(params);
|
|
139
|
+
const ptr = mod._malloc(packed.length);
|
|
140
|
+
try {
|
|
141
|
+
mod.HEAPU8.set(packed, ptr);
|
|
142
|
+
return fn(ptr, packed.length);
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
mod._free(ptr);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async execute(dbHandle, txHandle, sql, params = []) {
|
|
149
|
+
const mod = this.module;
|
|
150
|
+
const rc = this.withString(sql, (sqlPtr) => this.withParams(params, (paramPtr, paramLen) => params.length === 0
|
|
151
|
+
? mod._fb_execute(dbHandle, txHandle, sqlPtr)
|
|
152
|
+
: mod._fb_execute_params(dbHandle, txHandle, sqlPtr, paramPtr, paramLen)));
|
|
153
|
+
if (rc !== 0) {
|
|
154
|
+
throw engineError(mod, `Firebird exec failed for: ${sql}`, rc);
|
|
155
|
+
}
|
|
156
|
+
return mod._fb_last_affected_rows();
|
|
157
|
+
}
|
|
158
|
+
async query(dbHandle, txHandle, sql, params = []) {
|
|
159
|
+
const mod = this.module;
|
|
160
|
+
return this.withString(sql, (sqlPtr) => this.withParams(params, (paramPtr, paramLen) => {
|
|
161
|
+
const resultPtr = params.length === 0
|
|
162
|
+
? mod._fb_query(dbHandle, txHandle, sqlPtr)
|
|
163
|
+
: mod._fb_query_params(dbHandle, txHandle, sqlPtr, paramPtr, paramLen);
|
|
164
|
+
if (resultPtr === 0) {
|
|
165
|
+
throw engineError(mod, `Firebird query failed for: ${sql}`);
|
|
166
|
+
}
|
|
167
|
+
// The engine owns the buffer until fb_free_result.
|
|
168
|
+
const json = mod.UTF8ToString(resultPtr);
|
|
169
|
+
mod._fb_free_result(resultPtr);
|
|
170
|
+
return decodeResultSet(json);
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
async startTransaction(dbHandle) {
|
|
174
|
+
const mod = this.module;
|
|
175
|
+
const txHandle = mod._fb_start_transaction(dbHandle);
|
|
176
|
+
if (txHandle === 0) {
|
|
177
|
+
throw engineError(mod, 'Failed to start transaction');
|
|
178
|
+
}
|
|
179
|
+
return txHandle;
|
|
180
|
+
}
|
|
181
|
+
async commit(txHandle) {
|
|
182
|
+
const mod = this.module;
|
|
183
|
+
const rc = mod._fb_commit(txHandle);
|
|
184
|
+
if (rc !== 0) {
|
|
185
|
+
// fb_commit finishes the transaction whatever the outcome, so there is
|
|
186
|
+
// nothing left to roll back here.
|
|
187
|
+
throw engineError(mod, 'Transaction commit failed', rc);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async rollback(txHandle) {
|
|
191
|
+
this.module._fb_rollback(txHandle);
|
|
192
|
+
}
|
|
193
|
+
// ── Filesystem ─────────────────────────────────────────────────────────
|
|
194
|
+
async mkdir(path) {
|
|
195
|
+
const mod = this.module;
|
|
196
|
+
if (!mod.FS.analyzePath(path).exists) {
|
|
197
|
+
mod.FS.mkdir(path);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async exists(path) {
|
|
201
|
+
return this.module.FS.analyzePath(path).exists;
|
|
202
|
+
}
|
|
203
|
+
async readFile(path) {
|
|
204
|
+
return this.module.FS.readFile(path);
|
|
205
|
+
}
|
|
206
|
+
async writeFile(path, data) {
|
|
207
|
+
this.module.FS.writeFile(path, data);
|
|
208
|
+
}
|
|
209
|
+
async dispose() {
|
|
210
|
+
// The module is cached process-wide by loadFirebirdWasm and shared with
|
|
211
|
+
// any other instance, so it is deliberately not torn down here.
|
|
212
|
+
this.mod = null;
|
|
213
|
+
this.initPromise = null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.DirectTransport = DirectTransport;
|
|
217
|
+
//# sourceMappingURL=engine-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-transport.js","sourceRoot":"","sources":["../../src/browser/engine-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* field-types.ts – readable names for Firebird's SQL type codes.
|
|
3
|
+
*
|
|
4
|
+
* The engine reports numeric type codes. Turning them into names is not
|
|
5
|
+
* decoration: `NUMERIC` and `DECIMAL` are stored as scaled integers and arrive
|
|
6
|
+
* as exact decimal strings, so a caller has to be able to tell them from a
|
|
7
|
+
* `VARCHAR` to know whether `"20.25"` is a number or text.
|
|
8
|
+
*/
|
|
9
|
+
import type { FirebirdTypeName } from '../types';
|
|
10
|
+
/**
|
|
11
|
+
* Name a Firebird SQL type code.
|
|
12
|
+
*
|
|
13
|
+
* A non-zero `scale` reports `NUMERIC`: Firebird stores `NUMERIC` and
|
|
14
|
+
* `DECIMAL` as scaled `SMALLINT`, `INTEGER`, `BIGINT` or `INT128`, so the type
|
|
15
|
+
* code alone would call them integers and hide that the value is exact and
|
|
16
|
+
* arrives as a string.
|
|
17
|
+
*/
|
|
18
|
+
export declare function firebirdTypeName(type: number, scale?: number): FirebirdTypeName;
|
|
19
|
+
//# sourceMappingURL=field-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../src/browser/field-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAgDjD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,gBAAgB,CAgB1E"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* field-types.ts – readable names for Firebird's SQL type codes.
|
|
4
|
+
*
|
|
5
|
+
* The engine reports numeric type codes. Turning them into names is not
|
|
6
|
+
* decoration: `NUMERIC` and `DECIMAL` are stored as scaled integers and arrive
|
|
7
|
+
* as exact decimal strings, so a caller has to be able to tell them from a
|
|
8
|
+
* `VARCHAR` to know whether `"20.25"` is a number or text.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.firebirdTypeName = firebirdTypeName;
|
|
12
|
+
// From firebird/impl/sqlda_pub.h. The nullable flag is the low bit, and is
|
|
13
|
+
// masked off before lookup.
|
|
14
|
+
const SQL_TEXT = 452;
|
|
15
|
+
const SQL_VARYING = 448;
|
|
16
|
+
const SQL_SHORT = 500;
|
|
17
|
+
const SQL_LONG = 496;
|
|
18
|
+
const SQL_FLOAT = 482;
|
|
19
|
+
const SQL_DOUBLE = 480;
|
|
20
|
+
const SQL_D_FLOAT = 530;
|
|
21
|
+
const SQL_TIMESTAMP = 510;
|
|
22
|
+
const SQL_BLOB = 520;
|
|
23
|
+
const SQL_ARRAY = 540;
|
|
24
|
+
const SQL_TYPE_TIME = 560;
|
|
25
|
+
const SQL_TYPE_DATE = 570;
|
|
26
|
+
const SQL_INT64 = 580;
|
|
27
|
+
const SQL_TIMESTAMP_TZ = 32754;
|
|
28
|
+
const SQL_TIME_TZ = 32756;
|
|
29
|
+
const SQL_INT128 = 32752;
|
|
30
|
+
const SQL_DEC16 = 32760;
|
|
31
|
+
const SQL_DEC34 = 32762;
|
|
32
|
+
const SQL_BOOLEAN = 32764;
|
|
33
|
+
const SQL_NULL = 32766;
|
|
34
|
+
const NAMES = {
|
|
35
|
+
[SQL_TEXT]: 'TEXT',
|
|
36
|
+
[SQL_VARYING]: 'VARYING',
|
|
37
|
+
[SQL_SHORT]: 'SMALLINT',
|
|
38
|
+
[SQL_LONG]: 'INTEGER',
|
|
39
|
+
[SQL_FLOAT]: 'FLOAT',
|
|
40
|
+
[SQL_DOUBLE]: 'DOUBLE',
|
|
41
|
+
[SQL_D_FLOAT]: 'DOUBLE',
|
|
42
|
+
[SQL_TIMESTAMP]: 'TIMESTAMP',
|
|
43
|
+
[SQL_BLOB]: 'BLOB',
|
|
44
|
+
[SQL_ARRAY]: 'ARRAY',
|
|
45
|
+
[SQL_TYPE_TIME]: 'TIME',
|
|
46
|
+
[SQL_TYPE_DATE]: 'DATE',
|
|
47
|
+
[SQL_INT64]: 'BIGINT',
|
|
48
|
+
[SQL_TIMESTAMP_TZ]: 'TIMESTAMP_TZ',
|
|
49
|
+
[SQL_TIME_TZ]: 'TIME_TZ',
|
|
50
|
+
[SQL_INT128]: 'INT128',
|
|
51
|
+
[SQL_DEC16]: 'DECFLOAT16',
|
|
52
|
+
[SQL_DEC34]: 'DECFLOAT34',
|
|
53
|
+
[SQL_BOOLEAN]: 'BOOLEAN',
|
|
54
|
+
[SQL_NULL]: 'NULL',
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Name a Firebird SQL type code.
|
|
58
|
+
*
|
|
59
|
+
* A non-zero `scale` reports `NUMERIC`: Firebird stores `NUMERIC` and
|
|
60
|
+
* `DECIMAL` as scaled `SMALLINT`, `INTEGER`, `BIGINT` or `INT128`, so the type
|
|
61
|
+
* code alone would call them integers and hide that the value is exact and
|
|
62
|
+
* arrives as a string.
|
|
63
|
+
*/
|
|
64
|
+
function firebirdTypeName(type, scale = 0) {
|
|
65
|
+
const base = type & ~1; // strip the nullable flag
|
|
66
|
+
if (scale !== 0) {
|
|
67
|
+
switch (base) {
|
|
68
|
+
case SQL_SHORT:
|
|
69
|
+
case SQL_LONG:
|
|
70
|
+
case SQL_INT64:
|
|
71
|
+
case SQL_INT128:
|
|
72
|
+
return 'NUMERIC';
|
|
73
|
+
default:
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return NAMES[base] ?? 'UNKNOWN';
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=field-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-types.js","sourceRoot":"","sources":["../../src/browser/field-types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AA0DH,4CAgBC;AAtED,2EAA2E;AAC3E,4BAA4B;AAC5B,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,UAAU,GAAG,KAAK,CAAC;AACzB,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC;AAEvB,MAAM,KAAK,GAAqC;IAC9C,CAAC,QAAQ,CAAC,EAAE,MAAM;IAClB,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,SAAS,CAAC,EAAE,UAAU;IACvB,CAAC,QAAQ,CAAC,EAAE,SAAS;IACrB,CAAC,SAAS,CAAC,EAAE,OAAO;IACpB,CAAC,UAAU,CAAC,EAAE,QAAQ;IACtB,CAAC,WAAW,CAAC,EAAE,QAAQ;IACvB,CAAC,aAAa,CAAC,EAAE,WAAW;IAC5B,CAAC,QAAQ,CAAC,EAAE,MAAM;IAClB,CAAC,SAAS,CAAC,EAAE,OAAO;IACpB,CAAC,aAAa,CAAC,EAAE,MAAM;IACvB,CAAC,aAAa,CAAC,EAAE,MAAM;IACvB,CAAC,SAAS,CAAC,EAAE,QAAQ;IACrB,CAAC,gBAAgB,CAAC,EAAE,cAAc;IAClC,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,UAAU,CAAC,EAAE,QAAQ;IACtB,CAAC,SAAS,CAAC,EAAE,YAAY;IACzB,CAAC,SAAS,CAAC,EAAE,YAAY;IACzB,CAAC,WAAW,CAAC,EAAE,SAAS;IACxB,CAAC,QAAQ,CAAC,EAAE,MAAM;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,0BAA0B;IAElD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,SAAS,CAAC;YACf,KAAK,QAAQ,CAAC;YACd,KAAK,SAAS,CAAC;YACf,KAAK,UAAU;gBACb,OAAO,SAAS,CAAC;YACnB;gBACE,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;AAClC,CAAC"}
|