aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/queryjumblefuncs.c140
-rw-r--r--src/include/nodes/queryjumble.h12
2 files changed, 132 insertions, 20 deletions
diff --git a/src/backend/nodes/queryjumblefuncs.c b/src/backend/nodes/queryjumblefuncs.c
index 62d6cfb7ac1..c1d72765567 100644
--- a/src/backend/nodes/queryjumblefuncs.c
+++ b/src/backend/nodes/queryjumblefuncs.c
@@ -58,8 +58,11 @@ bool query_id_squash_values = false;
*/
bool query_id_enabled = false;
+static JumbleState *InitJumble(void);
+static uint64 DoJumble(JumbleState *jstate, Node *node);
static void AppendJumble(JumbleState *jstate,
const unsigned char *item, Size size);
+static void FlushPendingNulls(JumbleState *jstate);
static void RecordConstLocation(JumbleState *jstate,
int location, bool merged);
static void _jumbleNode(JumbleState *jstate, Node *node);
@@ -120,29 +123,22 @@ CleanQuerytext(const char *query, int *location, int *len)
return query;
}
+/*
+ * JumbleQuery
+ * Recursively process the given Query producing a 64-bit hash value by
+ * hashing the relevant fields and record that value in the Query's queryId
+ * field. Return the JumbleState object used for jumbling the query.
+ */
JumbleState *
JumbleQuery(Query *query)
{
- JumbleState *jstate = NULL;
+ JumbleState *jstate;
Assert(IsQueryIdEnabled());
- jstate = (JumbleState *) palloc(sizeof(JumbleState));
+ jstate = InitJumble();
- /* Set up workspace for query jumbling */
- jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
- jstate->jumble_len = 0;
- jstate->clocations_buf_size = 32;
- jstate->clocations = (LocationLen *)
- palloc(jstate->clocations_buf_size * sizeof(LocationLen));
- jstate->clocations_count = 0;
- jstate->highest_extern_param_id = 0;
-
- /* Compute query ID and mark the Query node with it */
- _jumbleNode(jstate, (Node *) query);
- query->queryId = DatumGetUInt64(hash_any_extended(jstate->jumble,
- jstate->jumble_len,
- 0));
+ query->queryId = DoJumble(jstate, (Node *) query);
/*
* If we are unlucky enough to get a hash of zero, use 1 instead for
@@ -173,11 +169,59 @@ EnableQueryId(void)
}
/*
- * AppendJumble: Append a value that is substantive in a given query to
- * the current jumble.
+ * InitJumble
+ * Allocate a JumbleState object and make it ready to jumble.
*/
-static void
-AppendJumble(JumbleState *jstate, const unsigned char *item, Size size)
+static JumbleState *
+InitJumble(void)
+{
+ JumbleState *jstate;
+
+ jstate = (JumbleState *) palloc(sizeof(JumbleState));
+
+ /* Set up workspace for query jumbling */
+ jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE);
+ jstate->jumble_len = 0;
+ jstate->clocations_buf_size = 32;
+ jstate->clocations = (LocationLen *) palloc(jstate->clocations_buf_size *
+ sizeof(LocationLen));
+ jstate->clocations_count = 0;
+ jstate->highest_extern_param_id = 0;
+ jstate->pending_nulls = 0;
+#ifdef USE_ASSERT_CHECKING
+ jstate->total_jumble_len = 0;
+#endif
+
+ return jstate;
+}
+
+/*
+ * DoJumble
+ * Jumble the given Node using the given JumbleState and return the resulting
+ * jumble hash.
+ */
+static uint64
+DoJumble(JumbleState *jstate, Node *node)
+{
+ /* Jumble the given node */
+ _jumbleNode(jstate, node);
+
+ /* Flush any pending NULLs before doing the final hash */
+ if (jstate->pending_nulls > 0)
+ FlushPendingNulls(jstate);
+
+ /* Process the jumble buffer and produce the hash value */
+ return DatumGetUInt64(hash_any_extended(jstate->jumble,
+ jstate->jumble_len,
+ 0));
+}
+
+/*
+ * AppendJumbleInternal: Internal function for appending to the jumble buffer
+ */
+static pg_attribute_always_inline void
+AppendJumbleInternal(JumbleState *jstate, const unsigned char *item,
+ Size size)
{
unsigned char *jumble = jstate->jumble;
Size jumble_len = jstate->jumble_len;
@@ -205,11 +249,56 @@ AppendJumble(JumbleState *jstate, const unsigned char *item, Size size)
jumble_len += part_size;
item += part_size;
size -= part_size;
+
+#ifdef USE_ASSERT_CHECKING
+ jstate->total_jumble_len += part_size;
+#endif
}
+
jstate->jumble_len = jumble_len;
}
/*
+ * AppendJumble
+ * Add 'size' bytes of the given jumble 'value' to the jumble state
+ */
+static pg_noinline void
+AppendJumble(JumbleState *jstate, const unsigned char *value, Size size)
+{
+ if (jstate->pending_nulls > 0)
+ FlushPendingNulls(jstate);
+
+ AppendJumbleInternal(jstate, value, size);
+}
+
+/*
+ * AppendJumbleNull
+ * For jumbling NULL pointers
+ */
+static pg_attribute_always_inline void
+AppendJumbleNull(JumbleState *jstate)
+{
+ jstate->pending_nulls++;
+}
+
+/*
+ * FlushPendingNulls
+ * Incorporate the pending_null value into the jumble buffer.
+ *
+ * Note: Callers must ensure that there's at least 1 pending NULL.
+ */
+static pg_attribute_always_inline void
+FlushPendingNulls(JumbleState *jstate)
+{
+ Assert(jstate->pending_nulls > 0);
+
+ AppendJumbleInternal(jstate,
+ (const unsigned char *) &jstate->pending_nulls, 4);
+ jstate->pending_nulls = 0;
+}
+
+
+/*
* Record location of constant within query string of query tree that is
* currently being walked.
*
@@ -335,6 +424,8 @@ IsSquashableConstList(List *elements, Node **firstExpr, Node **lastExpr)
do { \
if (expr->str) \
AppendJumble(jstate, (const unsigned char *) (expr->str), strlen(expr->str) + 1); \
+ else \
+ AppendJumbleNull(jstate); \
} while(0)
/* Function name used for the node field attribute custom_query_jumble. */
#define JUMBLE_CUSTOM(nodetype, item) \
@@ -385,9 +476,15 @@ static void
_jumbleNode(JumbleState *jstate, Node *node)
{
Node *expr = node;
+#ifdef USE_ASSERT_CHECKING
+ Size prev_jumble_len = jstate->total_jumble_len;
+#endif
if (expr == NULL)
+ {
+ AppendJumbleNull(jstate);
return;
+ }
/* Guard against stack overflow due to overly complex expressions */
check_stack_depth();
@@ -435,6 +532,9 @@ _jumbleNode(JumbleState *jstate, Node *node)
default:
break;
}
+
+ /* Ensure we added something to the jumble buffer */
+ Assert(jstate->total_jumble_len > prev_jumble_len);
}
static void
diff --git a/src/include/nodes/queryjumble.h b/src/include/nodes/queryjumble.h
index 905f66bc0bd..62794c5a901 100644
--- a/src/include/nodes/queryjumble.h
+++ b/src/include/nodes/queryjumble.h
@@ -54,6 +54,18 @@ typedef struct JumbleState
/* highest Param id we've seen, in order to start normalization correctly */
int highest_extern_param_id;
+
+ /*
+ * Count of the number of NULL nodes seen since last appending a value.
+ * These are flushed out to the jumble buffer before subsequent appends
+ * and before performing the final jumble hash.
+ */
+ unsigned int pending_nulls;
+
+#ifdef USE_ASSERT_CHECKING
+ /* The total number of bytes added to the jumble buffer */
+ Size total_jumble_len;
+#endif
} JumbleState;
/* Values for the compute_query_id GUC */