fix(data-tab): fall back to LIMIT 0 preview for snapshot-less lake tables (#2197)

Lake/external tables (e.g. Paimon in StarRocks) return 'There is currently no snapshot' on data reads when no snapshot exists yet, while metadata reads (DESC/SHOW CREATE) still succeed. Opening such a table surfaced the raw server error because executeTabSql stores the failure as an 'Error' result and never reached the column fetch. Detect that error result and retry the preview with LIMIT 0, which returns the table structure (columns + empty grid). Skip the synthetic-row-id re-query on this path since it is another data read that would fail the same way.
This commit is contained in:
jischeng authored and GitHub committed 2026-06-30 18:42:05 +08:00
1 parent 0777e4aad1
commit 112fce1050
3 files changed
+74 -1

No files matched your search

@@ -1,5 +1,6 @@
import * as api from "@/lib/api";
import { effectiveDatabaseTypeForConnection, metadataSchemaForConnection } from "@/lib/jdbcDialect";
import { isNoSnapshotErrorResult } from "@/lib/queryResultError";
import { buildTableSelectSql } from "@/lib/tableSelectSql";
import { editableRowIdentifierColumns, usesSyntheticRowIdKey } from "@/lib/tableEditing";
import { useConnectionStore } from "@/stores/connectionStore";
@@ -92,6 +93,24 @@ async function openTableTarget(target: NavigationTarget, options: { tableInfoTab
primaryKeys: [],
});
await queryStore.executeTabSql(tabId, sql);
// executeTabSql surfaces query failures as an "Error" result instead of throwing.
// A snapshot-less lake table fails the data preview above but its metadata still
// reads fine — retry with LIMIT 0 so the user sees the table structure (columns +
// empty grid) rather than a cryptic server error. The flag also skips the
// synthetic-row-id re-query below, which is another data read that would fail
// the same way on a snapshot-less table.
const fellBackToLimitZero = isNoSnapshotErrorResult(queryStore.tabs.find((tab) => tab.id === tabId)?.result);
if (fellBackToLimitZero) {
const emptySql = await buildTableSelectSql({
databaseType: effectiveDbType,
schema: target.schema,
tableName: target.tableName,
whereInput: target.whereInput,
limit: 0,
});
queryStore.updateSql(tabId, emptySql);
await queryStore.executeTabSql(tabId, emptySql);
}
try {
const columns = await api.getColumns(target.connectionId, target.database, querySchema, target.tableName);
const indexes = await api.listIndexes(target.connectionId, target.database, querySchema, target.tableName).catch(() => []);
@@ -104,7 +123,7 @@ async function openTableTarget(target: NavigationTarget, options: { tableInfoTab
columns,
primaryKeys,
});
if (useRowId || config.db_type === "tdengine") {
if (!fellBackToLimitZero && (useRowId || config.db_type === "tdengine")) {
const newSql = await buildTableSelectSql({
databaseType: effectiveDbType,
schema: target.schema,