aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/arrayfuncs.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-04-21 14:23:42 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-04-21 14:23:53 -0400
commit5836d326552cd0bada1b63281892a8515f07af0f (patch)
tree1a01905082b5a6c827f53acb8f2f8c78886dcd85 /src/backend/utils/adt/arrayfuncs.c
parentafccd76f1ccef73a341e9b0c6efb29a429f35aa4 (diff)
downloadpostgresql-5836d326552cd0bada1b63281892a8515f07af0f.tar.gz
postgresql-5836d326552cd0bada1b63281892a8515f07af0f.zip
Fix minor violations of FunctionCallInvoke usage protocol.
Working on commit 1c455078b led me to check through FunctionCallInvoke call sites to see if every one was being honest about (a) making sure that fcinfo.isnull is initially false, and (b) checking its state after the call. Sure enough, I found some violations. The main one is that finalize_partialaggregate re-used serialfn_fcinfo without resetting isnull, even though it clearly intends to cater for serialfns that return NULL. There would only be an issue with a non-strict serialfn, since it's unlikely that a serialfn would return NULL for non-null input. We have no non-strict serialfns in core, and there may be none in the wild either, which would account for the lack of complaints. Still, it's clearly wrong, so back-patch that fix to 9.6 where finalize_partialaggregate was introduced. Also, arrayfuncs.c and rowtypes.c contained various callers that were not bothering to check for result nulls. While what's being called is a comparison or hash function that probably *shouldn't* return null, that's a lousy excuse for not having any check at all. There are existing places that just Assert(!fcinfo->isnull) in comparable situations, so I added that to the places that were calling btree comparison or hash support functions. In the places calling boolean-returning equality functions, it's quite cheap to have them treat isnull as FALSE, so make those places do that. Also remove some "locfcinfo->isnull = false" assignments that are unnecessary given the assumption that no previous call returned null. These changes seem like mostly neatnik-ism or debugging support, so I didn't back-patch.
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 11987c8f3ba..800107d4e72 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -3668,7 +3668,7 @@ array_eq(PG_FUNCTION_ARGS)
}
/*
- * Apply the operator to the element pair
+ * Apply the operator to the element pair; treat NULL as false
*/
locfcinfo->args[0].value = elt1;
locfcinfo->args[0].isnull = false;
@@ -3676,7 +3676,7 @@ array_eq(PG_FUNCTION_ARGS)
locfcinfo->args[1].isnull = false;
locfcinfo->isnull = false;
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
- if (!oprresult)
+ if (locfcinfo->isnull || !oprresult)
{
result = false;
break;
@@ -3841,9 +3841,11 @@ array_cmp(FunctionCallInfo fcinfo)
locfcinfo->args[0].isnull = false;
locfcinfo->args[1].value = elt2;
locfcinfo->args[1].isnull = false;
- locfcinfo->isnull = false;
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
+ /* We don't expect comparison support functions to return null */
+ Assert(!locfcinfo->isnull);
+
if (cmpresult == 0)
continue; /* equal */
@@ -3983,8 +3985,9 @@ hash_array(PG_FUNCTION_ARGS)
/* Apply the hash function */
locfcinfo->args[0].value = elt;
locfcinfo->args[0].isnull = false;
- locfcinfo->isnull = false;
elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
+ /* We don't expect hash functions to return null */
+ Assert(!locfcinfo->isnull);
}
/*
@@ -4074,6 +4077,8 @@ hash_array_extended(PG_FUNCTION_ARGS)
locfcinfo->args[1].value = Int64GetDatum(seed);
locfcinfo->args[1].isnull = false;
elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
+ /* We don't expect hash functions to return null */
+ Assert(!locfcinfo->isnull);
}
result = (result << 5) - result + elthash;
@@ -4207,7 +4212,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
continue; /* can't match */
/*
- * Apply the operator to the element pair
+ * Apply the operator to the element pair; treat NULL as false
*/
locfcinfo->args[0].value = elt1;
locfcinfo->args[0].isnull = false;
@@ -4215,7 +4220,7 @@ array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
locfcinfo->args[1].isnull = false;
locfcinfo->isnull = false;
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
- if (oprresult)
+ if (!locfcinfo->isnull && oprresult)
break;
}
@@ -6202,7 +6207,7 @@ array_replace_internal(ArrayType *array,
else
{
/*
- * Apply the operator to the element pair
+ * Apply the operator to the element pair; treat NULL as false
*/
locfcinfo->args[0].value = elt;
locfcinfo->args[0].isnull = false;
@@ -6210,7 +6215,7 @@ array_replace_internal(ArrayType *array,
locfcinfo->args[1].isnull = false;
locfcinfo->isnull = false;
oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
- if (!oprresult)
+ if (locfcinfo->isnull || !oprresult)
{
/* no match, keep element */
values[nresult] = elt;
@@ -6517,10 +6522,12 @@ width_bucket_array_fixed(Datum operand,
locfcinfo->args[0].isnull = false;
locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
locfcinfo->args[1].isnull = false;
- locfcinfo->isnull = false;
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
+ /* We don't expect comparison support functions to return null */
+ Assert(!locfcinfo->isnull);
+
if (cmpresult < 0)
right = mid;
else
@@ -6577,6 +6584,9 @@ width_bucket_array_variable(Datum operand,
cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
+ /* We don't expect comparison support functions to return null */
+ Assert(!locfcinfo->isnull);
+
if (cmpresult < 0)
right = mid;
else