fix(tableview): paths normalizados (Windows) + error visible en ventana

Hipotesis del bug 'tras promover, la tabla expandida queda a 0 filas':
en Windows std::filesystem::path::string() devuelve la ruta con
backslashes ('C:\\Users\\...\\operations.db'). Al embebirla en
'ATTACH ''<path>'' AS ops' DuckDB la interpretaba con quirks segun
version, fallaba el ATTACH (silent), pero ademas el siguiente
duckdb_open con paths mixtos podria no abrir el .duckdb correcto.

Cambios:
- tableview_resolve_path normaliza '\\' -> '/' (DuckDB acepta ambos
  para duckdb_open, pero forzamos '/' para evitar ambiguedad en SQL).
- ATTACH normaliza ops_db tambien.
- TableWindowState.last_error: cuando count o page fallan, se setea
  con el path/tabla involucrada y se muestra en rojo en la cabecera
  de la ventana. Asi el bug es visible sin abrir consola.
- tableview_page log incluye la SQL completa cuando falla — facil
  diagnosticar via stderr en linux.
This commit is contained in:
2026-05-01 17:02:22 +02:00
parent 7561c3f4bb
commit e6719a5ae0
4 changed files with 47 additions and 10 deletions
+23 -5
View File
@@ -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()