diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 43323a6..e05fd00 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -19,6 +19,7 @@ SUBDIRS = \ test_rls_hooks \ test_shm_mq \ test_undo \ + test_undo_api \ worker_spi $(recurse) diff --git a/src/test/modules/test_undo_api/Makefile b/src/test/modules/test_undo_api/Makefile new file mode 100644 index 0000000..deb3816 --- /dev/null +++ b/src/test/modules/test_undo_api/Makefile @@ -0,0 +1,21 @@ +# src/test/modules/test_undo/Makefile + +MODULE_big = test_undo_api +OBJS = test_undo_api.o +PGFILEDESC = "test_undo_api - a test module for the undo api layer" + +EXTENSION = test_undo_api +DATA = test_undo_api--1.0.sql + +REGRESS = test_undo_api + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_undo_api +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_undo_api/expected/test_undo_api.out b/src/test/modules/test_undo_api/expected/test_undo_api.out new file mode 100644 index 0000000..995b517 --- /dev/null +++ b/src/test/modules/test_undo_api/expected/test_undo_api.out @@ -0,0 +1,12 @@ +CREATE EXTENSION test_undo_api; +-- +-- This test will insert the data in the undo using undo api and after that +-- it will fetch the data and verify that whether we have got the same data +-- back or not. +-- +SELECT test_undo_api(txid_current()::text::xid, 'permanent'); + test_undo_api +--------------- + +(1 row) + diff --git a/src/test/modules/test_undo_api/sql/test_undo_api.sql b/src/test/modules/test_undo_api/sql/test_undo_api.sql new file mode 100644 index 0000000..4fb40ff --- /dev/null +++ b/src/test/modules/test_undo_api/sql/test_undo_api.sql @@ -0,0 +1,8 @@ +CREATE EXTENSION test_undo_api; + +-- +-- This test will insert the data in the undo using undo api and after that +-- it will fetch the data and verify that whether we have got the same data +-- back or not. +-- +SELECT test_undo_api(txid_current()::text::xid, 'permanent'); diff --git a/src/test/modules/test_undo_api/test_undo_api--1.0.sql b/src/test/modules/test_undo_api/test_undo_api--1.0.sql new file mode 100644 index 0000000..3dd134b --- /dev/null +++ b/src/test/modules/test_undo_api/test_undo_api--1.0.sql @@ -0,0 +1,8 @@ +\echo Use "CREATE EXTENSION test_undo_api" to load this file. \quit + +CREATE FUNCTION test_undo_api(xid xid, persistence text) +RETURNS void +AS 'MODULE_PATHNAME' +LANGUAGE C; + + diff --git a/src/test/modules/test_undo_api/test_undo_api.c b/src/test/modules/test_undo_api/test_undo_api.c new file mode 100644 index 0000000..6026582 --- /dev/null +++ b/src/test/modules/test_undo_api/test_undo_api.c @@ -0,0 +1,84 @@ +#include "postgres.h" + +#include "access/transam.h" +#include "access/undoinsert.h" +#include "catalog/pg_class.h" +#include "fmgr.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "storage/bufmgr.h" +#include "utils/builtins.h" + +#include +#include + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(test_undo_api); + +static UndoPersistence +undo_persistence_from_text(text *t) +{ + char *str = text_to_cstring(t); + + if (strcmp(str, "permanent") == 0) + return UNDO_PERMANENT; + else if (strcmp(str, "temporary") == 0) + return UNDO_TEMP; + else if (strcmp(str, "unlogged") == 0) + return UNDO_UNLOGGED; + else + elog(ERROR, "unknown undo persistence level: %s", str); +} + +/* + * Prepare and insert data in undo storage and fetch it back to verify. + */ +Datum +test_undo_api(PG_FUNCTION_ARGS) +{ + TransactionId xid = DatumGetTransactionId(PG_GETARG_DATUM(0)); + UndoPersistence persistence = undo_persistence_from_text(PG_GETARG_TEXT_PP(1)); + char *data = "test_data"; + int len = strlen(data); + UnpackedUndoRecord undorecord; + UnpackedUndoRecord *undorecord_out; + int header_size = offsetof(UnpackedUndoRecord, uur_next) + sizeof(uint64); + UndoRecPtr undo_ptr; + + undorecord.uur_type = 0; + undorecord.uur_info = 0; + undorecord.uur_prevlen = 0; + undorecord.uur_prevxid = FrozenTransactionId; + undorecord.uur_xid = xid; + undorecord.uur_cid = 0; + undorecord.uur_tsid = 100; + undorecord.uur_fork = MAIN_FORKNUM; + undorecord.uur_blkprev = 0; + undorecord.uur_block = 1; + undorecord.uur_offset = 100; + initStringInfo(&undorecord.uur_tuple); + + appendBinaryStringInfo(&undorecord.uur_tuple, + (char *) data, + len); + undo_ptr = PrepareUndoInsert(&undorecord, persistence, xid, NULL); + InsertPreparedUndo(); + UnlockReleaseUndoBuffers(); + + undorecord_out = UndoFetchRecord(undo_ptr, InvalidBlockNumber, + InvalidOffsetNumber, + InvalidTransactionId, NULL, + NULL); + + if (strncmp((char *) &undorecord, (char *) undorecord_out, header_size) != 0) + elog(ERROR, "undo header did not match"); + if (strncmp(undorecord_out->uur_tuple.data, data, len) != 0) + elog(ERROR, "undo data did not match"); + + UndoRecordRelease(undorecord_out); + pfree(undorecord.uur_tuple.data); + + PG_RETURN_VOID(); +} diff --git a/src/test/modules/test_undo_api/test_undo_api.control b/src/test/modules/test_undo_api/test_undo_api.control new file mode 100644 index 0000000..09df344 --- /dev/null +++ b/src/test/modules/test_undo_api/test_undo_api.control @@ -0,0 +1,4 @@ +comment = 'test_undo_api' +default_version = '1.0' +module_pathname = '$libdir/test_undo_api' +relocatable = true