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.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index e33231f7be8..23c0fb9379b 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -3696,3 +3696,137 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
return state;
}
+
+/*
+ * Build equality expression that can be evaluated using ExecQual(), returning
+ * true if the expression context's inner/outer tuples are equal. Datums in
+ * the inner/outer slots are assumed to be in the same order and quantity as
+ * the 'eqfunctions' parameter. NULLs are treated as equal.
+ *
+ * desc: tuple descriptor of the to-be-compared tuples
+ * lops: the slot ops for the inner tuple slots
+ * rops: the slot ops for the outer tuple slots
+ * eqFunctions: array of function oids of the equality functions to use
+ * this must be the same length as the 'param_exprs' list.
+ * collations: collation Oids to use for equality comparison. Must be the
+ * same length as the 'param_exprs' list.
+ * parent: parent executor node
+ */
+ExprState *
+ExecBuildParamSetEqual(TupleDesc desc,
+ const TupleTableSlotOps *lops,
+ const TupleTableSlotOps *rops,
+ const Oid *eqfunctions,
+ const Oid *collations,
+ const List *param_exprs,
+ PlanState *parent)
+{
+ ExprState *state = makeNode(ExprState);
+ ExprEvalStep scratch = {0};
+ int maxatt = list_length(param_exprs);
+ List *adjust_jumps = NIL;
+ ListCell *lc;
+
+ state->expr = NULL;
+ state->flags = EEO_FLAG_IS_QUAL;
+ state->parent = parent;
+
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+
+ /* push deform steps */
+ scratch.opcode = EEOP_INNER_FETCHSOME;
+ scratch.d.fetch.last_var = maxatt;
+ scratch.d.fetch.fixed = false;
+ scratch.d.fetch.known_desc = desc;
+ scratch.d.fetch.kind = lops;
+ if (ExecComputeSlotInfo(state, &scratch))
+ ExprEvalPushStep(state, &scratch);
+
+ scratch.opcode = EEOP_OUTER_FETCHSOME;
+ scratch.d.fetch.last_var = maxatt;
+ scratch.d.fetch.fixed = false;
+ scratch.d.fetch.known_desc = desc;
+ scratch.d.fetch.kind = rops;
+ if (ExecComputeSlotInfo(state, &scratch))
+ ExprEvalPushStep(state, &scratch);
+
+ for (int attno = 0; attno < maxatt; attno++)
+ {
+ Form_pg_attribute att = TupleDescAttr(desc, attno);
+ Oid foid = eqfunctions[attno];
+ Oid collid = collations[attno];
+ FmgrInfo *finfo;
+ FunctionCallInfo fcinfo;
+ AclResult aclresult;
+
+ /* Check permission to call function */
+ aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
+
+ InvokeFunctionExecuteHook(foid);
+
+ /* Set up the primary fmgr lookup information */
+ finfo = palloc0(sizeof(FmgrInfo));
+ fcinfo = palloc0(SizeForFunctionCallInfo(2));
+ fmgr_info(foid, finfo);
+ fmgr_info_set_expr(NULL, finfo);
+ InitFunctionCallInfoData(*fcinfo, finfo, 2,
+ collid, NULL, NULL);
+
+ /* left arg */
+ scratch.opcode = EEOP_INNER_VAR;
+ scratch.d.var.attnum = attno;
+ scratch.d.var.vartype = att->atttypid;
+ scratch.resvalue = &fcinfo->args[0].value;
+ scratch.resnull = &fcinfo->args[0].isnull;
+ ExprEvalPushStep(state, &scratch);
+
+ /* right arg */
+ scratch.opcode = EEOP_OUTER_VAR;
+ scratch.d.var.attnum = attno;
+ scratch.d.var.vartype = att->atttypid;
+ scratch.resvalue = &fcinfo->args[1].value;
+ scratch.resnull = &fcinfo->args[1].isnull;
+ ExprEvalPushStep(state, &scratch);
+
+ /* evaluate distinctness */
+ scratch.opcode = EEOP_NOT_DISTINCT;
+ scratch.d.func.finfo = finfo;
+ scratch.d.func.fcinfo_data = fcinfo;
+ scratch.d.func.fn_addr = finfo->fn_addr;
+ scratch.d.func.nargs = 2;
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+ ExprEvalPushStep(state, &scratch);
+
+ /* then emit EEOP_QUAL to detect if result is false (or null) */
+ scratch.opcode = EEOP_QUAL;
+ scratch.d.qualexpr.jumpdone = -1;
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+ ExprEvalPushStep(state, &scratch);
+ adjust_jumps = lappend_int(adjust_jumps,
+ state->steps_len - 1);
+ }
+
+ /* adjust jump targets */
+ foreach(lc, adjust_jumps)
+ {
+ ExprEvalStep *as = &state->steps[lfirst_int(lc)];
+
+ Assert(as->opcode == EEOP_QUAL);
+ Assert(as->d.qualexpr.jumpdone == -1);
+ as->d.qualexpr.jumpdone = state->steps_len;
+ }
+
+ scratch.resvalue = NULL;
+ scratch.resnull = NULL;
+ scratch.opcode = EEOP_DONE;
+ ExprEvalPushStep(state, &scratch);
+
+ ExecReadyExpr(state);
+
+ return state;
+}