aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/executor/execExpr.c8
-rw-r--r--src/backend/executor/execExprInterp.c14
-rw-r--r--src/backend/jit/llvm/llvmjit_expr.c33
3 files changed, 50 insertions, 5 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 60f9eb28cd4..ca0d38b3095 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1171,6 +1171,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
state);
/*
+ * If first argument is of varlena type, we'll need to ensure
+ * that the value passed to the comparison function is a
+ * read-only pointer.
+ */
+ scratch.d.func.make_ro =
+ (get_typlen(exprType((Node *) linitial(op->args))) == -1);
+
+ /*
* Change opcode of call instruction to EEOP_NULLIF.
*
* XXX: historically we've not called the function usage
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6b7997465d0..30ea9627c75 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1280,12 +1280,24 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
* The arguments are already evaluated into fcinfo->args.
*/
FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
+ Datum save_arg0 = fcinfo->args[0].value;
/* if either argument is NULL they can't be equal */
if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
{
Datum result;
+ /*
+ * If first argument is of varlena type, it might be an
+ * expanded datum. We need to ensure that the value passed to
+ * the comparison function is a read-only pointer. However,
+ * if we end by returning the first argument, that will be the
+ * original read-write pointer if it was read-write.
+ */
+ if (op->d.func.make_ro)
+ fcinfo->args[0].value =
+ MakeExpandedObjectReadOnlyInternal(save_arg0);
+
fcinfo->isnull = false;
result = op->d.func.fn_addr(fcinfo);
@@ -1300,7 +1312,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
}
/* Arguments aren't equal, so return the first one */
- *op->resvalue = fcinfo->args[0].value;
+ *op->resvalue = save_arg0;
*op->resnull = fcinfo->args[0].isnull;
EEO_NEXT();
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index e2b566b9d53..600262fd99d 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1550,6 +1550,9 @@ llvm_compile_expr(ExprState *state)
v_fcinfo = l_ptr_const(fcinfo, l_ptr(StructFunctionCallInfoData));
+ /* save original arg[0] */
+ v_arg0 = l_funcvalue(b, v_fcinfo, 0);
+
/* if either argument is NULL they can't be equal */
v_argnull0 = l_funcnull(b, v_fcinfo, 0);
v_argnull1 = l_funcnull(b, v_fcinfo, 1);
@@ -1566,7 +1569,6 @@ llvm_compile_expr(ExprState *state)
/* one (or both) of the arguments are null, return arg[0] */
LLVMPositionBuilderAtEnd(b, b_hasnull);
- v_arg0 = l_funcvalue(b, v_fcinfo, 0);
LLVMBuildStore(b, v_argnull0, v_resnullp);
LLVMBuildStore(b, v_arg0, v_resvaluep);
LLVMBuildBr(b, opblocks[opno + 1]);
@@ -1574,12 +1576,35 @@ llvm_compile_expr(ExprState *state)
/* build block to invoke function and check result */
LLVMPositionBuilderAtEnd(b, b_nonull);
+ /*
+ * If first argument is of varlena type, it might be an
+ * expanded datum. We need to ensure that the value
+ * passed to the comparison function is a read-only
+ * pointer. However, if we end by returning the first
+ * argument, that will be the original read-write pointer
+ * if it was read-write.
+ */
+ if (op->d.func.make_ro)
+ {
+ LLVMValueRef v_params[1];
+ LLVMValueRef v_arg0_ro;
+
+ v_params[0] = v_arg0;
+ v_arg0_ro =
+ l_call(b,
+ llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
+ llvm_pg_func(mod, "MakeExpandedObjectReadOnlyInternal"),
+ v_params, lengthof(v_params), "");
+ LLVMBuildStore(b, v_arg0_ro,
+ l_funcvaluep(b, v_fcinfo, 0));
+ }
+
v_retval = BuildV1Call(context, b, mod, fcinfo, &v_fcinfo_isnull);
/*
- * If result not null, and arguments are equal return null
- * (same result as if there'd been NULLs, hence reuse
- * b_hasnull).
+ * If result not null and arguments are equal return null,
+ * else return arg[0] (same result as if there'd been
+ * NULLs, hence reuse b_hasnull).
*/
v_argsequal = LLVMBuildAnd(b,
LLVMBuildICmp(b, LLVMIntEQ,