Merge pull request #4630 from citusdata/fix_4626

Columnar: Fix zero column tables
pull/4672/head
Hadi Moshayedi 2021-02-09 23:12:08 -08:00 committed by GitHub
commit 29d340331e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 186 additions and 0 deletions

View File

@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "catalog/pg_am.h"
#include "commands/defrem.h"
#include "distributed/listutils.h"
#include "nodes/makefuncs.h"
#if PG_VERSION_NUM >= 120000
#include "nodes/nodeFuncs.h"
@ -46,6 +47,13 @@ struct TableReadState
TupleDesc tupleDescriptor;
Relation relation;
/*
* Following are used for tables with zero columns, or when no
* columns are projected.
*/
uint64 totalRowCount;
uint64 readRowCount;
/*
* List of Var pointers for columns in the query. We use this both for
* getting vector of projected columns, and also when we want to build
@ -112,6 +120,13 @@ ColumnarBeginRead(Relation relation, TupleDesc tupleDescriptor,
List *projectedColumnList, List *whereClauseList)
{
List *stripeList = StripesForRelfilenode(relation->rd_node);
StripeMetadata *stripeMetadata = NULL;
uint64 totalRowCount = 0;
foreach_ptr(stripeMetadata, stripeList)
{
totalRowCount += stripeMetadata->rowCount;
}
/*
* We allocate all stripe specific data in the stripeReadContext, and reset
@ -135,6 +150,8 @@ ColumnarBeginRead(Relation relation, TupleDesc tupleDescriptor,
readState->stripeReadContext = stripeReadContext;
readState->chunkData = NULL;
readState->deserializedChunkIndex = -1;
readState->readRowCount = 0;
readState->totalRowCount = totalRowCount;
return readState;
}
@ -151,6 +168,26 @@ ColumnarReadNextRow(TableReadState *readState, Datum *columnValues, bool *column
StripeMetadata *stripeMetadata = readState->currentStripeMetadata;
MemoryContext oldContext = NULL;
/*
* We rely on first column's metadata in rest of this function. So for zero
* column tables we just return "true" for totalRowCount times. We do the
* same when no columns are projected.
*/
if (readState->projectedColumnList == NIL)
{
if (readState->totalRowCount == readState->readRowCount)
{
return false;
}
else
{
int columnCount = readState->tupleDescriptor->natts;
memset(columnNulls, 1, sizeof(bool) * columnCount);
readState->readRowCount++;
return true;
}
}
/*
* If no stripes are loaded, load the next non-empty stripe. Note that when
* loading stripes, we skip over chunks whose contents can be filtered with

View File

@ -240,5 +240,99 @@ SELECT * FROM test_gen_ex;
3 | 4
(3 rows)
-- check removing all columns while having some data to simulate
-- table with non-zero rows but zero-columns.
-- https://github.com/citusdata/citus/issues/4626
BEGIN;
create table local(y int);
insert into local values (1), (2);
alter table local drop column y;
CREATE TABLE zero_col_columnar (like local) USING COLUMNAR;
ALTER TABLE local RENAME TO local_xxxxx;
INSERT INTO zero_col_columnar SELECT * FROM local_xxxxx;
COMMIT;
SELECT * FROM zero_col_columnar;
--
(2 rows)
SELECT count(*) FROM zero_col_columnar;
count
---------------------------------------------------------------------
2
(1 row)
EXPLAIN (costs off, summary off) SELECT * FROM zero_col_columnar;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (ColumnarScan) on zero_col_columnar
(1 row)
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
SELECT * FROM zero_col_columnar;
--
(5 rows)
SELECT count(*) FROM zero_col_columnar;
count
---------------------------------------------------------------------
5
(1 row)
EXPLAIN (costs off, summary off) SELECT * FROM zero_col_columnar;
QUERY PLAN
---------------------------------------------------------------------
Custom Scan (ColumnarScan) on zero_col_columnar
(1 row)
VACUUM VERBOSE zero_col_columnar;
INFO: statistics for "zero_col_columnar":
storage id: xxxxx
total file size: 16384, total data size: 0
compression rate: 1.00x
total row count: 5, stripe count: 4, average rows per stripe: 1
chunk count: 0, containing data for dropped columns: 0
ANALYZE zero_col_columnar;
VACUUM FULL zero_col_columnar;
SELECT * FROM zero_col_columnar;
--
(5 rows)
TRUNCATE zero_col_columnar;
SELECT * FROM zero_col_columnar;
--
(0 rows)
DROP TABLE zero_col_columnar;
CREATE TABLE zero_col_columnar(a int) USING columnar;
INSERT INTO zero_col_columnar SELECT i FROM generate_series(1, 5) i;
alter table zero_col_columnar drop column a;
SELECT * FROM zero_col_columnar;
--
(5 rows)
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
SELECT * FROM zero_col_columnar;
--
(8 rows)
VACUUM VERBOSE zero_col_columnar;
INFO: statistics for "zero_col_columnar":
storage id: xxxxx
total file size: 49152, total data size: 60
compression rate: 0.40x
total row count: 8, stripe count: 4, average rows per stripe: 2
chunk count: 4, containing data for dropped columns: 4, zstd compressed: 4
ANALYZE zero_col_columnar;
VACUUM FULL zero_col_columnar;
SELECT * FROM zero_col_columnar;
--
(8 rows)
SET client_min_messages TO WARNING;
DROP SCHEMA columnar_alter CASCADE;

View File

@ -123,5 +123,60 @@ INSERT INTO test_gen_ex VALUES (1), (2), (3);
ALTER TABLE test_gen_ex ADD COLUMN y int generated always as (x+1) stored;
SELECT * FROM test_gen_ex;
-- check removing all columns while having some data to simulate
-- table with non-zero rows but zero-columns.
-- https://github.com/citusdata/citus/issues/4626
BEGIN;
create table local(y int);
insert into local values (1), (2);
alter table local drop column y;
CREATE TABLE zero_col_columnar (like local) USING COLUMNAR;
ALTER TABLE local RENAME TO local_xxxxx;
INSERT INTO zero_col_columnar SELECT * FROM local_xxxxx;
COMMIT;
SELECT * FROM zero_col_columnar;
SELECT count(*) FROM zero_col_columnar;
EXPLAIN (costs off, summary off) SELECT * FROM zero_col_columnar;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
SELECT * FROM zero_col_columnar;
SELECT count(*) FROM zero_col_columnar;
EXPLAIN (costs off, summary off) SELECT * FROM zero_col_columnar;
VACUUM VERBOSE zero_col_columnar;
ANALYZE zero_col_columnar;
VACUUM FULL zero_col_columnar;
SELECT * FROM zero_col_columnar;
TRUNCATE zero_col_columnar;
SELECT * FROM zero_col_columnar;
DROP TABLE zero_col_columnar;
CREATE TABLE zero_col_columnar(a int) USING columnar;
INSERT INTO zero_col_columnar SELECT i FROM generate_series(1, 5) i;
alter table zero_col_columnar drop column a;
SELECT * FROM zero_col_columnar;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
INSERT INTO zero_col_columnar DEFAULT VALUES;
SELECT * FROM zero_col_columnar;
VACUUM VERBOSE zero_col_columnar;
ANALYZE zero_col_columnar;
VACUUM FULL zero_col_columnar;
SELECT * FROM zero_col_columnar;
SET client_min_messages TO WARNING;
DROP SCHEMA columnar_alter CASCADE;