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

Commit5b8728c

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 parent4ba84de commit5b8728c

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
@@ -1191,6 +1191,14 @@ ExecInitExprRec(Expr *node, ExprState *state,
11911191
op->args,op->opfuncid,op->inputcollid,
11921192
state);
11931193

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

‎src/backend/executor/execExprInterp.c

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

13121313
/* if either argument is NULL they can't be equal */
13131314
if (!fcinfo->args[0].isnull&& !fcinfo->args[1].isnull)
13141315
{
13151316
Datumresult;
13161317

1318+
/*
1319+
* If first argument is of varlena type, it might be an
1320+
* expanded datum. We need to ensure that the value passed to
1321+
* the comparison function is a read-only pointer. However,
1322+
* if we end by returning the first argument, that will be the
1323+
* original read-write pointer if it was read-write.
1324+
*/
1325+
if (op->d.func.make_ro)
1326+
fcinfo->args[0].value=
1327+
MakeExpandedObjectReadOnlyInternal(save_arg0);
1328+
13171329
fcinfo->isnull= false;
13181330
result=op->d.func.fn_addr(fcinfo);
13191331

@@ -1328,7 +1340,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
13281340
}
13291341

13301342
/* Arguments aren't equal, so return the first one */
1331-
*op->resvalue=fcinfo->args[0].value;
1343+
*op->resvalue=save_arg0;
13321344
*op->resnull=fcinfo->args[0].isnull;
13331345

13341346
EEO_NEXT();

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

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

15601560
v_fcinfo=l_ptr_const(fcinfo,l_ptr(StructFunctionCallInfoData));
15611561

1562+
/* save original arg[0] */
1563+
v_arg0=l_funcvalue(b,v_fcinfo,0);
1564+
15621565
/* if either argument is NULL they can't be equal */
15631566
v_argnull0=l_funcnull(b,v_fcinfo,0);
15641567
v_argnull1=l_funcnull(b,v_fcinfo,1);
@@ -1575,20 +1578,42 @@ llvm_compile_expr(ExprState *state)
15751578

15761579
/* one (or both) of the arguments are null, return arg[0] */
15771580
LLVMPositionBuilderAtEnd(b,b_hasnull);
1578-
v_arg0=l_funcvalue(b,v_fcinfo,0);
15791581
LLVMBuildStore(b,v_argnull0,v_resnullp);
15801582
LLVMBuildStore(b,v_arg0,v_resvaluep);
15811583
LLVMBuildBr(b,opblocks[opno+1]);
15821584

15831585
/* build block to invoke function and check result */
15841586
LLVMPositionBuilderAtEnd(b,b_nonull);
15851587

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

15881613
/*
1589-
* If result not null, and arguments are equal return null
1590-
* (same result as if there'd been NULLs, hence reuse
1591-
* b_hasnull).
1614+
* If result not null and arguments are equal return null,
1615+
*else return arg[0](same result as if there'd been
1616+
*NULLs, hence reuseb_hasnull).
15921617
*/
15931618
v_argsequal=LLVMBuildAnd(b,
15941619
LLVMBuildICmp(b,LLVMIntEQ,

‎src/include/executor/execExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ typedef struct ExprEvalStep
365365
/* faster to access without additional indirection: */
366366
PGFunctionfn_addr;/* actual call address */
367367
intnargs;/* number of arguments */
368+
boolmake_ro;/* make arg0 R/O (used only for NULLIF) */
368369
}func;
369370

370371
/* 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