aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeMemoize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeMemoize.c')
-rw-r--r--src/backend/executor/nodeMemoize.c92
1 files changed, 76 insertions, 16 deletions
diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c
index bec588b3a04..683502dd90e 100644
--- a/src/backend/executor/nodeMemoize.c
+++ b/src/backend/executor/nodeMemoize.c
@@ -71,6 +71,7 @@
#include "executor/nodeMemoize.h"
#include "lib/ilist.h"
#include "miscadmin.h"
+#include "utils/datum.h"
#include "utils/lsyscache.h"
/* States of the ExecMemoize state machine */
@@ -131,7 +132,7 @@ typedef struct MemoizeEntry
static uint32 MemoizeHash_hash(struct memoize_hash *tb,
const MemoizeKey *key);
-static int MemoizeHash_equal(struct memoize_hash *tb,
+static bool MemoizeHash_equal(struct memoize_hash *tb,
const MemoizeKey *params1,
const MemoizeKey *params2);
@@ -140,7 +141,7 @@ static int MemoizeHash_equal(struct memoize_hash *tb,
#define SH_KEY_TYPE MemoizeKey *
#define SH_KEY key
#define SH_HASH_KEY(tb, key) MemoizeHash_hash(tb, key)
-#define SH_EQUAL(tb, a, b) (MemoizeHash_equal(tb, a, b) == 0)
+#define SH_EQUAL(tb, a, b) MemoizeHash_equal(tb, a, b)
#define SH_SCOPE static inline
#define SH_STORE_HASH
#define SH_GET_HASH(tb, a) a->hash
@@ -160,21 +161,45 @@ MemoizeHash_hash(struct memoize_hash *tb, const MemoizeKey *key)
TupleTableSlot *pslot = mstate->probeslot;
uint32 hashkey = 0;
int numkeys = mstate->nkeys;
- FmgrInfo *hashfunctions = mstate->hashfunctions;
- Oid *collations = mstate->collations;
- for (int i = 0; i < numkeys; i++)
+ if (mstate->binary_mode)
{
- /* rotate hashkey left 1 bit at each step */
- hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
+ for (int i = 0; i < numkeys; i++)
+ {
+ /* rotate hashkey left 1 bit at each step */
+ hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
+
+ if (!pslot->tts_isnull[i]) /* treat nulls as having hash key 0 */
+ {
+ FormData_pg_attribute *attr;
+ uint32 hkey;
+
+ attr = &pslot->tts_tupleDescriptor->attrs[i];
+
+ hkey = datum_image_hash(pslot->tts_values[i], attr->attbyval, attr->attlen);
+
+ hashkey ^= hkey;
+ }
+ }
+ }
+ else
+ {
+ FmgrInfo *hashfunctions = mstate->hashfunctions;
+ Oid *collations = mstate->collations;
- if (!pslot->tts_isnull[i]) /* treat nulls as having hash key 0 */
+ for (int i = 0; i < numkeys; i++)
{
- uint32 hkey;
+ /* rotate hashkey left 1 bit at each step */
+ hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
+
+ if (!pslot->tts_isnull[i]) /* treat nulls as having hash key 0 */
+ {
+ uint32 hkey;
- hkey = DatumGetUInt32(FunctionCall1Coll(&hashfunctions[i],
- collations[i], pslot->tts_values[i]));
- hashkey ^= hkey;
+ hkey = DatumGetUInt32(FunctionCall1Coll(&hashfunctions[i],
+ collations[i], pslot->tts_values[i]));
+ hashkey ^= hkey;
+ }
}
}
@@ -187,7 +212,7 @@ MemoizeHash_hash(struct memoize_hash *tb, const MemoizeKey *key)
* table lookup. 'key2' is never used. Instead the MemoizeState's
* probeslot is always populated with details of what's being looked up.
*/
-static int
+static bool
MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1,
const MemoizeKey *key2)
{
@@ -199,9 +224,38 @@ MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1,
/* probeslot should have already been prepared by prepare_probe_slot() */
ExecStoreMinimalTuple(key1->params, tslot, false);
- econtext->ecxt_innertuple = tslot;
- econtext->ecxt_outertuple = pslot;
- return !ExecQualAndReset(mstate->cache_eq_expr, econtext);
+ if (mstate->binary_mode)
+ {
+ int numkeys = mstate->nkeys;
+
+ slot_getallattrs(tslot);
+ slot_getallattrs(pslot);
+
+ for (int i = 0; i < numkeys; i++)
+ {
+ FormData_pg_attribute *attr;
+
+ if (tslot->tts_isnull[i] != pslot->tts_isnull[i])
+ return false;
+
+ /* both NULL? they're equal */
+ if (tslot->tts_isnull[i])
+ continue;
+
+ /* perform binary comparison on the two datums */
+ attr = &tslot->tts_tupleDescriptor->attrs[i];
+ if (!datum_image_eq(tslot->tts_values[i], pslot->tts_values[i],
+ attr->attbyval, attr->attlen))
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ econtext->ecxt_innertuple = tslot;
+ econtext->ecxt_outertuple = pslot;
+ return ExecQualAndReset(mstate->cache_eq_expr, econtext);
+ }
}
/*
@@ -926,6 +980,12 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags)
*/
mstate->singlerow = node->singlerow;
+ /*
+ * Record if the cache keys should be compared bit by bit, or logically
+ * using the type's hash equality operator
+ */
+ mstate->binary_mode = node->binary_mode;
+
/* Zero the statistics counters */
memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));