merge: quick/page-empty-after-promote — paths normalizados + error visible
This commit is contained in:
@@ -869,9 +869,19 @@ static void render() {
|
||||
auto& w = kv.second;
|
||||
if (!w.page_dirty) continue;
|
||||
const auto& m = w.meta;
|
||||
ge::tableview_count(m.duckdb_path_abs.c_str(), m.table_name.c_str(),
|
||||
m.filter_sql.empty() ? nullptr : m.filter_sql.c_str(),
|
||||
&w.total_rows);
|
||||
w.last_error.clear();
|
||||
bool ok_count = ge::tableview_count(m.duckdb_path_abs.c_str(),
|
||||
m.table_name.c_str(),
|
||||
m.filter_sql.empty() ? nullptr : m.filter_sql.c_str(),
|
||||
&w.total_rows);
|
||||
if (!ok_count) {
|
||||
char buf[512];
|
||||
std::snprintf(buf, sizeof(buf),
|
||||
"count failed | duckdb=%s table=%s",
|
||||
m.duckdb_path_abs.c_str(), m.table_name.c_str());
|
||||
w.last_error = buf;
|
||||
std::fprintf(stderr, "[graph_explorer] %s\n", buf);
|
||||
}
|
||||
if (m.columns.empty()) {
|
||||
std::vector<std::string> cols;
|
||||
if (ge::tableview_list_columns(m.duckdb_path_abs.c_str(),
|
||||
@@ -881,11 +891,19 @@ static void render() {
|
||||
w.meta.columns = cols;
|
||||
}
|
||||
}
|
||||
ge::tableview_page(m.duckdb_path_abs.c_str(), m.table_name.c_str(),
|
||||
m.id_column.c_str(), w.meta.columns,
|
||||
bool ok_page = ge::tableview_page(m.duckdb_path_abs.c_str(),
|
||||
m.table_name.c_str(), m.id_column.c_str(),
|
||||
w.meta.columns,
|
||||
m.filter_sql.empty() ? nullptr : m.filter_sql.c_str(),
|
||||
g_input_path.c_str(), m.row_type.c_str(),
|
||||
w.offset, 200, &w.page);
|
||||
if (!ok_page && w.last_error.empty()) {
|
||||
char buf[256];
|
||||
std::snprintf(buf, sizeof(buf),
|
||||
"page query failed | offset=%lld limit=200", (long long)w.offset);
|
||||
w.last_error = buf;
|
||||
std::fprintf(stderr, "[graph_explorer] %s\n", buf);
|
||||
}
|
||||
w.page_dirty = false;
|
||||
}
|
||||
if (g_app.want_promote_row && !g_app.promote_table_id.empty()
|
||||
|
||||
+19
-5
@@ -137,7 +137,12 @@ bool tableview_page(const char* duckdb_path,
|
||||
// ATTACH del SQLite. Las attaches viven por conexion; idempotente
|
||||
// detectando si ya existe seria mas robusto pero este path se llama
|
||||
// por cada page() — abrimos conexion fresca cada vez asi que no.
|
||||
std::string attach = "ATTACH '" + sql_escape(ops_db) + "' AS ops (TYPE SQLITE)";
|
||||
// Normaliza backslashes a '/' para que ATTACH lo interprete sin
|
||||
// ambiguedad en Windows.
|
||||
std::string ops_norm = ops_db;
|
||||
for (char& c : ops_norm) if (c == '\\') c = '/';
|
||||
std::string attach = "ATTACH '" + sql_escape(ops_norm.c_str())
|
||||
+ "' AS ops (TYPE SQLITE)";
|
||||
if (!duck_query_silent(h.cn, attach.c_str())) {
|
||||
// sin fallar — sin promovidas, solo perdemos el flag.
|
||||
join_ops = false;
|
||||
@@ -171,8 +176,9 @@ bool tableview_page(const char* duckdb_path,
|
||||
|
||||
duckdb_result r;
|
||||
if (duckdb_query(h.cn, sel.c_str(), &r) == DuckDBError) {
|
||||
std::fprintf(stderr, "[tableview_page] %s\n",
|
||||
duckdb_result_error(&r) ? duckdb_result_error(&r) : "?");
|
||||
const char* e = duckdb_result_error(&r);
|
||||
std::fprintf(stderr, "[tableview_page] FAIL: %s\n SQL: %s\n",
|
||||
e ? e : "?", sel.c_str());
|
||||
duckdb_destroy_result(&r);
|
||||
return false;
|
||||
}
|
||||
@@ -303,12 +309,20 @@ bool is_absolute(const char* p) {
|
||||
|
||||
} // namespace
|
||||
|
||||
// Normaliza separadores a '/' — DuckDB acepta ambos en duckdb_open pero la
|
||||
// SQL embedida en ATTACH '...' interpreta backslashes con quirks segun
|
||||
// version. Forzamos '/' siempre para evitar sorpresas en Windows.
|
||||
static std::string normalize_path(std::string p) {
|
||||
for (char& c : p) if (c == '\\') c = '/';
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string tableview_resolve_path(const char* ops_db, const char* maybe_rel) {
|
||||
if (!maybe_rel) return "";
|
||||
if (is_absolute(maybe_rel)) return maybe_rel;
|
||||
if (is_absolute(maybe_rel)) return normalize_path(maybe_rel);
|
||||
std::string base = dirname_of(ops_db);
|
||||
if (base.empty()) base = ".";
|
||||
return base + "/" + maybe_rel;
|
||||
return normalize_path(base + "/" + maybe_rel);
|
||||
}
|
||||
|
||||
bool tableview_refresh_counts(const char* ops_db,
|
||||
|
||||
@@ -1861,6 +1861,10 @@ void views_table_window(AppState& app) {
|
||||
ImGui::TextDisabled("%s · %s · %lld rows",
|
||||
m.duckdb_path.c_str(), m.table_name.c_str(),
|
||||
(long long)w.total_rows);
|
||||
if (!w.last_error.empty()) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f),
|
||||
"ERROR: %s", w.last_error.c_str());
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
// Tabla
|
||||
|
||||
Reference in New Issue
Block a user