FFFF
Skip to content

All-NULL tenant via direct compress — mark_invalid never fires #10474

Description

@philkra
-- Found by: commit 038822925 agent
-- Location: tsl/src/continuous_aggs/insert.c:632-639, 712-718
--
-- When every row has a NULL tenant, the buffer is empty so the foreach
-- loop over hypertable_ids never executes. tenant_buffer_unencodable is
-- set but mark_invalid never fires. Correctness maintained via seqnum=0
-- fallback, but the code path is unusual.

\set ON_ERROR_STOP on
SET timezone TO 'UTC';
SET client_min_messages TO notice;

DROP TABLE IF EXISTS null_compress CASCADE;

SELECT (CURRENT_DATE - DATE '2019-01-01')::text || ' days' AS lookback \gset

CREATE TABLE null_compress(time timestamptz NOT NULL, sensor_id text, value float)
  WITH (tsdb.hypertable, tsdb.orderby = 'time');

ALTER TABLE null_compress SET (
    timescaledb.compress,
    timescaledb.compress_orderby = 'time',
    timescaledb.granular_refresh_column = 'sensor_id',
    timescaledb.granular_refresh_start_offset = :'lookback',
    timescaledb.granular_refresh_end_offset = '1 day'
);

CREATE MATERIALIZED VIEW null_daily
  WITH (timescaledb.continuous) AS
  SELECT time_bucket('1 day', time) AS bucket, sensor_id, sum(value) AS total
  FROM null_compress
  GROUP BY bucket, sensor_id
  WITH NO DATA;
ALTER MATERIALIZED VIEW null_daily SET (timescaledb.enable_granular_refresh = true);

-- Prime
CALL refresh_continuous_aggregate('null_daily', NULL, NULL);

-- Enable direct compress
SET timescaledb.enable_direct_compress_insert = true;
SET timescaledb.enable_direct_compress_insert_sort_batches = true;
SET timescaledb.enable_direct_compress_insert_client_sorted = false;

-- Insert ALL-NULL tenants via direct compress (1000 rows to trigger direct compress)
INSERT INTO null_compress
SELECT '2020-01-01 00:00+00'::timestamptz + (g || ' seconds')::interval,
       NULL,
       g::float
FROM generate_series(1, 1000) g;

RESET timescaledb.enable_direct_compress_insert;
RESET timescaledb.enable_direct_compress_insert_sort_batches;
RESET timescaledb.enable_direct_compress_insert_client_sorted;

-- Refresh should still work (full-refresh fallback via seqnum=0)
CALL refresh_continuous_aggregate('null_daily', NULL, NULL);

DO $$
DECLARE
  cagg_sum float;
  raw_sum float;
BEGIN
  SELECT coalesce(sum(total), 0) INTO cagg_sum FROM null_daily;
  SELECT coalesce(sum(value), 0) INTO raw_sum FROM null_compress;

  IF abs(cagg_sum - raw_sum) < 0.001 THEN
    RAISE NOTICE 'RESULT: PASS — all-NULL tenant via direct compress correctly falls back (cagg=%, raw=%)',
                 cagg_sum, raw_sum;
  ELSE
    RAISE WARNING 'RESULT: BUG CONFIRMED — all-NULL tenant data not materialized (cagg=%, raw=%)',
                  cagg_sum, raw_sum;
  END IF;
END $$;

-- Also test: mix of NULL and valid tenants in same direct-compress batch
SET timescaledb.enable_direct_compress_insert = true;
SET timescaledb.enable_direct_compress_insert_sort_batches = true;
SET timescaledb.enable_direct_compress_insert_client_sorted = false;

INSERT INTO null_compress
SELECT '2020-02-01 00:00+00'::timestamptz + (g || ' seconds')::interval,
       CASE WHEN g % 2 = 0 THEN NULL ELSE 'valid_sensor' END,
       g::float
FROM generate_series(1, 1000) g;

RESET timescaledb.enable_direct_compress_insert;
RESET timescaledb.enable_direct_compress_insert_sort_batches;
RESET timescaledb.enable_direct_compress_insert_client_sorted;

CALL refresh_continuous_aggregate('null_daily', NULL, NULL);

DO $$
DECLARE
  cagg_sum float;
  raw_sum float;
BEGIN
  SELECT coalesce(sum(total), 0) INTO cagg_sum FROM null_daily
  WHERE bucket >= '2020-02-01' AND bucket < '2020-03-01';
  SELECT coalesce(sum(value), 0) INTO raw_sum FROM null_compress
  WHERE time >= '2020-02-01' AND time < '2020-03-01';

  IF abs(cagg_sum - raw_sum) < 0.001 THEN
    RAISE NOTICE 'RESULT: PASS — mixed NULL/valid tenant via direct compress (cagg=%, raw=%)',
                 cagg_sum, raw_sum;
  ELSE
    RAISE WARNING 'RESULT: BUG CONFIRMED — mixed NULL/valid data mismatch (cagg=%, raw=%)',
                  cagg_sum, raw_sum;
  END IF;
END $$;

DROP MATERIALIZED VIEW null_daily;
DROP TABLE null_compress;

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

0