Update vector columns logic
This commit is contained in:
Vendored
+57
-20
@@ -4,7 +4,6 @@ import getTableColumns, {} from "./get-table-columns";
|
||||
import isVectorField from "./is-vector-field";
|
||||
import mapDataType from "./map-data-types";
|
||||
import MariaDBQuoteGen from "./mariadb-quote-gen";
|
||||
import recreateTable from "./recreate-table";
|
||||
import runSchemaQuery, { querySchemaRows } from "./run-schema-query";
|
||||
import schemaCondition from "./schema-condition";
|
||||
import { dropForeignKeysOnColumns } from "./sync-foreign-keys";
|
||||
@@ -141,6 +140,50 @@ async function dropColumn({ tableName, fieldName, config, }) {
|
||||
config,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Drop + re-add a column (values discarded). Used when VECTOR dimensions change —
|
||||
* MODIFY cannot resize VECTOR, and a full table rebuild is unnecessary.
|
||||
*/
|
||||
async function recreateColumn({ tableName, field, config, }) {
|
||||
if (!field.fieldName)
|
||||
return;
|
||||
console.log(`Recreating column: ${tableName}.${field.fieldName} (values will be cleared)`);
|
||||
await dropForeignKeysOnColumns({
|
||||
tableName,
|
||||
columns: [field.fieldName],
|
||||
config,
|
||||
});
|
||||
const schemaCond = schemaCondition(config);
|
||||
const indexRows = await querySchemaRows({
|
||||
query: `SELECT INDEX_NAME, COLUMN_NAME FROM information_schema.STATISTICS WHERE ${schemaCond.where} AND TABLE_NAME = ? AND INDEX_NAME <> 'PRIMARY'`,
|
||||
values: [...schemaCond.values, tableName],
|
||||
config,
|
||||
});
|
||||
const indexesToDrop = new Set();
|
||||
for (const row of indexRows) {
|
||||
if (row.COLUMN_NAME === field.fieldName) {
|
||||
indexesToDrop.add(row.INDEX_NAME);
|
||||
}
|
||||
}
|
||||
for (const indexName of indexesToDrop) {
|
||||
console.log(`Dropping index ${indexName} because column ${field.fieldName} is being recreated`);
|
||||
try {
|
||||
await runSchemaQuery({
|
||||
query: `DROP INDEX ${MariaDBQuoteGen(indexName)} ON ${MariaDBQuoteGen(tableName)}`,
|
||||
config,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
if (String(err?.message || "").includes("needed in a foreign key constraint")) {
|
||||
console.warn(`Skipping drop of index ${indexName}: required by a foreign key constraint`);
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
await dropColumn({ tableName, fieldName: field.fieldName, config });
|
||||
await addColumn({ tableName, field, config });
|
||||
}
|
||||
export default async function updateTable({ table, config, }) {
|
||||
const existingColumns = await getTableColumns({
|
||||
tableName: table.tableName,
|
||||
@@ -154,8 +197,8 @@ export default async function updateTable({ table, config, }) {
|
||||
const codeFieldsMap = new Map((table.fields || []).map((f) => [f.fieldName, f]));
|
||||
const fieldsToAdd = [];
|
||||
const fieldsToModify = [];
|
||||
const fieldsToRecreate = [];
|
||||
const fieldsToDrop = [];
|
||||
let needsVectorRecreate = false;
|
||||
for (const field of table.fields || []) {
|
||||
if (!field.fieldName)
|
||||
continue;
|
||||
@@ -168,7 +211,9 @@ export default async function updateTable({ table, config, }) {
|
||||
if (isVectorField(field)) {
|
||||
typeDiverged = vectorTypeDiverged(liveField.type, liveField.comment || "", field);
|
||||
if (typeDiverged) {
|
||||
needsVectorRecreate = true;
|
||||
// VECTOR dimensions / storage cannot be MODIFYed — drop + re-add column
|
||||
fieldsToRecreate.push(field);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const attrsDiverged = !typeDiverged && columnAttributesDiverged(liveField, field);
|
||||
@@ -177,12 +222,6 @@ export default async function updateTable({ table, config, }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Vector dimension / storage type changes → full rebuild automatically
|
||||
if (needsVectorRecreate) {
|
||||
console.log(`Vector column change detected on \`${table.tableName}\`; recreating table`);
|
||||
await recreateTable({ table, config });
|
||||
return;
|
||||
}
|
||||
for (const col of existingColumns) {
|
||||
if (!codeFieldsMap.has(col.name)) {
|
||||
fieldsToDrop.push(col.name);
|
||||
@@ -190,6 +229,7 @@ export default async function updateTable({ table, config, }) {
|
||||
}
|
||||
if (fieldsToAdd.length === 0 &&
|
||||
fieldsToModify.length === 0 &&
|
||||
fieldsToRecreate.length === 0 &&
|
||||
fieldsToDrop.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -257,17 +297,14 @@ export default async function updateTable({ table, config, }) {
|
||||
await addColumn({ tableName: table.tableName, field, config });
|
||||
}
|
||||
for (const field of fieldsToModify) {
|
||||
try {
|
||||
await modifyColumn({ tableName: table.tableName, field, config });
|
||||
}
|
||||
catch (err) {
|
||||
if (isVectorField(field)) {
|
||||
console.warn(`[Vector Resize] Re-aligning dimension spaces natively via safe migration schema rebuild.`);
|
||||
await recreateTable({ table, config });
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
await modifyColumn({ tableName: table.tableName, field, config });
|
||||
}
|
||||
for (const field of fieldsToRecreate) {
|
||||
await recreateColumn({
|
||||
tableName: table.tableName,
|
||||
field,
|
||||
config,
|
||||
});
|
||||
}
|
||||
for (const fieldName of fieldsToDrop) {
|
||||
await dropColumn({ tableName: table.tableName, fieldName, config });
|
||||
|
||||
Reference in New Issue
Block a user