diff --git a/migrate_llm_catelog_prod.py b/migrate_llm_catelog_prod.py new file mode 100644 index 0000000..be95f48 --- /dev/null +++ b/migrate_llm_catelog_prod.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +""" +Production Migration Script for llm -> llm_catalog_rel. +This script handles: +1. Creating the new relationship table if it doesn't exist. +2. Migrating existing single-type associations to the new table. +3. Dropping the old column (optional but recommended). + +Usage: + cd /home/hermesai/repos/sage + ./py3/bin/python migrate_llm_catelog_prod.py +""" +import asyncio +import sys +sys.path.insert(0, '.') + +from sqlor.dbpools import DBPools +from appPublic.jsonConfig import getConfig +from appPublic.uniqueID import getID + +async def migrate(): + config = getConfig('.') + db = DBPools(config.databases) + + # Sage 数据库 + dbname = 'sage' + + async with db.sqlorContext(dbname) as sor: + # 1. 检查列是否存在 + check_col_sql = "select count(*) as cnt from information_schema.columns where table_schema = database() and table_name = 'llm' and column_name = 'llmcatelogid'" + res = await sor.sqlExe(check_col_sql, {}) + has_column = res[0].cnt > 0 if res else False + + if not has_column: + print("[SKIP] Column 'llmcatelogid' does not exist in 'llm' table. Migration not needed.") + return True + + # 2. 创建表 (如果不存在) + print("[STEP 1] Ensuring table 'llm_catalog_rel' exists...") + create_sql = """ + CREATE TABLE IF NOT EXISTS llm_catalog_rel ( + id VARCHAR(32) NOT NULL PRIMARY KEY, + llmid VARCHAR(32) NOT NULL, + llmcatelogid VARCHAR(32) NOT NULL, + UNIQUE KEY uq_llm_catelog (llmid, llmcatelogid), + INDEX idx_llm (llmid), + INDEX idx_catelog (llmcatelogid) + ) + """ + try: + await sor.sqlExe(create_sql, {}) + print(" -> Table created or exists.") + except Exception as e: + print(f" -> Table creation warning: {e}") + + # 2.1 确保唯一索引存在 + print("[STEP 1.1] Ensuring unique index 'uq_llm_catelog' exists...") + try: + await sor.sqlExe("ALTER TABLE llm_catalog_rel ADD UNIQUE INDEX uq_llm_catelog (llmid, llmcatelogid)", {}) + print(" -> Unique index added.") + except Exception as e: + if "Duplicate key name" in str(e) or "Multiple primary key defined" in str(e): + print(" -> Unique index already exists.") + else: + print(f" -> Index creation warning (may already exist): {e}") + + # 3. 迁移数据 + print("[STEP 2] Migrating data...") + sql = "select id, llmcatelogid from llm where llmcatelogid is not null and llmcatelogid != ''" + rows = await sor.sqlExe(sql, {}) + print(f" -> Found {len(rows)} records to migrate.") + + migrated_count = 0 + error_count = 0 + + for r in rows: + # Check if already migrated to avoid duplicates if re-running + check_rel_sql = "select count(*) as cnt from llm_catalog_rel where llmid = ${llmid}$ and llmcatelogid = ${catelogid}$" + rel_res = await sor.sqlExe(check_rel_sql, {'llmid': r['id'], 'catelogid': r['llmcatelogid']}) + if rel_res and rel_res[0].cnt > 0: + continue + + new_id = getID() + data = { + 'id': new_id, + 'llmid': r['id'], + 'llmcatelogid': r['llmcatelogid'] + } + try: + await sor.C('llm_catalog_rel', data) + migrated_count += 1 + except Exception as e: + print(f" -> Error migrating {r['id']}: {e}") + error_count += 1 + + print(f" -> Migration complete. Inserted: {migrated_count}, Errors: {error_count}") + + # 4. 删除旧列 (生产环境谨慎执行,建议确认迁移成功后手动执行) + # print("[STEP 3] Dropping old column 'llmcatelogid'...") + # try: + # await sor.sqlExe("alter table llm drop column llmcatelogid", {}) + # print(" -> Column dropped.") + # except Exception as e: + # print(f" -> Drop column error: {e}") + + print("\n[MIGRATION DONE]") + print("Please verify data in 'llm_catalog_rel'.") + print("If correct, you may manually run: alter table llm drop column llmcatelogid;") + + return True + +if __name__ == '__main__': + print("Starting production migration...") + try: + success = asyncio.get_event_loop().run_until_complete(migrate()) + if success: + sys.exit(0) + else: + sys.exit(1) + except Exception as e: + print(f"FATAL ERROR: {e}") + import traceback + traceback.print_exc() + sys.exit(1)