From 44edf2eb6b2439516bc1b2a7819997b4c05ef71e Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 29 Jul 2024 14:18:45 -0400 Subject: [PATCH] fix: adjust to ffi breaking changes --- src/blob.ts | 6 +-- src/database.ts | 56 +++++++++++++------- src/ffi.ts | 9 ---- src/statement.ts | 134 +++++++++++------------------------------------ 4 files changed, 69 insertions(+), 136 deletions(-) diff --git a/src/blob.ts b/src/blob.ts index 402a06a..b01d65d 100644 --- a/src/blob.ts +++ b/src/blob.ts @@ -40,17 +40,17 @@ export class SQLBlob { readonly: true, db: "main", }, options); - const pHandle = new Uint32Array(2); + const pHandle = new BigUint64Array(1); unwrap(sqlite3_blob_open( db.unsafeHandle, toCString(options.db ?? "main"), toCString(options.table), toCString(options.column), - options.row, + BigInt(options.row), options.readonly === false ? 1 : 0, pHandle, )); - this.#handle = Deno.UnsafePointer.create(pHandle[0] + 2 ** 32 * pHandle[1]); + this.#handle = Deno.UnsafePointer.create(pHandle[0]); } /** Byte size of the Blob */ diff --git a/src/database.ts b/src/database.ts index 799247c..f47f053 100644 --- a/src/database.ts +++ b/src/database.ts @@ -124,6 +124,8 @@ export function isComplete(statement: string): boolean { return Boolean(sqlite3_complete(toCString(statement))); } +const BIG_MAX = BigInt(Number.MAX_SAFE_INTEGER); + /** * Represents a SQLite3 database connection. * @@ -231,9 +233,9 @@ export class Database { } } - const pHandle = new Uint32Array(2); + const pHandle = new BigUint64Array(1); const result = sqlite3_open_v2(toCString(this.#path), pHandle, flags, null); - this.#handle = Deno.UnsafePointer.create(pHandle[0] + 2 ** 32 * pHandle[1]); + this.#handle = Deno.UnsafePointer.create(pHandle[0]); if (result !== 0) sqlite3_close_v2(this.#handle); unwrap(result); @@ -314,7 +316,7 @@ export class Database { */ exec(sql: string, ...params: RestBindParameters): number { if (params.length === 0) { - const pErr = new Uint32Array(2); + const pErr = new BigUint64Array(1); sqlite3_exec( this.#handle, toCString(sql), @@ -322,7 +324,7 @@ export class Database { null, new Uint8Array(pErr.buffer), ); - const errPtr = Deno.UnsafePointer.create(pErr[0] + 2 ** 32 * pErr[1]); + const errPtr = Deno.UnsafePointer.create(pErr[0]); if (errPtr !== null) { const err = readCstr(errPtr); sqlite3_free(errPtr); @@ -444,13 +446,19 @@ export class Database { const args: any[] = []; for (let i = 0; i < nArgs; i++) { const arg = Deno.UnsafePointer.create( - Number(argptr.getBigUint64(i * 8)), + argptr.getBigUint64(i * 8), ); const type = sqlite3_value_type(arg); switch (type) { - case SQLITE_INTEGER: - args.push(sqlite3_value_int64(arg)); + case SQLITE_INTEGER: { + const value = sqlite3_value_int64(arg); + if (value < -BIG_MAX || value > BIG_MAX) { + args.push(value); + } else { + args.push(Number(value)); + } break; + } case SQLITE_FLOAT: args.push(sqlite3_value_double(arg)); break; @@ -498,15 +506,16 @@ export class Database { } else if (typeof result === "boolean") { sqlite3_result_int(ctx, result ? 1 : 0); } else if (typeof result === "number") { - if (Number.isSafeInteger(result)) sqlite3_result_int64(ctx, result); - else sqlite3_result_double(ctx, result); + if (Number.isSafeInteger(result)) { + sqlite3_result_int64(ctx, BigInt(result)); + } else sqlite3_result_double(ctx, result); } else if (typeof result === "bigint") { sqlite3_result_int64(ctx, result); } else if (typeof result === "string") { const buffer = new TextEncoder().encode(result); - sqlite3_result_text(ctx, buffer, buffer.byteLength, 0); + sqlite3_result_text(ctx, buffer, buffer.byteLength, 0n); } else if (result instanceof Uint8Array) { - sqlite3_result_blob(ctx, result, result.length, -1); + sqlite3_result_blob(ctx, result, result.length, -1n); } else { const buffer = new TextEncoder().encode( `Invalid return value: ${Deno.inspect(result)}`, @@ -585,13 +594,19 @@ export class Database { const args: any[] = []; for (let i = 0; i < nArgs; i++) { const arg = Deno.UnsafePointer.create( - Number(argptr.getBigUint64(i * 8)), + argptr.getBigUint64(i * 8), ); const type = sqlite3_value_type(arg); switch (type) { - case SQLITE_INTEGER: - args.push(sqlite3_value_int64(arg)); + case SQLITE_INTEGER: { + const value = sqlite3_value_int64(arg); + if (value < -BIG_MAX || value > BIG_MAX) { + args.push(value); + } else { + args.push(Number(value)); + } break; + } case SQLITE_FLOAT: args.push(sqlite3_value_double(arg)); break; @@ -662,15 +677,16 @@ export class Database { } else if (typeof result === "boolean") { sqlite3_result_int(ctx, result ? 1 : 0); } else if (typeof result === "number") { - if (Number.isSafeInteger(result)) sqlite3_result_int64(ctx, result); - else sqlite3_result_double(ctx, result); + if (Number.isSafeInteger(result)) { + sqlite3_result_int64(ctx, BigInt(result)); + } else sqlite3_result_double(ctx, result); } else if (typeof result === "bigint") { sqlite3_result_int64(ctx, result); } else if (typeof result === "string") { const buffer = new TextEncoder().encode(result); - sqlite3_result_text(ctx, buffer, buffer.byteLength, 0); + sqlite3_result_text(ctx, buffer, buffer.byteLength, 0n); } else if (result instanceof Uint8Array) { - sqlite3_result_blob(ctx, result, result.length, -1); + sqlite3_result_blob(ctx, result, result.length, -1n); } else { const buffer = new TextEncoder().encode( `Invalid return value: ${Deno.inspect(result)}`, @@ -729,7 +745,7 @@ export class Database { throw new Error("Extension loading is not enabled"); } - const pzErrMsg = new Uint32Array(2); + const pzErrMsg = new BigUint64Array(1); const result = sqlite3_load_extension( this.#handle, @@ -739,7 +755,7 @@ export class Database { ); const pzErrPtr = Deno.UnsafePointer.create( - pzErrMsg[0] + 2 ** 32 * pzErrMsg[1], + pzErrMsg[0], ); if (pzErrPtr !== null) { const pzErr = readCstr(pzErrPtr); diff --git a/src/ffi.ts b/src/ffi.ts index a6a5b8d..f28757e 100644 --- a/src/ffi.ts +++ b/src/ffi.ts @@ -79,15 +79,6 @@ const symbols = { result: "i32", }, - sqlite3_step_cb: { - name: "sqlite3_step", - callback: true, - parameters: [ - "pointer", // sqlite3_stmt *pStmt - ], - result: "i32", - }, - sqlite3_column_count: { parameters: [ "pointer", // sqlite3_stmt *pStmt diff --git a/src/statement.ts b/src/statement.ts index f8b8294..aca3c27 100644 --- a/src/statement.ts +++ b/src/statement.ts @@ -39,7 +39,6 @@ const { sqlite3_bind_parameter_name, sqlite3_changes, sqlite3_column_int, - sqlite3_step_cb, } = ffi; /** Types that can be possibly serialized as SQLite bind values */ @@ -76,6 +75,8 @@ const statementFinalizer = new FinalizationRegistry( // https://github.com/sqlite/sqlite/blob/195611d8e6fc0bba559a49e91e6ceb42e4bdd6ba/src/json.c#L125-L126 const JSON_SUBTYPE = 74; +const BIG_MAX = BigInt(Number.MAX_SAFE_INTEGER); + function getColumn(handle: Deno.PointerValue, i: number, int64: boolean): any { const ty = sqlite3_column_type(handle, i); @@ -99,7 +100,11 @@ function getColumn(handle: Deno.PointerValue, i: number, int64: boolean): any { } case SQLITE_INTEGER: { - return sqlite3_column_int64(handle, i); + const val = sqlite3_column_int64(handle, i); + if (val < -BIG_MAX || val > BIG_MAX) { + return val; + } + return Number(val); } case SQLITE_FLOAT: { @@ -183,7 +188,7 @@ export class Statement { * Run the query and return the resulting rows where rows are objects * mapping column name to their corresponding values. */ - all = Record>( + all>( ...args: RestBindParameters ): T[] { return this.#allWithArgs(...args); @@ -197,7 +202,7 @@ export class Statement { } constructor(public db: Database, sql: string) { - const pHandle = new Uint32Array(2); + const pHandle = new BigUint64Array(1); unwrap( sqlite3_prepare_v2( db.unsafeHandle, @@ -208,7 +213,7 @@ export class Statement { ), db.unsafeHandle, ); - this.#handle = Deno.UnsafePointer.create(pHandle[0] + 2 ** 32 * pHandle[1]); + this.#handle = Deno.UnsafePointer.create(pHandle[0]); STATEMENTS_TO_DB.set(this.#handle, db.unsafeHandle); this.#unsafeConcurrency = db.unsafeConcurrency; this.#finalizerToken = { handle: this.#handle }; @@ -393,12 +398,7 @@ export class Statement { #runNoArgs(): number { const handle = this.#handle; this.#begin(); - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (status !== SQLITE3_ROW && status !== SQLITE3_DONE) { unwrap(status, this.db.unsafeHandle); } @@ -410,12 +410,7 @@ export class Statement { const handle = this.#handle; this.#begin(); this.#bindAll(params); - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (!this.#hasNoArgs && !this.#bound && params.length) { this.#bindRefs.clear(); } @@ -428,7 +423,6 @@ export class Statement { #valuesNoArgs>(): T[] { const handle = this.#handle; - const callback = this.callback; this.#begin(); const columnCount = sqlite3_column_count(handle); const result: T[] = []; @@ -445,19 +439,10 @@ export class Statement { }; `, )(getColumn); - let status; - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + let status = sqlite3_step(handle); while (status === SQLITE3_ROW) { result.push(getRowArray(handle)); - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + status = sqlite3_step(handle); } if (status !== SQLITE3_DONE) { unwrap(status, this.db.unsafeHandle); @@ -470,7 +455,6 @@ export class Statement { ...params: RestBindParameters ): T[] { const handle = this.#handle; - const callback = this.callback; this.#begin(); this.#bindAll(params); const columnCount = sqlite3_column_count(handle); @@ -488,19 +472,10 @@ export class Statement { }; `, )(getColumn); - let status; - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + let status = sqlite3_step(handle); while (status === SQLITE3_ROW) { result.push(getRowArray(handle)); - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + status = sqlite3_step(handle); } if (!this.#hasNoArgs && !this.#bound && params.length) { this.#bindRefs.clear(); @@ -536,25 +511,15 @@ export class Statement { return this.#rowObjectFn!; } - #allNoArgs>(): T[] { + #allNoArgs(): T[] { const handle = this.#handle; - const callback = this.callback; this.#begin(); const getRowObject = this.getRowObject(); const result: T[] = []; - let status; - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + let status = sqlite3_step(handle); while (status === SQLITE3_ROW) { result.push(getRowObject(handle)); - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + status = sqlite3_step(handle); } if (status !== SQLITE3_DONE) { unwrap(status, this.db.unsafeHandle); @@ -563,28 +528,18 @@ export class Statement { return result as T[]; } - #allWithArgs>( + #allWithArgs( ...params: RestBindParameters ): T[] { const handle = this.#handle; - const callback = this.callback; this.#begin(); this.#bindAll(params); const getRowObject = this.getRowObject(); const result: T[] = []; - let status; - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + let status = sqlite3_step(handle); while (status === SQLITE3_ROW) { result.push(getRowObject(handle)); - if (callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + status = sqlite3_step(handle); } if (!this.#hasNoArgs && !this.#bound && params.length) { this.#bindRefs.clear(); @@ -612,12 +567,7 @@ export class Statement { } } - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (!this.#hasNoArgs && !this.#bound && params.length) { this.#bindRefs.clear(); @@ -642,12 +592,7 @@ export class Statement { const cc = sqlite3_column_count(handle); const arr = new Array(cc); sqlite3_reset(handle); - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (status === SQLITE3_ROW) { for (let i = 0; i < cc; i++) { arr[i] = getColumn(handle, i, int64); @@ -681,7 +626,7 @@ export class Statement { } /** Fetch only first row as an object, if any. */ - get>( + get( ...params: RestBindParameters ): T | undefined { const handle = this.#handle; @@ -699,12 +644,7 @@ export class Statement { } } - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (!this.#hasNoArgs && !this.#bound && params.length) { this.#bindRefs.clear(); @@ -723,18 +663,13 @@ export class Statement { } } - #getNoArgs>(): T | undefined { + #getNoArgs(): T | undefined { const handle = this.#handle; const int64 = this.db.int64; const columnNames = this.columnNames(); const row: Record = this.#rowObject; sqlite3_reset(handle); - let status; - if (this.callback) { - status = sqlite3_step_cb(handle); - } else { - status = sqlite3_step(handle); - } + const status = sqlite3_step(handle); if (status === SQLITE3_ROW) { for (let i = 0; i < columnNames?.length; i++) { row[columnNames[i]] = getColumn(handle, i, int64); @@ -766,19 +701,10 @@ export class Statement { *[Symbol.iterator](): IterableIterator { this.#begin(); const getRowObject = this.getRowObject(); - let status; - if (this.callback) { - status = sqlite3_step_cb(this.#handle); - } else { - status = sqlite3_step(this.#handle); - } + let status = sqlite3_step(this.#handle); while (status === SQLITE3_ROW) { yield getRowObject(this.#handle); - if (this.callback) { - status = sqlite3_step_cb(this.#handle); - } else { - status = sqlite3_step(this.#handle); - } + status = sqlite3_step(this.#handle); } if (status !== SQLITE3_DONE) { unwrap(status, this.db.unsafeHandle);