aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/nodeIndexscan.c86
-rw-r--r--src/include/nodes/execnodes.h3
2 files changed, 56 insertions, 33 deletions
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index cc92e5bfb37..0ed6b868934 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.132.2.1 2009/07/18 19:15:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.132.2.2 2009/08/23 18:26:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -238,6 +238,10 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
{
int j;
+ MemoryContext oldContext;
+
+ /* We want to keep the key values in per-tuple memory */
+ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
for (j = 0; j < numRuntimeKeys; j++)
{
@@ -256,18 +260,32 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
* econtext->ecxt_per_tuple_memory. We assume that the outer tuple
* will stay put throughout our scan. If this is wrong, we could copy
* the result into our context explicitly, but I think that's not
- * necessary...
+ * necessary.
+ *
+ * It's also entirely possible that the result of the eval is a
+ * toasted value. In this case we should forcibly detoast it,
+ * to avoid repeat detoastings each time the value is examined
+ * by an index support function.
*/
- scanvalue = ExecEvalExprSwitchContext(key_expr,
- econtext,
- &isNull,
- NULL);
- scan_key->sk_argument = scanvalue;
+ scanvalue = ExecEvalExpr(key_expr,
+ econtext,
+ &isNull,
+ NULL);
if (isNull)
+ {
+ scan_key->sk_argument = scanvalue;
scan_key->sk_flags |= SK_ISNULL;
+ }
else
+ {
+ if (runtimeKeys[j].key_toastable)
+ scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
+ scan_key->sk_argument = scanvalue;
scan_key->sk_flags &= ~SK_ISNULL;
+ }
}
+
+ MemoryContextSwitchTo(oldContext);
}
/*
@@ -795,6 +813,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
runtime_keys[n_runtime_keys].scan_key = this_scan_key;
runtime_keys[n_runtime_keys].key_expr =
ExecInitExpr(rightop, planstate);
+ runtime_keys[n_runtime_keys].key_toastable =
+ TypeIsToastable(op_righttype);
n_runtime_keys++;
scanvalue = (Datum) 0;
}
@@ -844,6 +864,31 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
varattno = ((Var *) leftop)->varattno;
/*
+ * We have to look up the operator's associated btree support
+ * function
+ */
+ opno = lfirst_oid(opnos_cell);
+ opnos_cell = lnext(opnos_cell);
+
+ if (index->rd_rel->relam != BTREE_AM_OID ||
+ varattno < 1 || varattno > index->rd_index->indnatts)
+ elog(ERROR, "bogus RowCompare index qualification");
+ opfamily = index->rd_opfamily[varattno - 1];
+
+ get_op_opfamily_properties(opno, opfamily,
+ &op_strategy,
+ &op_lefttype,
+ &op_righttype);
+
+ if (op_strategy != rc->rctype)
+ elog(ERROR, "RowCompare index qualification contains wrong operator");
+
+ opfuncid = get_opfamily_proc(opfamily,
+ op_lefttype,
+ op_righttype,
+ BTORDER_PROC);
+
+ /*
* rightop is the constant or variable comparison value
*/
rightop = (Expr *) lfirst(rargs_cell);
@@ -867,36 +912,13 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
runtime_keys[n_runtime_keys].scan_key = this_sub_key;
runtime_keys[n_runtime_keys].key_expr =
ExecInitExpr(rightop, planstate);
+ runtime_keys[n_runtime_keys].key_toastable =
+ TypeIsToastable(op_righttype);
n_runtime_keys++;
scanvalue = (Datum) 0;
}
/*
- * We have to look up the operator's associated btree support
- * function
- */
- opno = lfirst_oid(opnos_cell);
- opnos_cell = lnext(opnos_cell);
-
- if (index->rd_rel->relam != BTREE_AM_OID ||
- varattno < 1 || varattno > index->rd_index->indnatts)
- elog(ERROR, "bogus RowCompare index qualification");
- opfamily = index->rd_opfamily[varattno - 1];
-
- get_op_opfamily_properties(opno, opfamily,
- &op_strategy,
- &op_lefttype,
- &op_righttype);
-
- if (op_strategy != rc->rctype)
- elog(ERROR, "RowCompare index qualification contains wrong operator");
-
- opfuncid = get_opfamily_proc(opfamily,
- op_lefttype,
- op_righttype,
- BTORDER_PROC);
-
- /*
* initialize the subsidiary scan key's fields appropriately
*/
ScanKeyEntryInitialize(this_sub_key,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index b74db12afcb..57be60626fe 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.205 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.205.2.1 2009/08/23 18:26:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1086,6 +1086,7 @@ typedef struct
{
ScanKey scan_key; /* scankey to put value into */
ExprState *key_expr; /* expr to evaluate to get value */
+ bool key_toastable; /* is expr's result a toastable datatype? */
} IndexRuntimeKeyInfo;
typedef struct