mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(sqlite): budget schema names by returned text
This commit is contained in:
1 parent
5d2c8c2b78
commit
7a46b394e7
2 files changed
+44
-24
No files matched your search
@@ -124,8 +124,10 @@ const missingSelectedTable = (name: string): SqliteInspectionFailure =>
|
||||
);
|
||||
// SQLite folds only ASCII letters when matching identifiers. Fold stored
|
||||
// bytes so replacement decoding cannot make distinct names share an identity.
|
||||
// Latin-1 maps every byte to one code unit without hex expansion. These opaque
|
||||
// keys are never returned as text or charged against the JSON reply budget.
|
||||
const sqliteNameBytesKey = (name: Uint8Array): string =>
|
||||
Buffer.from(name).toString("hex");
|
||||
Buffer.from(name.buffer, name.byteOffset, name.byteLength).toString("latin1");
|
||||
const sqliteIdentifierBytesKey = (
|
||||
name: Uint8Array,
|
||||
encoding: DatabaseEncoding,
|
||||
@@ -147,7 +149,7 @@ const sqliteIdentifierBytesKey = (
|
||||
bytes[index + asciiOffset] = letter + 0x20;
|
||||
}
|
||||
}
|
||||
return bytes.toString("hex");
|
||||
return bytes.toString("latin1");
|
||||
};
|
||||
const sqliteNameBytes = (
|
||||
db: DatabaseSync,
|
||||
@@ -333,14 +335,14 @@ const readSchema = (
|
||||
const value = tableRow.parse(raw);
|
||||
const nameKey = sqliteNameBytesKey(value.name);
|
||||
if (selectedName === undefined) {
|
||||
metadataBudget.retain(nameKey);
|
||||
metadataBudget.retain(value.display_name);
|
||||
metadata.set(nameKey, value);
|
||||
} else if (nameKey === selectedKey) {
|
||||
metadata.set(nameKey, value);
|
||||
}
|
||||
if (value.type === "virtual" && value.ncol === 0) {
|
||||
const virtualName = value.display_name;
|
||||
const prefix = `${sqliteIdentifierBytesKey(value.name, encoding)}${underscore.toString("hex")}`;
|
||||
const prefix = `${sqliteIdentifierBytesKey(value.name, encoding)}${underscore.toString("latin1")}`;
|
||||
if (
|
||||
selectedKey === undefined ||
|
||||
(unresolvedVirtualTables.length === 0 &&
|
||||
|
||||
@@ -217,26 +217,44 @@ it.each(["UTF-8", "UTF-16le", "UTF-16be"])(
|
||||
},
|
||||
);
|
||||
|
||||
it("counts schema names once when enforcing the complete reply budget", async () => {
|
||||
const names = Array.from(
|
||||
{ length: 48 },
|
||||
(_, index) => `${index}_${"x".repeat(128 * 1024)}`,
|
||||
);
|
||||
const path = await createDatabase(
|
||||
names.map((name) => `CREATE TABLE "${name}" (value TEXT);`).join("\n"),
|
||||
);
|
||||
const result = inspectSqliteDatabaseSnapshot(path, {
|
||||
path,
|
||||
schema_scope: "database",
|
||||
});
|
||||
expect(result.schema.tables).toHaveLength(names.length);
|
||||
expect(result.schema.tables.map((table) => table.name)).toEqual(
|
||||
expect.arrayContaining(names),
|
||||
);
|
||||
expect(Buffer.byteLength(JSON.stringify(result))).toBeLessThan(
|
||||
16 * 1024 * 1024,
|
||||
);
|
||||
});
|
||||
it.each(["UTF-8", "UTF-16le", "UTF-16be"])(
|
||||
"counts returned %s schema names rather than internal lookup keys in the reply budget",
|
||||
async (encoding) => {
|
||||
const names = Array.from(
|
||||
{ length: 48 },
|
||||
(_, index) => `${index}_${"x".repeat(128 * 1024)}`,
|
||||
);
|
||||
const path = await createDatabase(
|
||||
`PRAGMA encoding='${encoding}'; BEGIN; ${names
|
||||
.map((name) => `CREATE TABLE "${name}" (value TEXT);`)
|
||||
.join("\n")} COMMIT;`,
|
||||
);
|
||||
for (const schema_scope of ["inventory", "database"] as const) {
|
||||
const result = inspectSqliteDatabaseSnapshot(path, {
|
||||
path,
|
||||
schema_scope,
|
||||
});
|
||||
expect(result.database_encoding).toBe(encoding);
|
||||
expect(result.schema.completeness).toBe("complete");
|
||||
expect(result.schema.tables.map((table) => table.name).sort()).toEqual(
|
||||
[...names].sort(),
|
||||
);
|
||||
for (const table of result.schema.tables)
|
||||
expect(table).toMatchObject(
|
||||
schema_scope === "inventory"
|
||||
? { columns_completeness: "not_requested", columns: [] }
|
||||
: {
|
||||
sql: `CREATE TABLE "${table.name}" (value TEXT)`,
|
||||
columns_completeness: "complete",
|
||||
columns: [{ name: "value", declared_type: "TEXT" }],
|
||||
},
|
||||
);
|
||||
expect(
|
||||
Buffer.byteLength(JSON.stringify({ ok: true, inspection: result })),
|
||||
).toBeLessThan(16 * 1024 * 1024);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps unrelated catalog names outside the selected-table reply budget", async () => {
|
||||
const path = await createDatabase(
|
||||
|
||||
Reference in new issue
Block a user