aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execExpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r--src/backend/executor/execExpr.c99
1 files changed, 81 insertions, 18 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 23c0fb9379b..74fcfbea566 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1149,6 +1149,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
FmgrInfo *finfo;
FunctionCallInfo fcinfo;
AclResult aclresult;
+ FmgrInfo *hash_finfo;
+ FunctionCallInfo hash_fcinfo;
Assert(list_length(opexpr->args) == 2);
scalararg = (Expr *) linitial(opexpr->args);
@@ -1163,6 +1165,17 @@ ExecInitExprRec(Expr *node, ExprState *state,
get_func_name(opexpr->opfuncid));
InvokeFunctionExecuteHook(opexpr->opfuncid);
+ if (OidIsValid(opexpr->hashfuncid))
+ {
+ aclresult = pg_proc_aclcheck(opexpr->hashfuncid,
+ GetUserId(),
+ ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_FUNCTION,
+ get_func_name(opexpr->hashfuncid));
+ InvokeFunctionExecuteHook(opexpr->hashfuncid);
+ }
+
/* Set up the primary fmgr lookup information */
finfo = palloc0(sizeof(FmgrInfo));
fcinfo = palloc0(SizeForFunctionCallInfo(2));
@@ -1171,26 +1184,76 @@ ExecInitExprRec(Expr *node, ExprState *state,
InitFunctionCallInfoData(*fcinfo, finfo, 2,
opexpr->inputcollid, NULL, NULL);
- /* Evaluate scalar directly into left function argument */
- ExecInitExprRec(scalararg, state,
- &fcinfo->args[0].value, &fcinfo->args[0].isnull);
-
/*
- * Evaluate array argument into our return value. There's no
- * danger in that, because the return value is guaranteed to
- * be overwritten by EEOP_SCALARARRAYOP, and will not be
- * passed to any other expression.
+ * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
+ * step instead of a EEOP_SCALARARRAYOP. This provides much
+ * faster lookup performance than the normal linear search
+ * when the number of items in the array is anything but very
+ * small.
*/
- ExecInitExprRec(arrayarg, state, resv, resnull);
-
- /* And perform the operation */
- scratch.opcode = EEOP_SCALARARRAYOP;
- scratch.d.scalararrayop.element_type = InvalidOid;
- scratch.d.scalararrayop.useOr = opexpr->useOr;
- scratch.d.scalararrayop.finfo = finfo;
- scratch.d.scalararrayop.fcinfo_data = fcinfo;
- scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
- ExprEvalPushStep(state, &scratch);
+ if (OidIsValid(opexpr->hashfuncid))
+ {
+ hash_finfo = palloc0(sizeof(FmgrInfo));
+ hash_fcinfo = palloc0(SizeForFunctionCallInfo(1));
+ fmgr_info(opexpr->hashfuncid, hash_finfo);
+ fmgr_info_set_expr((Node *) node, hash_finfo);
+ InitFunctionCallInfoData(*hash_fcinfo, hash_finfo,
+ 1, opexpr->inputcollid, NULL,
+ NULL);
+
+ scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
+ scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
+ scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
+
+ /* Evaluate scalar directly into left function argument */
+ ExecInitExprRec(scalararg, state,
+ &fcinfo->args[0].value, &fcinfo->args[0].isnull);
+
+ /*
+ * Evaluate array argument into our return value. There's
+ * no danger in that, because the return value is
+ * guaranteed to be overwritten by
+ * EEOP_HASHED_SCALARARRAYOP, and will not be passed to
+ * any other expression.
+ */
+ ExecInitExprRec(arrayarg, state, resv, resnull);
+
+ /* And perform the operation */
+ scratch.opcode = EEOP_HASHED_SCALARARRAYOP;
+ scratch.d.hashedscalararrayop.finfo = finfo;
+ scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
+ scratch.d.hashedscalararrayop.fn_addr = finfo->fn_addr;
+
+ scratch.d.hashedscalararrayop.hash_finfo = hash_finfo;
+ scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo;
+ scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr;
+
+ ExprEvalPushStep(state, &scratch);
+ }
+ else
+ {
+ /* Evaluate scalar directly into left function argument */
+ ExecInitExprRec(scalararg, state,
+ &fcinfo->args[0].value,
+ &fcinfo->args[0].isnull);
+
+ /*
+ * Evaluate array argument into our return value. There's
+ * no danger in that, because the return value is
+ * guaranteed to be overwritten by EEOP_SCALARARRAYOP, and
+ * will not be passed to any other expression.
+ */
+ ExecInitExprRec(arrayarg, state, resv, resnull);
+
+ /* And perform the operation */
+ scratch.opcode = EEOP_SCALARARRAYOP;
+ scratch.d.scalararrayop.element_type = InvalidOid;
+ scratch.d.scalararrayop.useOr = opexpr->useOr;
+ scratch.d.scalararrayop.finfo = finfo;
+ scratch.d.scalararrayop.fcinfo_data = fcinfo;
+ scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
+ ExprEvalPushStep(state, &scratch);
+ }
break;
}