From c76bdc2c88b627be7a0ab309973064883eeb0573 Mon Sep 17 00:00:00 2001 From: Zhimin-arya Date: Thu, 2 Jul 2026 11:37:26 +0800 Subject: [PATCH 1/2] set createDbFileIfMissing=true for ensureAttached fn --- services/trex/core/server/index.ts | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/services/trex/core/server/index.ts b/services/trex/core/server/index.ts index 885f6105e9..977129d8f2 100644 --- a/services/trex/core/server/index.ts +++ b/services/trex/core/server/index.ts @@ -100,27 +100,6 @@ export async function initTrex() { logger.error('Failed to attach cdw_config_svc validation schema:', e); } - try { - const dbm = await DatabaseManager.get(); - const datasets = await dbm.getCredentialsDecrypted(); - const hanaConn = new Trex.TrexDB("memory"); - const hanaExec: ExecFn = (sql) => hanaConn.execute(sql, []); - for (const ds of datasets) { - if (ds.dialect !== "hana") continue; - try { - await ensureCacheAttached(ds.code, { - cacheDir: "/usr/src/data/cache", - exec: hanaExec, - }); - logger.log(`Attached HANA cache for '${ds.code}'`); - } catch (e) { - logger.error(`Failed to attach HANA cache for '${ds.code}': ${e}`); - } - } - } catch (e) { - logger.error(`Failed to enumerate HANA datasets for cache attach: ${e}`); - } - try { const dbmInstance = await DatabaseManager.get(); const credentials = await dbmInstance.getCredentialsDecrypted(); @@ -158,7 +137,7 @@ export async function initTrex() { } for (const cid of cacheIds) { try { - await ensureAttached({ cacheIds: [cid] }, { exec: attachExec }); + await ensureAttached({ cacheIds: [cid] }, { exec: attachExec, createDbFileIfMissing: true }); } catch (e) { logger.log(`[attach-startup] cache ${cid} attach failed: ${(e as Error).message}`); } From c3fa4de22162cef7906b4c376d96d57f36e66d4c Mon Sep 17 00:00:00 2001 From: Zhimin-arya Date: Thu, 2 Jul 2026 15:02:16 +0800 Subject: [PATCH 2/2] attach hana in duckdb cache as {dbname}_cache.db --- .../base/create_cachedb_hana_plugin/flow.py | 4 ++-- .../search_embedding_plugin/flow.py | 5 ++-- .../src/services/hana-hdb-dao.ts | 6 ++--- services/trex/core/server/index.ts | 24 ++++++++++++++++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/plugins/flows/base/create_cachedb_hana_plugin/flow.py b/plugins/flows/base/create_cachedb_hana_plugin/flow.py index 732a3b041d..8c252e6ea9 100644 --- a/plugins/flows/base/create_cachedb_hana_plugin/flow.py +++ b/plugins/flows/base/create_cachedb_hana_plugin/flow.py @@ -41,8 +41,8 @@ def create_schema_via_trex(database_code: str, schema_name: str): # duckdb_data_folder = Variable.get("duckdb_data_folder") # duckdb_file_path = str(Path(duckdb_data_folder) / f"{database_code}.db") - trex_dao = DBDao(dialect=SupportedDatabaseDialects.TREX, database_code=database_code) + trex_dao = DBDao(dialect=SupportedDatabaseDialects.TREX, database_code=database_code, cache_id=database_code + "_cache") trex_dao.execute_sql("CALL pg_clear_cache();") - trex_dao.create_schema(f"{database_code}.{schema_name}") + trex_dao.create_schema(f"{database_code}_cache.{schema_name}") logger.info(f"Schema '{schema_name}' in database '{database_code}' created.") diff --git a/plugins/flows/search_embedding/search_embedding_plugin/flow.py b/plugins/flows/search_embedding/search_embedding_plugin/flow.py index 492eaaf6eb..abe04083ff 100644 --- a/plugins/flows/search_embedding/search_embedding_plugin/flow.py +++ b/plugins/flows/search_embedding/search_embedding_plugin/flow.py @@ -79,12 +79,13 @@ def create_embeddings_hana(dbdao_hana, database_code, schema_name, chunksize): select_sql = sqla.text(f'SELECT CONCEPT_ID, CONCEPT_NAME FROM {quoted_schema}.CONCEPT') count_sql = sqla.text(f'SELECT COUNT(*) FROM {quoted_schema}.CONCEPT') - cache_dao = DBDao(dialect=SupportedDatabaseDialects.TREX, database_code=database_code) + # cache_id for HANA is set: database_code + "_cache", according to HANA attachement in trex, otherwise the Trex conncetion will always rounte to HANA instead of the cache + cache_dao = DBDao(dialect=SupportedDatabaseDialects.TREX, database_code=database_code, cache_id=database_code + "_cache") cache_dao.execute_sql("LOAD vss") embedding_table = 'concept_name_embeddings' embedding_cols = {'concept_id': 'INTEGER', embedding_col_name: 'FLOAT[384]'} - db_schema = f"{database_code}.{schema_name}" + db_schema = f"{database_code}_cache.{schema_name}" # Make sure the cache schema exists before writing embeddings. Mirrors create_cachedb_hana_plugin cache_dao.execute_sql("CALL pg_clear_cache();") diff --git a/plugins/functions/terminology-svc/src/services/hana-hdb-dao.ts b/plugins/functions/terminology-svc/src/services/hana-hdb-dao.ts index e59c896770..114e7afbfe 100644 --- a/plugins/functions/terminology-svc/src/services/hana-hdb-dao.ts +++ b/plugins/functions/terminology-svc/src/services/hana-hdb-dao.ts @@ -126,7 +126,7 @@ export class HanaHDBDao { try { await client.connect(); await client.query( - `ATTACH IF NOT EXISTS '/usr/src/data/cache/${this.databaseCode}.db' AS "${this.databaseCode}"`, + `ATTACH IF NOT EXISTS '/usr/src/data/cache/${this.databaseCode}_cache.db' AS "${this.databaseCode}_cache"`, ); } catch (err) { try { @@ -358,7 +358,7 @@ export class HanaHDBDao { string_split('${embedding}', ',')::FLOAT[384] ) AS embd_score FROM fts_input f - LEFT JOIN "${this.databaseCode}"."${this.schemaName}".concept_name_embeddings e USING (concept_id) + LEFT JOIN "${this.databaseCode}_cache"."${this.schemaName}".concept_name_embeddings e USING (concept_id) ), stats AS ( SELECT @@ -433,7 +433,7 @@ export class HanaHDBDao { e.concept_name_embedding, string_split('${embedding}', ',')::FLOAT[384] ) AS embd_score - FROM "${this.databaseCode}"."${this.schemaName}".concept_name_embeddings e + FROM "${this.databaseCode}_cache"."${this.schemaName}".concept_name_embeddings e ORDER BY embd_score DESC LIMIT ${env.HANA_HYBRID_TOPK} `; diff --git a/services/trex/core/server/index.ts b/services/trex/core/server/index.ts index 977129d8f2..2ca9ac4f2c 100644 --- a/services/trex/core/server/index.ts +++ b/services/trex/core/server/index.ts @@ -100,6 +100,28 @@ export async function initTrex() { logger.error('Failed to attach cdw_config_svc validation schema:', e); } + try { + const dbm = await DatabaseManager.get(); + const datasets = await dbm.getCredentialsDecrypted(); + const hanaConn = new Trex.TrexDB("memory"); + const hanaExec: ExecFn = (sql) => hanaConn.execute(sql, []); + for (const ds of datasets) { + if (ds.dialect !== "hana") continue; + try { + await ensureCacheAttached(`${ds.code}_cache`, { + createDbFileIfMissing: true, + exec: hanaExec, + }); + logger.log(`Attached HANA ${ds.code} as ${ds.code}_cache`); + } catch (e) { + logger.error(`Failed to attach HANA cache for '${ds.code}': ${e}`); + } + } + } catch (e) { + logger.error(`Failed to enumerate HANA datasets for cache attach: ${e}`); + } + + try { const dbmInstance = await DatabaseManager.get(); const credentials = await dbmInstance.getCredentialsDecrypted(); @@ -137,7 +159,7 @@ export async function initTrex() { } for (const cid of cacheIds) { try { - await ensureAttached({ cacheIds: [cid] }, { exec: attachExec, createDbFileIfMissing: true }); + await ensureAttached({ cacheIds: [cid] }, { exec: attachExec }); } catch (e) { logger.log(`[attach-startup] cache ${cid} attach failed: ${(e as Error).message}`); }