diff --git a/.github/workflows/postgres_dev.yaml b/.github/workflows/postgres_dev.yaml index f8da93851..c1125c56f 100644 --- a/.github/workflows/postgres_dev.yaml +++ b/.github/workflows/postgres_dev.yaml @@ -10,7 +10,7 @@ jobs: PG_INSTALL_DIR: postgresql MAKE_JOBS: 2 # postgres version to build against this can either be commit hash, branch or tag - PG_COMMIT: 5028981923 + PG_COMMIT: 3d351d916b CLANG: clang-9 LLVM_CONFIG: llvm-config-9 CC: gcc diff --git a/sql/size_utils.sql b/sql/size_utils.sql index 07112615a..dc57ebc9a 100644 --- a/sql/size_utils.sql +++ b/sql/size_utils.sql @@ -376,7 +376,7 @@ DECLARE row_count_parent BIGINT; row_count BIGINT; BEGIN - SELECT relname, nspname, c.reltuples::bigint + SELECT relname, nspname, CASE WHEN c.reltuples > 0 THEN c.reltuples::bigint ELSE 0 END INTO table_name, schema_name, row_count_parent FROM pg_class c INNER JOIN pg_namespace n ON (n.OID = c.relnamespace) @@ -394,7 +394,7 @@ BEGIN FROM pg_inherits i JOIN inherited_id b ON i.inhparent = b.oid ) - SELECT sum(child.reltuples)::bigint + SELECT sum(CASE WHEN child.reltuples > 0 THEN child.reltuples ELSE 0 END)::bigint INTO row_count FROM inherited_id i JOIN pg_class child ON i.oid = child.oid diff --git a/tsl/src/chunk_api.c b/tsl/src/chunk_api.c index 3dbbbb789..cae0e7aea 100644 --- a/tsl/src/chunk_api.c +++ b/tsl/src/chunk_api.c @@ -512,6 +512,7 @@ chunk_get_single_stats_tuple(Chunk *chunk, TupleDesc tupdesc) Form_pg_class pgcform; Datum values[_Anum_chunk_relstats_max]; bool nulls[_Anum_chunk_relstats_max] = { false }; + float reltuples = 0; ctup = SearchSysCache1(RELOID, ObjectIdGetDatum(chunk->table_id)); @@ -528,8 +529,8 @@ chunk_get_single_stats_tuple(Chunk *chunk, TupleDesc tupdesc) Int32GetDatum(chunk->fd.hypertable_id); values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_pages)] = Int32GetDatum(pgcform->relpages); - values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_tuples)] = - Float4GetDatum(pgcform->reltuples); + reltuples = Float4GetDatum(pgcform->reltuples); + values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_tuples)] = reltuples > 0 ? reltuples : 0; values[AttrNumberGetAttrOffset(Anum_chunk_relstats_num_allvisible)] = Int32GetDatum(pgcform->relallvisible); diff --git a/tsl/src/fdw/relinfo.c b/tsl/src/fdw/relinfo.c index 4f97e7648..3748afdbc 100644 --- a/tsl/src/fdw/relinfo.c +++ b/tsl/src/fdw/relinfo.c @@ -341,7 +341,7 @@ estimate_tuples_and_pages(PlannerInfo *root, RelOptInfo *rel) Hyperspace *hyperspace; RelEstimates *estimates; - Assert(rel->tuples == 0); + Assert(rel->tuples <= 0); Assert(rel->pages == 0); /* In some cases (e.g., UPDATE stmt) top_parent_relids is not set so the best @@ -366,7 +366,7 @@ estimate_tuples_and_pages(PlannerInfo *root, RelOptInfo *rel) /* Let's first try figuring out number of tuples/pages using stats from previous chunks, otherwise make an estimation based on shared buffers size */ estimates = estimate_tuples_and_pages_using_prev_chunks(root, hyperspace, chunk); - if (estimates->tuples == 0 || estimates->pages == 0) + if (estimates->tuples <= 0 || estimates->pages == 0) estimates = estimate_tuples_and_pages_using_shared_buffers(root, ht, rel->reltarget->width); chunk_fillfactor = estimate_chunk_fillfactor(chunk, hyperspace); @@ -478,9 +478,10 @@ fdw_relinfo_create(PlannerInfo *root, RelOptInfo *rel, Oid server_oid, Oid local /* * If the foreign table has never been ANALYZEd, it will have relpages * and reltuples equal to zero, which most likely has nothing to do - * with reality. The best we can do is estimate number of tuples/pages. + * with reality. Starting with PG14 it will have reltuples < 0, meaning + * "unknown". The best we can do is estimate number of tuples/pages. */ - if (rel->pages == 0 && rel->tuples == 0 && type == TS_FDW_RELINFO_FOREIGN_TABLE) + if (rel->pages == 0 && rel->tuples <= 0 && type == TS_FDW_RELINFO_FOREIGN_TABLE) estimate_tuples_and_pages(root, rel); /* Estimate rel size as best we can with local statistics. There are diff --git a/tsl/test/expected/chunk_api.out b/tsl/test/expected/chunk_api.out index d2a921838..207ffd38d 100644 --- a/tsl/test/expected/chunk_api.out +++ b/tsl/test/expected/chunk_api.out @@ -162,7 +162,8 @@ SELECT * FROM _timescaledb_internal.get_chunk_colstats('chunkapi'); ----------+---------------+---------+----------+-------+-------------+----------+---------------+----------------+--------------+--------------+--------------+--------------+--------------+---------------------+-------------+-------------+-------------+-------------+------------- (0 rows) -SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN +-- reltuples is -1 on PG14 when no VACUUM/ANALYZE has run yet +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY relname; diff --git a/tsl/test/expected/compression.out b/tsl/test/expected/compression.out index 22ba06ae6..a612e4dcb 100644 --- a/tsl/test/expected/compression.out +++ b/tsl/test/expected/compression.out @@ -1286,7 +1286,8 @@ FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.chunk ch , _timescaledb_catalog.chunk compch WHERE ht.table_name = 'stattest' AND ch.hypertable_id = ht.id AND compch.id = ch.compressed_chunk_id AND ch.compressed_chunk_id > 0 \gset -SELECT relpages, reltuples FROM pg_class WHERE relname = :'STAT_COMP_CHUNK_NAME'; +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE was run +SELECT relpages, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples FROM pg_class WHERE relname = :'STAT_COMP_CHUNK_NAME'; relpages | reltuples ----------+----------- 0 | 0 @@ -1401,7 +1402,8 @@ WHERE ch1.hypertable_id = ht.id and ht.table_name like 'stattest2' _timescaledb_internal._hyper_29_58_chunk (1 row) -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) @@ -1422,7 +1424,8 @@ SET reltuples = 0, relpages = 0 WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id AND ch.compressed_chunk_id > 0 ); \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) @@ -1439,7 +1442,8 @@ FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.hypertable compht WHERE ht.table_name = 'stattest2' AND ht.compressed_hypertable_id = compht.id \gset --analyze the compressed table, will update stats for the raw table. ANALYZE :STAT_COMP_TABLE; -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) diff --git a/tsl/test/expected/dist_hypertable-12.out b/tsl/test/expected/dist_hypertable-12.out index 3b0524423..459747b82 100644 --- a/tsl/test/expected/dist_hypertable-12.out +++ b/tsl/test/expected/dist_hypertable-12.out @@ -232,7 +232,8 @@ INSERT INTO disttable VALUES -- Test distributed ANALYZE. -- -- First show no statistics -SELECT relname, relkind, reltuples, relpages +-- reltuples is initially -1 before any VACUUM/ANALYZE has been run on PG14 +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass; relname | relkind | reltuples | relpages @@ -240,7 +241,7 @@ WHERE oid = 'disttable'::regclass; disttable | r | 0 | 0 (1 row) -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class cl, (SELECT show_chunks AS chunk FROM show_chunks('disttable')) ch WHERE cl.oid = ch.chunk::regclass; relname | relkind | reltuples | relpages @@ -255,7 +256,7 @@ WHERE cl.oid = ch.chunk::regclass; ANALYZE disttable; -- Show updated statistics -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass; relname | relkind | reltuples | relpages diff --git a/tsl/test/expected/dist_hypertable-13.out b/tsl/test/expected/dist_hypertable-13.out index 8418b2e8e..a92121c21 100644 --- a/tsl/test/expected/dist_hypertable-13.out +++ b/tsl/test/expected/dist_hypertable-13.out @@ -232,7 +232,8 @@ INSERT INTO disttable VALUES -- Test distributed ANALYZE. -- -- First show no statistics -SELECT relname, relkind, reltuples, relpages +-- reltuples is initially -1 before any VACUUM/ANALYZE has been run on PG14 +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass; relname | relkind | reltuples | relpages @@ -240,7 +241,7 @@ WHERE oid = 'disttable'::regclass; disttable | r | 0 | 0 (1 row) -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class cl, (SELECT show_chunks AS chunk FROM show_chunks('disttable')) ch WHERE cl.oid = ch.chunk::regclass; relname | relkind | reltuples | relpages @@ -255,7 +256,7 @@ WHERE cl.oid = ch.chunk::regclass; ANALYZE disttable; -- Show updated statistics -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass; relname | relkind | reltuples | relpages diff --git a/tsl/test/sql/chunk_api.sql b/tsl/test/sql/chunk_api.sql index 44378ff4c..d1b0cb19a 100644 --- a/tsl/test/sql/chunk_api.sql +++ b/tsl/test/sql/chunk_api.sql @@ -85,7 +85,8 @@ ORDER BY chunk_id; SELECT * FROM _timescaledb_internal.get_chunk_relstats('chunkapi'); SELECT * FROM _timescaledb_internal.get_chunk_colstats('chunkapi'); -SELECT relname, reltuples, relpages, relallvisible FROM pg_class WHERE relname IN +-- reltuples is -1 on PG14 when no VACUUM/ANALYZE has run yet +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname IN (SELECT (_timescaledb_internal.show_chunk(show_chunks)).table_name FROM show_chunks('chunkapi')) ORDER BY relname; diff --git a/tsl/test/sql/compression.sql b/tsl/test/sql/compression.sql index 1504f383d..ab8bd0b0a 100644 --- a/tsl/test/sql/compression.sql +++ b/tsl/test/sql/compression.sql @@ -541,7 +541,8 @@ FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.chunk ch WHERE ht.table_name = 'stattest' AND ch.hypertable_id = ht.id AND compch.id = ch.compressed_chunk_id AND ch.compressed_chunk_id > 0 \gset -SELECT relpages, reltuples FROM pg_class WHERE relname = :'STAT_COMP_CHUNK_NAME'; +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE was run +SELECT relpages, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples FROM pg_class WHERE relname = :'STAT_COMP_CHUNK_NAME'; -- Now verify stats are not changed when we analyze the hypertable ANALYZE stattest; @@ -584,7 +585,8 @@ FROM _timescaledb_catalog.chunk ch1, _timescaledb_catalog.hypertable ht WHERE ch1.hypertable_id = ht.id and ht.table_name like 'stattest2' ORDER BY ch1.id limit 1; -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) @@ -602,7 +604,8 @@ SET reltuples = 0, relpages = 0 AND ch.compressed_chunk_id > 0 ); \c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) @@ -616,7 +619,8 @@ WHERE ht.table_name = 'stattest2' AND ht.compressed_hypertable_id = compht.id \g --analyze the compressed table, will update stats for the raw table. ANALYZE :STAT_COMP_TABLE; -SELECT relname, reltuples, relpages, relallvisible FROM pg_class +-- reltuples is initially -1 on PG14 before VACUUM/ANALYZE has been run +SELECT relname, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages, relallvisible FROM pg_class WHERE relname in ( SELECT ch.table_name FROM _timescaledb_catalog.chunk ch, _timescaledb_catalog.hypertable ht WHERE ht.table_name = 'stattest2' AND ch.hypertable_id = ht.id ) diff --git a/tsl/test/sql/dist_hypertable.sql.in b/tsl/test/sql/dist_hypertable.sql.in index c97489e91..6ab56b923 100644 --- a/tsl/test/sql/dist_hypertable.sql.in +++ b/tsl/test/sql/dist_hypertable.sql.in @@ -173,18 +173,19 @@ INSERT INTO disttable VALUES -- -- First show no statistics -SELECT relname, relkind, reltuples, relpages +-- reltuples is initially -1 before any VACUUM/ANALYZE has been run on PG14 +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass; -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class cl, (SELECT show_chunks AS chunk FROM show_chunks('disttable')) ch WHERE cl.oid = ch.chunk::regclass; ANALYZE disttable; -- Show updated statistics -SELECT relname, relkind, reltuples, relpages +SELECT relname, relkind, CASE WHEN reltuples > 0 THEN reltuples ELSE 0 END AS reltuples, relpages FROM pg_class WHERE oid = 'disttable'::regclass;