Summary
POST /_sql responses for SELECT * (and other non-aggregate projections) come back with an empty columns array, even though each row is a fully-keyed object. Aggregate queries like SELECT count(*) return a populated columns (e.g. ["n"]). This inconsistency breaks any client that relies on columns to interpret rows.
Version: chronik-server:v2.12.1, 3-broker cluster (RF=3).
Evidence (live cluster)
POST /_sql {"query":"SELECT * FROM \"default_logs\" WHERE _timestamp >= to_timestamp_millis(...) AND _timestamp <= to_timestamp_millis(...) ORDER BY _timestamp DESC LIMIT 3"}
Response:
columns : [] <-- empty
row_count: 3
rows[0] keys: ["_timestamp_type","_timestamp","_topic","_partition","_offset","_key","_value"]
rows[0] has "_value": true
Compare with an aggregate:
POST /_sql {"query":"SELECT count(*) AS n FROM default_logs WHERE ..."}
Response: columns: ["n"], rows: [{"n": ...}] <-- columns populated
So the row data is correct and keyed, but columns is [] for SELECT *.
Impact
A client that maps rows to positional arrays using columns (or that locates a column such as _value via columns) gets nothing for SELECT *, because columns is empty. In our case (Chronik Signal) this silently made every field-filtered / projected query decode 0 rows while aggregate (count()) queries worked — a confusing, hard-to-diagnose failure. We worked around it by recovering the column set from the first row's keys, but the response should be self-consistent.
Expected
columns should list the projected columns for SELECT * (the schema of the returned rows), matching the keys present in each row object — consistent with how aggregate queries populate columns.
Notes
Possibly related to the fan-out merge path (merge_sql_responses) not carrying the columns metadata from peer responses, since aggregates (which populate columns) and SELECT * differ here. Reproduces via the round-robin unified-API service on an RF=3 topic.
Summary
POST /_sqlresponses forSELECT *(and other non-aggregate projections) come back with an emptycolumnsarray, even though each row is a fully-keyed object. Aggregate queries likeSELECT count(*)return a populatedcolumns(e.g.["n"]). This inconsistency breaks any client that relies oncolumnsto interpret rows.Version:
chronik-server:v2.12.1, 3-broker cluster (RF=3).Evidence (live cluster)
Compare with an aggregate:
So the row data is correct and keyed, but
columnsis[]forSELECT *.Impact
A client that maps
rowsto positional arrays usingcolumns(or that locates a column such as_valueviacolumns) gets nothing forSELECT *, becausecolumnsis empty. In our case (Chronik Signal) this silently made every field-filtered / projected query decode 0 rows while aggregate (count()) queries worked — a confusing, hard-to-diagnose failure. We worked around it by recovering the column set from the first row's keys, but the response should be self-consistent.Expected
columnsshould list the projected columns forSELECT *(the schema of the returned rows), matching the keys present in each row object — consistent with how aggregate queries populatecolumns.Notes
Possibly related to the fan-out merge path (
merge_sql_responses) not carrying thecolumnsmetadata from peer responses, since aggregates (which populate columns) andSELECT *differ here. Reproduces via the round-robin unified-API service on an RF=3 topic.