summaryrefslogtreecommitdiff
path: root/src/test/regress/regress.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/regress/regress.c')
-rw-r--r--src/test/regress/regress.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index e5136cfa7c..3bd8a15285 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -7,7 +7,9 @@
#include <float.h>
#include <math.h>
+#include "access/htup_details.h"
#include "access/transam.h"
+#include "access/tuptoaster.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/sequence.h"
@@ -17,6 +19,8 @@
#include "utils/builtins.h"
#include "utils/geo_decls.h"
#include "utils/rel.h"
+#include "utils/typcache.h"
+#include "utils/memutils.h"
#define P_MAXDIG 12
@@ -35,6 +39,7 @@ extern char *reverse_name(char *string);
extern int oldstyle_length(int n, text *t);
extern Datum int44in(PG_FUNCTION_ARGS);
extern Datum int44out(PG_FUNCTION_ARGS);
+extern Datum make_tuple_indirect(PG_FUNCTION_ARGS);
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
@@ -737,3 +742,90 @@ int44out(PG_FUNCTION_ARGS)
*--walk = '\0';
PG_RETURN_CSTRING(result);
}
+
+PG_FUNCTION_INFO_V1(make_tuple_indirect);
+Datum
+make_tuple_indirect(PG_FUNCTION_ARGS)
+{
+ HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
+ HeapTupleData tuple;
+ int ncolumns;
+ Datum *values;
+ bool *nulls;
+
+ Oid tupType;
+ int32 tupTypmod;
+ TupleDesc tupdesc;
+
+ HeapTuple newtup;
+
+ int i;
+
+ MemoryContext old_context;
+
+ /* Extract type info from the tuple itself */
+ tupType = HeapTupleHeaderGetTypeId(rec);
+ tupTypmod = HeapTupleHeaderGetTypMod(rec);
+ tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+ ncolumns = tupdesc->natts;
+
+ /* Build a temporary HeapTuple control structure */
+ tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
+ ItemPointerSetInvalid(&(tuple.t_self));
+ tuple.t_tableOid = InvalidOid;
+ tuple.t_data = rec;
+
+ values = (Datum *) palloc(ncolumns * sizeof(Datum));
+ nulls = (bool *) palloc(ncolumns * sizeof(bool));
+
+ heap_deform_tuple(&tuple, tupdesc, values, nulls);
+
+ old_context = MemoryContextSwitchTo(TopTransactionContext);
+
+ for (i = 0; i < ncolumns; i++)
+ {
+ struct varlena *attr;
+ struct varlena *new_attr;
+ struct varatt_indirect redirect_pointer;
+
+ /* only work on existing, not-null varlenas */
+ if (tupdesc->attrs[i]->attisdropped ||
+ nulls[i] ||
+ tupdesc->attrs[i]->attlen != -1)
+ continue;
+
+ attr = (struct varlena *) DatumGetPointer(values[i]);
+
+ /* don't recursively indirect */
+ if (VARATT_IS_EXTERNAL_INDIRECT(attr))
+ continue;
+
+ /* copy datum, so it still lives later */
+ if (VARATT_IS_EXTERNAL_ONDISK(attr))
+ attr = heap_tuple_fetch_attr(attr);
+ else
+ {
+ struct varlena *oldattr = attr;
+ attr = palloc0(VARSIZE_ANY(oldattr));
+ memcpy(attr, oldattr, VARSIZE_ANY(oldattr));
+ }
+
+ /* build indirection Datum */
+ new_attr = (struct varlena *) palloc0(INDIRECT_POINTER_SIZE);
+ redirect_pointer.pointer = attr;
+ SET_VARTAG_EXTERNAL(new_attr, VARTAG_INDIRECT);
+ memcpy(VARDATA_EXTERNAL(new_attr), &redirect_pointer,
+ sizeof(redirect_pointer));
+
+ values[i] = PointerGetDatum(new_attr);
+ }
+
+ newtup = heap_form_tuple(tupdesc, values, nulls);
+ pfree(values);
+ pfree(nulls);
+ ReleaseTupleDesc(tupdesc);
+
+ MemoryContextSwitchTo(old_context);
+
+ PG_RETURN_HEAPTUPLEHEADER(newtup->t_data);
+}