@@ -584,7 +584,7 @@ def update_top_values(con: duckdb.DuckDBPyConnection, source: dict):
584584 "pop" ,
585585 ]
586586
587- schema_cols = {f ["name" ] for f in get_schema (con , source )}
587+ schema_cols = {f ["name" ] for f in get_schema (con , source , stats = False )}
588588 fields = [f for f in fields if f in schema_cols or (f == "waf_sig_ind" and "waf_sig" in schema_cols )]
589589
590590 if not fields :
@@ -813,8 +813,8 @@ def delete_ingested_files(
813813 }
814814
815815
816- _schema_cache : dict [tuple [str , str ], tuple [float , list [dict [str , Any ]]]] = {}
817- # (source_name, table_name) -> (timestamp, schema_list)
816+ _schema_cache : dict [tuple [str , str , bool ], tuple [float , list [dict [str , Any ]]]] = {}
817+ # (source_name, table_name, stats ) -> (timestamp, schema_list)
818818# The heavy refresh_config_status path fires SUMMARIZE every 60 s. With the
819819# previous 60 s TTL the cache aged out at exactly the heavy-tick interval —
820820# now-ts hit 60.0 right when the next call landed, so we missed every time
@@ -838,14 +838,18 @@ def _clear_schema_cache(source_name: str | None = None):
838838 _schema_cache = {}
839839
840840
841- def get_schema (con : duckdb .DuckDBPyConnection , source : dict | None = None ) -> list [dict ]:
841+ def get_schema (
842+ con : duckdb .DuckDBPyConnection ,
843+ source : dict | None = None ,
844+ stats : bool = True ,
845+ ) -> list [dict ]:
842846 """Return column names and types for a source's table."""
843847 src = source or _db_main ._DEFAULT_SOURCE
844848 source_name = src ["name" ]
845849 table_name = _safe_table_name (source_name )
846850
847851 now = time .time ()
848- cache_key = (source_name , table_name )
852+ cache_key = (source_name , table_name , stats )
849853 if cache_key in _schema_cache :
850854 ts , schema = _schema_cache [cache_key ]
851855 if now - ts < _SCHEMA_CACHE_TTL :
@@ -864,6 +868,13 @@ def get_schema(con: duckdb.DuckDBPyConnection, source: dict | None = None) -> li
864868 if not table_exists :
865869 return []
866870
871+ if not stats :
872+ # SRE-22: Instant catalog schema reflection via DESCRIBE bypasses heavy data scans
873+ result = con .execute (f"DESCRIBE { table_name } " ).fetchall ()
874+ schema = [{"name" : r [0 ], "type" : r [1 ]} for r in result ]
875+ _schema_cache [cache_key ] = (now , schema )
876+ return schema
877+
867878 # Use SUMMARIZE to get rich metadata instead of just DESCRIBE.
868879 # 10_000 rows is enough sample for the precision the UI displays
869880 # (null % to 1 decimal, approx_unique relative error ~3%); the prior
0 commit comments