diff --git a/cstore.h b/cstore.h index 8efb0e6af..489a4839b 100644 --- a/cstore.h +++ b/cstore.h @@ -283,7 +283,7 @@ extern StringInfo DecompressBuffer(StringInfo buffer, CompressionType compressio extern void DeleteDataFileMetadataRowIfExists(Oid relfilenode); extern void InitCStoreDataFileMetadata(Oid relfilenode, int blockRowCount); extern void InsertStripeMetadataRow(Oid relfilenode, StripeMetadata *stripe); -extern DataFileMetadata * ReadDataFileMetadata(Oid relfilenode); +extern DataFileMetadata * ReadDataFileMetadata(Oid relfilenode, bool missingOk); extern void SaveStripeSkipList(Oid relfilenode, uint64 stripe, StripeSkipList *stripeSkipList, TupleDesc tupleDescriptor); diff --git a/cstore_metadata_tables.c b/cstore_metadata_tables.c index 3ebee02e7..7c214eed5 100644 --- a/cstore_metadata_tables.c +++ b/cstore_metadata_tables.c @@ -343,7 +343,7 @@ InsertStripeMetadataRow(Oid relfilenode, StripeMetadata *stripe) * from cstore_data_files and cstore_stripes. */ DataFileMetadata * -ReadDataFileMetadata(Oid relfilenode) +ReadDataFileMetadata(Oid relfilenode, bool missingOk) { Oid cstoreStripesOid = InvalidOid; Relation cstoreStripes = NULL; @@ -358,8 +358,15 @@ ReadDataFileMetadata(Oid relfilenode) found = ReadCStoreDataFiles(relfilenode, &datafileMetadata->blockRowCount); if (!found) { - ereport(ERROR, (errmsg("Relfilenode %d doesn't belong to a cstore table.", - relfilenode))); + if (!missingOk) + { + ereport(ERROR, (errmsg("Relfilenode %d doesn't belong to a cstore table.", + relfilenode))); + } + else + { + return NULL; + } } ScanKeyInit(&scanKey[0], Anum_cstore_stripes_relfilenode, diff --git a/cstore_reader.c b/cstore_reader.c index 66807ad08..e51695353 100644 --- a/cstore_reader.c +++ b/cstore_reader.c @@ -88,7 +88,7 @@ CStoreBeginRead(Relation relation, TupleDesc tupleDescriptor, MemoryContext stripeReadContext = NULL; Oid relNode = relation->rd_node.relNode; - datafileMetadata = ReadDataFileMetadata(relNode); + datafileMetadata = ReadDataFileMetadata(relNode, false); /* * We allocate all stripe specific data in the stripeReadContext, and reset @@ -309,7 +309,7 @@ CStoreTableRowCount(Relation relation) ListCell *stripeMetadataCell = NULL; uint64 totalRowCount = 0; - datafileMetadata = ReadDataFileMetadata(relation->rd_node.relNode); + datafileMetadata = ReadDataFileMetadata(relation->rd_node.relNode, false); foreach(stripeMetadataCell, datafileMetadata->stripeMetadataList) { diff --git a/cstore_tableam.c b/cstore_tableam.c index 2744a9a76..0369ca15a 100644 --- a/cstore_tableam.c +++ b/cstore_tableam.c @@ -443,7 +443,20 @@ cstore_relation_set_new_filenode(Relation rel, MultiXactId *minmulti) { SMgrRelation srel; - CStoreOptions *options = CStoreTableAMGetOptions(); + DataFileMetadata *metadata = ReadDataFileMetadata(rel->rd_node.relNode, true); + uint64 blockRowCount = 0; + + if (metadata != NULL) + { + /* existing table (e.g. TRUNCATE), use existing blockRowCount */ + blockRowCount = metadata->blockRowCount; + } + else + { + /* new table, use options */ + CStoreOptions *options = CStoreTableAMGetOptions(); + blockRowCount = options->blockRowCount; + } /* delete old relfilenode metadata */ DeleteDataFileMetadataRowIfExists(rel->rd_node.relNode); @@ -452,7 +465,7 @@ cstore_relation_set_new_filenode(Relation rel, *freezeXid = RecentXmin; *minmulti = GetOldestMultiXactId(); srel = RelationCreateStorage(*newrnode, persistence); - InitCStoreDataFileMetadata(newrnode->relNode, options->blockRowCount); + InitCStoreDataFileMetadata(newrnode->relNode, blockRowCount); smgrclose(srel); } @@ -460,7 +473,20 @@ cstore_relation_set_new_filenode(Relation rel, static void cstore_relation_nontransactional_truncate(Relation rel) { - elog(ERROR, "cstore_relation_nontransactional_truncate not implemented"); + DataFileMetadata *metadata = ReadDataFileMetadata(rel->rd_node.relNode, false); + + /* + * No need to set new relfilenode, since the table was created in this + * transaction and no other transaction can see this relation yet. We + * can just truncate the relation. + * + * This is similar to what is done in heapam_relation_nontransactional_truncate. + */ + RelationTruncate(rel, 0); + + /* Delete old relfilenode metadata and recreate it */ + DeleteDataFileMetadataRowIfExists(rel->rd_node.relNode); + InitCStoreDataFileMetadata(rel->rd_node.relNode, metadata->blockRowCount); } diff --git a/cstore_writer.c b/cstore_writer.c index 1146bd0a3..8069f4aba 100644 --- a/cstore_writer.c +++ b/cstore_writer.c @@ -75,7 +75,7 @@ CStoreBeginWrite(Relation relation, uint64 currentStripeId = 0; Oid relNode = relation->rd_node.relNode; - datafileMetadata = ReadDataFileMetadata(relNode); + datafileMetadata = ReadDataFileMetadata(relNode, false); /* * If stripeMetadataList is not empty, jump to the position right after diff --git a/expected/am_truncate.out b/expected/am_truncate.out index 951a77f04..245c72062 100644 --- a/expected/am_truncate.out +++ b/expected/am_truncate.out @@ -153,6 +153,30 @@ SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_fil 0 (1 row) +-- test if truncation in the same transaction that created the table works properly +BEGIN; +CREATE TABLE cstore_same_transaction_truncate(a int) USING cstore_tableam; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100); +TRUNCATE cstore_same_transaction_truncate; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23); +COMMIT; +-- should output "1" for the newly created relation +SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files; + ?column? +---------- + 1 +(1 row) + +SELECT * FROM cstore_same_transaction_truncate; + a +---- + 20 + 21 + 22 + 23 +(4 rows) + +DROP TABLE cstore_same_transaction_truncate; -- test if a cached truncate from a pl/pgsql function works CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$ BEGIN diff --git a/expected/fdw_truncate.out b/expected/fdw_truncate.out index f357c6358..6192c704c 100644 --- a/expected/fdw_truncate.out +++ b/expected/fdw_truncate.out @@ -150,6 +150,30 @@ SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_fil 0 (1 row) +-- test if truncation in the same transaction that created the table works properly +BEGIN; +CREATE FOREIGN TABLE cstore_same_transaction_truncate(a int) SERVER cstore_server; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100); +TRUNCATE cstore_same_transaction_truncate; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23); +COMMIT; +-- should output "1" for the newly created relation +SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files; + ?column? +---------- + 1 +(1 row) + +SELECT * FROM cstore_same_transaction_truncate; + a +---- + 20 + 21 + 22 + 23 +(4 rows) + +DROP FOREIGN TABLE cstore_same_transaction_truncate; -- test if a cached truncate from a pl/pgsql function works CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$ BEGIN diff --git a/sql/am_truncate.sql b/sql/am_truncate.sql index ae86098ee..5d27a69fb 100644 --- a/sql/am_truncate.sql +++ b/sql/am_truncate.sql @@ -65,6 +65,20 @@ SELECT * from cstore_truncate_test; -- make sure TRUNATE deletes metadata for old relfilenode SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files; +-- test if truncation in the same transaction that created the table works properly +BEGIN; +CREATE TABLE cstore_same_transaction_truncate(a int) USING cstore_tableam; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100); +TRUNCATE cstore_same_transaction_truncate; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23); +COMMIT; + +-- should output "1" for the newly created relation +SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files; +SELECT * FROM cstore_same_transaction_truncate; + +DROP TABLE cstore_same_transaction_truncate; + -- test if a cached truncate from a pl/pgsql function works CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$ BEGIN diff --git a/sql/fdw_truncate.sql b/sql/fdw_truncate.sql index b82e7fc7b..ed2aaa04a 100644 --- a/sql/fdw_truncate.sql +++ b/sql/fdw_truncate.sql @@ -62,6 +62,20 @@ SELECT * from cstore_truncate_test; -- make sure TRUNATE deletes metadata for old relfilenode SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files; +-- test if truncation in the same transaction that created the table works properly +BEGIN; +CREATE FOREIGN TABLE cstore_same_transaction_truncate(a int) SERVER cstore_server; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100); +TRUNCATE cstore_same_transaction_truncate; +INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23); +COMMIT; + +-- should output "1" for the newly created relation +SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files; +SELECT * FROM cstore_same_transaction_truncate; + +DROP FOREIGN TABLE cstore_same_transaction_truncate; + -- test if a cached truncate from a pl/pgsql function works CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$ BEGIN