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

Commit97be02a

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 parent718af10 commit97be02a

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
@@ -1188,6 +1188,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
11881188
op->args,op->opfuncid,op->inputcollid,
11891189
state);
11901190

1191+
/*
1192+
* If first argument is of varlena type, we'll need to ensure
1193+
* that the value passed to the comparison function is a
1194+
* read-only pointer.
1195+
*/
1196+
scratch.d.func.make_ro=
1197+
(get_typlen(exprType((Node*)linitial(op->args)))==-1);
1198+
11911199
/*
11921200
* Change opcode of call instruction to EEOP_NULLIF.
11931201
*

‎src/backend/executor/execExprInterp.c

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

12991300
/* if either argument is NULL they can't be equal */
13001301
if (!fcinfo->args[0].isnull&& !fcinfo->args[1].isnull)
13011302
{
13021303
Datumresult;
13031304

1305+
/*
1306+
* If first argument is of varlena type, it might be an
1307+
* expanded datum. We need to ensure that the value passed to
1308+
* the comparison function is a read-only pointer. However,
1309+
* if we end by returning the first argument, that will be the
1310+
* original read-write pointer if it was read-write.
1311+
*/
1312+
if (op->d.func.make_ro)
1313+
fcinfo->args[0].value=
1314+
MakeExpandedObjectReadOnlyInternal(save_arg0);
1315+
13041316
fcinfo->isnull= false;
13051317
result=op->d.func.fn_addr(fcinfo);
13061318

@@ -1315,7 +1327,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
13151327
}
13161328

13171329
/* Arguments aren't equal, so return the first one */
1318-
*op->resvalue=fcinfo->args[0].value;
1330+
*op->resvalue=save_arg0;
13191331
*op->resnull=fcinfo->args[0].isnull;
13201332

13211333
EEO_NEXT();

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

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

15631563
v_fcinfo=l_ptr_const(fcinfo,l_ptr(StructFunctionCallInfoData));
15641564

1565+
/* save original arg[0] */
1566+
v_arg0=l_funcvalue(b,v_fcinfo,0);
1567+
15651568
/* if either argument is NULL they can't be equal */
15661569
v_argnull0=l_funcnull(b,v_fcinfo,0);
15671570
v_argnull1=l_funcnull(b,v_fcinfo,1);
@@ -1578,20 +1581,42 @@ llvm_compile_expr(ExprState *state)
15781581

15791582
/* one (or both) of the arguments are null, return arg[0] */
15801583
LLVMPositionBuilderAtEnd(b,b_hasnull);
1581-
v_arg0=l_funcvalue(b,v_fcinfo,0);
15821584
LLVMBuildStore(b,v_argnull0,v_resnullp);
15831585
LLVMBuildStore(b,v_arg0,v_resvaluep);
15841586
LLVMBuildBr(b,opblocks[opno+1]);
15851587

15861588
/* build block to invoke function and check result */
15871589
LLVMPositionBuilderAtEnd(b,b_nonull);
15881590

1591+
/*
1592+
* If first argument is of varlena type, it might be an
1593+
* expanded datum. We need to ensure that the value
1594+
* passed to the comparison function is a read-only
1595+
* pointer. However, if we end by returning the first
1596+
* argument, that will be the original read-write pointer
1597+
* if it was read-write.
1598+
*/
1599+
if (op->d.func.make_ro)
1600+
{
1601+
LLVMValueRefv_params[1];
1602+
LLVMValueRefv_arg0_ro;
1603+
1604+
v_params[0]=v_arg0;
1605+
v_arg0_ro=
1606+
l_call(b,
1607+
llvm_pg_var_func_type("MakeExpandedObjectReadOnlyInternal"),
1608+
llvm_pg_func(mod,"MakeExpandedObjectReadOnlyInternal"),
1609+
v_params,lengthof(v_params),"");
1610+
LLVMBuildStore(b,v_arg0_ro,
1611+
l_funcvaluep(b,v_fcinfo,0));
1612+
}
1613+
15891614
v_retval=BuildV1Call(context,b,mod,fcinfo,&v_fcinfo_isnull);
15901615

15911616
/*
1592-
* If result not null, and arguments are equal return null
1593-
* (same result as if there'd been NULLs, hence reuse
1594-
* b_hasnull).
1617+
* If result not null and arguments are equal return null,
1618+
*else return arg[0](same result as if there'd been
1619+
*NULLs, hence reuseb_hasnull).
15951620
*/
15961621
v_argsequal=LLVMBuildAnd(b,
15971622
LLVMBuildICmp(b,LLVMIntEQ,

‎src/include/executor/execExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ typedef struct ExprEvalStep
356356
/* faster to access without additional indirection: */
357357
PGFunctionfn_addr;/* actual call address */
358358
intnargs;/* number of arguments */
359+
boolmake_ro;/* make arg0 R/O (used only for NULLIF) */
359360
}func;
360361

361362
/* for EEOP_BOOL_*_STEP */

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,14 @@ SELECT CASE make_ad(1,2)
397397
right
398398
(1 row)
399399

400+
-- While we're here, also test handling of a NULLIF arg that is a read/write
401+
-- object (bug #18722)
402+
SELECT NULLIF(make_ad(1,2), array[2,3]::arrdomain);
403+
nullif
404+
--------
405+
{1,2}
406+
(1 row)
407+
400408
ROLLBACK;
401409
-- Test interaction of CASE with ArrayCoerceExpr (bug #15471)
402410
BEGIN;

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

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

245+
-- While we're here, also test handling of a NULLIF arg that is a read/write
246+
-- object (bug #18722)
247+
248+
SELECT NULLIF(make_ad(1,2), array[2,3]::arrdomain);
249+
245250
ROLLBACK;
246251

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp