aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/common
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2018-10-02 11:14:26 -0700
committerAndres Freund <andres@anarazel.de>2018-10-02 11:14:26 -0700
commitcc2905e963e950d01cd2cb6c860638ce9506c63d (patch)
treedeced53c4772484db83b21d85f7d50b17a21fa39 /src/backend/access/common
parent625b38ea0e98cb596b393c70e5eaba67c6f4279e (diff)
downloadpostgresql-cc2905e963e950d01cd2cb6c860638ce9506c63d.tar.gz
postgresql-cc2905e963e950d01cd2cb6c860638ce9506c63d.zip
Use slots more widely in tuple mapping code and make naming more consistent.
It's inefficient to use a single slot for mapping between tuple descriptors for multiple tuples, as previously done when using ConvertPartitionTupleSlot(), as that means the slot's tuple descriptors change for every tuple. Previously we also, via ConvertPartitionTupleSlot(), built new tuples after the mapping even in cases where we, immediately afterwards, access individual columns again. Refactor the code so one slot, on demand, is used for each partition. That avoids having to change the descriptor (and allows to use the more efficient "fixed" tuple slots). Then use slot->slot mapping, to avoid unnecessarily forming a tuple. As the naming between the tuple and slot mapping functions wasn't consistent, rename them to execute_attr_map_{tuple,slot}. It's likely that we'll also rename convert_tuples_by_* to denote that these functions "only" build a map, but that's left for later. Author: Amit Khandekar and Amit Langote, editorialized by me Reviewed-By: Amit Langote, Amit Khandekar, Andres Freund Discussion: https://postgr.es/m/CAJ3gD9fR0wRNeAE8VqffNTyONS_UfFPRpqxhnD9Q42vZB+Jvpg@mail.gmail.com https://postgr.es/m/e4f9d743-cd4b-efb0-7574-da21d86a7f36%40lab.ntt.co.jp Backpatch: -
Diffstat (limited to 'src/backend/access/common')
-rw-r--r--src/backend/access/common/tupconvert.c182
1 files changed, 131 insertions, 51 deletions
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index 3bc67b846d4..21fe8ae4909 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -4,10 +4,8 @@
* Tuple conversion support.
*
* These functions provide conversion between rowtypes that are logically
- * equivalent but might have columns in a different order or different sets
- * of dropped columns. There is some overlap of functionality with the
- * executor's "junkfilter" routines, but these functions work on bare
- * HeapTuples rather than TupleTableSlots.
+ * equivalent but might have columns in a different order or different sets of
+ * dropped columns.
*
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
@@ -22,6 +20,7 @@
#include "access/htup_details.h"
#include "access/tupconvert.h"
+#include "executor/tuptable.h"
#include "utils/builtins.h"
@@ -31,7 +30,7 @@
* The setup routine checks whether the given source and destination tuple
* descriptors are logically compatible. If not, it throws an error.
* If so, it returns NULL if they are physically compatible (ie, no conversion
- * is needed), else a TupleConversionMap that can be used by do_convert_tuple
+ * is needed), else a TupleConversionMap that can be used by execute_attr_map_tuple
* to perform the conversion.
*
* The TupleConversionMap, if needed, is palloc'd in the caller's memory
@@ -214,55 +213,13 @@ convert_tuples_by_name(TupleDesc indesc,
TupleConversionMap *map;
AttrNumber *attrMap;
int n = outdesc->natts;
- int i;
- bool same;
/* Verify compatibility and prepare attribute-number map */
- attrMap = convert_tuples_by_name_map(indesc, outdesc, msg);
-
- /*
- * Check to see if the map is one-to-one, in which case we need not do a
- * tuple conversion. We must also insist that both tupdescs either
- * specify or don't specify an OID column, else we need a conversion to
- * add/remove space for that. (For some callers, presence or absence of
- * an OID column perhaps would not really matter, but let's be safe.)
- */
- if (indesc->natts == outdesc->natts &&
- indesc->tdhasoid == outdesc->tdhasoid)
- {
- same = true;
- for (i = 0; i < n; i++)
- {
- Form_pg_attribute inatt;
- Form_pg_attribute outatt;
-
- if (attrMap[i] == (i + 1))
- continue;
-
- /*
- * If it's a dropped column and the corresponding input column is
- * also dropped, we needn't convert. However, attlen and attalign
- * must agree.
- */
- inatt = TupleDescAttr(indesc, i);
- outatt = TupleDescAttr(outdesc, i);
- if (attrMap[i] == 0 &&
- inatt->attisdropped &&
- inatt->attlen == outatt->attlen &&
- inatt->attalign == outatt->attalign)
- continue;
-
- same = false;
- break;
- }
- }
- else
- same = false;
+ attrMap = convert_tuples_by_name_map_if_req(indesc, outdesc, msg);
- if (same)
+ if (attrMap == NULL)
{
- /* Runtime conversion is not needed */
- pfree(attrMap);
+ /* runtime conversion is not needed */
return NULL;
}
@@ -368,10 +325,77 @@ convert_tuples_by_name_map(TupleDesc indesc,
}
/*
+ * Returns mapping created by convert_tuples_by_name_map, or NULL if no
+ * conversion not required. This is a convenience routine for
+ * convert_tuples_by_name() and other functions.
+ */
+AttrNumber *
+convert_tuples_by_name_map_if_req(TupleDesc indesc,
+ TupleDesc outdesc,
+ const char *msg)
+{
+ AttrNumber *attrMap;
+ int n = outdesc->natts;
+ int i;
+ bool same;
+
+ /* Verify compatibility and prepare attribute-number map */
+ attrMap = convert_tuples_by_name_map(indesc, outdesc, msg);
+
+ /*
+ * Check to see if the map is one-to-one, in which case we need not do a
+ * tuple conversion. We must also insist that both tupdescs either
+ * specify or don't specify an OID column, else we need a conversion to
+ * add/remove space for that. (For some callers, presence or absence of
+ * an OID column perhaps would not really matter, but let's be safe.)
+ */
+ if (indesc->natts == outdesc->natts &&
+ indesc->tdhasoid == outdesc->tdhasoid)
+ {
+ same = true;
+ for (i = 0; i < n; i++)
+ {
+ Form_pg_attribute inatt;
+ Form_pg_attribute outatt;
+
+ if (attrMap[i] == (i + 1))
+ continue;
+
+ /*
+ * If it's a dropped column and the corresponding input column is
+ * also dropped, we needn't convert. However, attlen and attalign
+ * must agree.
+ */
+ inatt = TupleDescAttr(indesc, i);
+ outatt = TupleDescAttr(outdesc, i);
+ if (attrMap[i] == 0 &&
+ inatt->attisdropped &&
+ inatt->attlen == outatt->attlen &&
+ inatt->attalign == outatt->attalign)
+ continue;
+
+ same = false;
+ break;
+ }
+ }
+ else
+ same = false;
+
+ if (same)
+ {
+ /* Runtime conversion is not needed */
+ pfree(attrMap);
+ return NULL;
+ }
+ else
+ return attrMap;
+}
+
+/*
* Perform conversion of a tuple according to the map.
*/
HeapTuple
-do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
+execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
{
AttrNumber *attrMap = map->attrMap;
Datum *invalues = map->invalues;
@@ -406,6 +430,62 @@ do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
}
/*
+ * Perform conversion of a tuple slot according to the map.
+ */
+TupleTableSlot *
+execute_attr_map_slot(AttrNumber *attrMap,
+ TupleTableSlot *in_slot,
+ TupleTableSlot *out_slot)
+{
+ Datum *invalues;
+ bool *inisnull;
+ Datum *outvalues;
+ bool *outisnull;
+ int outnatts;
+ int i;
+
+ /* Sanity checks */
+ Assert(in_slot->tts_tupleDescriptor != NULL &&
+ out_slot->tts_tupleDescriptor != NULL);
+ Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
+
+ outnatts = out_slot->tts_tupleDescriptor->natts;
+
+ /* Extract all the values of the in slot. */
+ slot_getallattrs(in_slot);
+
+ /* Before doing the mapping, clear any old contents from the out slot */
+ ExecClearTuple(out_slot);
+
+ invalues = in_slot->tts_values;
+ inisnull = in_slot->tts_isnull;
+ outvalues = out_slot->tts_values;
+ outisnull = out_slot->tts_isnull;
+
+ /* Transpose into proper fields of the out slot. */
+ for (i = 0; i < outnatts; i++)
+ {
+ int j = attrMap[i] - 1;
+
+ /* attrMap[i] == 0 means it's a NULL datum. */
+ if (j == -1)
+ {
+ outvalues[i] = (Datum) 0;
+ outisnull[i] = true;
+ }
+ else
+ {
+ outvalues[i] = invalues[j];
+ outisnull[i] = inisnull[j];
+ }
+ }
+
+ ExecStoreVirtualTuple(out_slot);
+
+ return out_slot;
+}
+
+/*
* Free a TupleConversionMap structure.
*/
void