Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit48a6cd1

Browse files
committed
Fix NULLIF()'s handling of read-write expanded objects.
If passed a read-write expanded object pointer, the EEOP_NULLIFcode would hand that same pointer to the equality functionand then (unless equality was reported) also return the samepointer as its value. This is no good, because a function thatreceives a read-write expanded object pointer is fully entitledto scribble on or even delete the object, thus corrupting theNULLIF output. (This problem is likely unobservable with theequality functions provided in core Postgres, but it's easy todemonstrate with one coded in plpgsql.)To fix, make sure the pointer passed to the equality functionis read-only. We can still return the original read-writepointer as the NULLIF result, allowing optimization of lateroperations.Per bug #18722 from Alexander Lakhin. This has been wrongsince we invented expanded objects, so back-patch to allsupported branches.Discussion:https://postgr.es/m/18722-fd9e645448cc78b4@postgresql.org
1 parent01745fb commit48a6cd1

File tree

6 files changed

+64
-5
lines changed

6 files changed

+64
-5
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
964964
op->args,op->opfuncid,op->inputcollid,
965965
state);
966966

967+
/*
968+
* If first argument is of varlena type, we'll need to ensure
969+
* that the value passed to the comparison function is a
970+
* read-only pointer.
971+
*/
972+
scratch.d.func.make_ro=
973+
(get_typlen(exprType((Node*)linitial(op->args)))==-1);
974+
967975
/*
968976
* Change opcode of call instruction to EEOP_NULLIF.
969977
*

‎src/backend/executor/execExprInterp.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1226,12 +1226,24 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
12261226
* The arguments are already evaluated into fcinfo->args.
12271227
*/
12281228
FunctionCallInfofcinfo=op->d.func.fcinfo_data;
1229+
Datumsave_arg0=fcinfo->args[0].value;
12291230

12301231
/* if either argument is NULL they can't be equal */
12311232
if (!fcinfo->args[0].isnull&& !fcinfo->args[1].isnull)
12321233
{
12331234
Datumresult;
12341235

1236+
/*
1237+
* If first argument is of varlena type, it might be an
1238+
* expanded datum. We need to ensure that the value passed to
1239+
* the comparison function is a read-only pointer. However,
1240+
* if we end by returning the first argument, that will be the
1241+
* original read-write pointer if it was read-write.
1242+
*/
1243+
if (op->d.func.make_ro)
1244+
fcinfo->args[0].value=
1245+
MakeExpandedObjectReadOnlyInternal(save_arg0);
1246+
12351247
fcinfo->isnull= false;
12361248
result=op->d.func.fn_addr(fcinfo);
12371249

@@ -1246,7 +1258,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
12461258
}
12471259

12481260
/* Arguments aren't equal, so return the first one */
1249-
*op->resvalue=fcinfo->args[0].value;
1261+
*op->resvalue=save_arg0;
12501262
*op->resnull=fcinfo->args[0].isnull;
12511263

12521264
EEO_NEXT();

‎src/backend/jit/llvm/llvmjit_expr.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,9 @@ llvm_compile_expr(ExprState *state)
15191519

15201520
v_fcinfo=l_ptr_const(fcinfo,l_ptr(StructFunctionCallInfoData));
15211521

1522+
/* save original arg[0] */
1523+
v_arg0=l_funcvalue(b,v_fcinfo,0);
1524+
15221525
/* if either argument is NULL they can't be equal */
15231526
v_argnull0=l_funcnull(b,v_fcinfo,0);
15241527
v_argnull1=l_funcnull(b,v_fcinfo,1);
@@ -1535,20 +1538,42 @@ llvm_compile_expr(ExprState *state)
15351538

15361539
/* one (or both) of the arguments are null, return arg[0] */
15371540
LLVMPositionBuilderAtEnd(b,b_hasnull);
1538-
v_arg0=l_funcvalue(b,v_fcinfo,0);
15391541
LLVMBuildStore(b,v_argnull0,v_resnullp);
15401542
LLVMBuildStore(b,v_arg0,v_resvaluep);
15411543
LLVMBuildBr(b,opblocks[opno+1]);
15421544

15431545
/* build block to invoke function and check result */
15441546
LLVMPositionBuilderAtEnd(b,b_nonull);
15451547

1548+
/*
1549+
* If first argument is of varlena type, it might be an
1550+
* expanded datum. We need to ensure that the value
1551+
* passed to the comparison function is a read-only
1552+
* pointer. However, if we end by returning the first
1553+
* argument, that will be the original read-write pointer
1554+
* if it was read-write.
1555+
*/
1556+
if (op->d.func.make_ro)
1557+
{
1558+
LLVMValueRefv_params[1];
1559+
LLVMValueRefv_arg0_ro;
1560+
1561+
v_params[0]=v_arg0;
1562+
v_arg0_ro=
1563+
l_call(b,
1564+
llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
1565+
llvm_pg_func(mod,"MakeExpandedObjectReadOnlyInternal"),
1566+
v_params,lengthof(v_params),"");
1567+
LLVMBuildStore(b,v_arg0_ro,
1568+
l_funcvaluep(b,v_fcinfo,0));
1569+
}
1570+
15461571
v_retval=BuildV1Call(context,b,mod,fcinfo,&v_fcinfo_isnull);
15471572

15481573
/*
1549-
* If result not null, and arguments are equal return null
1550-
* (same result as if there'd been NULLs, hence reuse
1551-
* b_hasnull).
1574+
* If result not null and arguments are equal return null,
1575+
*else return arg[0](same result as if there'd been
1576+
*NULLs, hence reuseb_hasnull).
15521577
*/
15531578
v_argsequal=LLVMBuildAnd(b,
15541579
LLVMBuildICmp(b,LLVMIntEQ,

‎src/include/executor/execExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ typedef struct ExprEvalStep
339339
/* faster to access without additional indirection: */
340340
PGFunctionfn_addr;/* actual call address */
341341
intnargs;/* number of arguments */
342+
boolmake_ro;/* make arg0 R/O (used only for NULLIF) */
342343
}func;
343344

344345
/* for EEOP_BOOL_*_STEP */

‎src/test/regress/expected/case.out

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,14 @@ SELECT CASE make_ad(1,2)
372372
right
373373
(1 row)
374374

375+
-- While we're here, also test handling of a NULLIF arg that is a read/write
376+
-- object (bug #18722)
377+
SELECT NULLIF(make_ad(1,2), array[2,3]::arrdomain);
378+
nullif
379+
--------
380+
{1,2}
381+
(1 row)
382+
375383
ROLLBACK;
376384
-- Test interaction of CASE with ArrayCoerceExpr (bug #15471)
377385
BEGIN;

‎src/test/regress/sql/case.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ SELECT CASE make_ad(1,2)
231231
WHEN array[1,2]::arrdomain THEN'right'
232232
END;
233233

234+
-- While we're here, also test handling of a NULLIF arg that is a read/write
235+
-- object (bug #18722)
236+
237+
SELECT NULLIF(make_ad(1,2), array[2,3]::arrdomain);
238+
234239
ROLLBACK;
235240

236241
-- Test interaction of CASE with ArrayCoerceExpr (bug #15471)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp