mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
fix(lbug): stop dropFTSIndex from swallowing genuine engine failures
dropFTSIndex previously caught and discarded every DROP_FTS_INDEX error unconditionally. Extract isBenignDropFtsIndexError, a pure classifier for the two legitimate "nothing to drop" cases (Binder/Catalog exceptions: index never created, or the FTS function isn't registered) verified end-to-end against @ladybugdb/core 0.18.x's real conn.query() error text. Anything else -- e.g. the Runtime exception "FTS index is inconsistent" class from #2589 -- now rethrows instead of being masked, so a corrupted index can no longer persist across analyze runs undetected.
This commit is contained in:
parent
1fd1f14cee
commit
c548652eca
2 changed files with 83 additions and 3 deletions
|
|
@ -2904,7 +2904,26 @@ export const queryFTS = async (
|
|||
};
|
||||
|
||||
/**
|
||||
* Drop an FTS index
|
||||
* True for the two benign "nothing to drop" `DROP_FTS_INDEX` failures —
|
||||
* both catalog/binder exceptions, LadybugDB's classes for "this name isn't
|
||||
* bound to anything right now" (probe-verified end-to-end through
|
||||
* `dropFTSIndex`'s real `conn.query()` path against @ladybugdb/core
|
||||
* 0.18.x): the named index was never created (`Binder exception: Table <T>
|
||||
* doesn't have an index with name <name>.`), or the FTS extension/function
|
||||
* isn't registered at all (`Catalog exception: function DROP_FTS_INDEX is
|
||||
* not defined...`). A real engine failure — e.g. the `Runtime exception:
|
||||
* FTS index '<name>' is inconsistent: ...` class from #2589 — is a
|
||||
* DIFFERENT exception class (an execution-time failure, not a catalog/bind
|
||||
* lookup miss), so this returns false for it. Pure string logic so it is
|
||||
* unit-testable without a native LadybugDB connection.
|
||||
*/
|
||||
export const isBenignDropFtsIndexError = (message: string): boolean =>
|
||||
message.includes('Binder exception:') || message.includes('Catalog exception:');
|
||||
|
||||
/**
|
||||
* Drop an FTS index. Tolerates only {@link isBenignDropFtsIndexError} —
|
||||
* anything else rethrows instead of being silently masked, which previously
|
||||
* let a corrupted index persist across analyze runs undetected.
|
||||
*/
|
||||
export const dropFTSIndex = async (tableName: string, indexName: string): Promise<void> => {
|
||||
if (!conn) {
|
||||
|
|
@ -2913,8 +2932,11 @@ export const dropFTSIndex = async (tableName: string, indexName: string): Promis
|
|||
|
||||
try {
|
||||
await queryAndDrain(conn, `CALL DROP_FTS_INDEX('${tableName}', '${indexName}')`);
|
||||
} catch {
|
||||
// Index may not exist
|
||||
} catch (e: unknown) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
if (!isBenignDropFtsIndexError(msg)) {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
ensuredFTSIndexes.delete(ftsIndexKey(tableName, indexName));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* #2589: `dropFTSIndex` must tolerate only benign "nothing to drop"
|
||||
* `DROP_FTS_INDEX` failures and rethrow everything else — previously it
|
||||
* swallowed every error unconditionally, which could mask a genuinely
|
||||
* corrupted FTS index across analyze runs.
|
||||
*
|
||||
* `isBenignDropFtsIndexError` is pure string logic (no native connection
|
||||
* needed), so the classification itself is unit-tested directly, including
|
||||
* against the exact reported #2589 error text — a native repro of that
|
||||
* specific engine failure was not achieved during investigation, but the
|
||||
* classifier's behavior for it is still provable from the message alone.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { isBenignDropFtsIndexError, dropFTSIndex } from '../../src/core/lbug/lbug-adapter.js';
|
||||
import { withTestLbugDB } from '../helpers/test-indexed-db.js';
|
||||
|
||||
describe('isBenignDropFtsIndexError', () => {
|
||||
it('is true for the FTS-extension/function-not-registered catalog error (probe-verified text)', () => {
|
||||
expect(
|
||||
isBenignDropFtsIndexError(
|
||||
"Catalog exception: function DROP_FTS_INDEX is not defined. This function exists in the FTS extension. You can install and load the extension by running 'INSTALL FTS; LOAD EXTENSION FTS;'.",
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('is true for the index-never-created binder error (probe-verified against the real dropFTSIndex path)', () => {
|
||||
expect(
|
||||
isBenignDropFtsIndexError(
|
||||
"Binder exception: Table File doesn't have an index with name file_fts.",
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('is false for the #2589 runtime inconsistency error (must surface, not be swallowed)', () => {
|
||||
expect(
|
||||
isBenignDropFtsIndexError(
|
||||
"Runtime exception: FTS index 'file_fts' is inconsistent: term 'wiki' is missing during delete.",
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('is false for an unrelated failure', () => {
|
||||
expect(isBenignDropFtsIndexError('Connection Exception: database is closed')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
withTestLbugDB('drop-fts-index-benign-cases', (handle) => {
|
||||
describe('dropFTSIndex end-to-end benign cases (#2589)', () => {
|
||||
it('resolves cleanly when the named index was never created', async () => {
|
||||
void handle;
|
||||
const { executeQuery } = await import('../../src/core/lbug/lbug-adapter.js');
|
||||
await executeQuery(
|
||||
`CREATE NODE TABLE IF NOT EXISTS DropProbe (id STRING PRIMARY KEY, content STRING)`,
|
||||
);
|
||||
await expect(dropFTSIndex('DropProbe', 'drop_probe_never_created')).resolves.toBeUndefined();
|
||||
}, 120_000);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue