1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-30 21:42:05 +03:00

Change array_offset to return subscripts, not offsets

... and rename it and its sibling array_offsets to array_position and
array_positions, to account for the changed behavior.

Having the functions return subscripts better matches existing practice,
and is better suited to using the result value as a subscript into the
array directly.  For one-based arrays, the new definition is identical
to what was originally committed.

(We use the term "subscript" in the documentation, which is what we use
whenever we talk about arrays; but the functions themselves are named
using the word "position" to match the standard-defined POSITION()
functions.)

Author: Pavel Stěhule
Behavioral problem noted by Dean Rasheed.
This commit is contained in:
Alvaro Herrera
2015-03-30 16:13:21 -03:00
parent 0853630159
commit 97690ea6e8
8 changed files with 136 additions and 117 deletions

View File

@ -19,7 +19,7 @@
#include "utils/typcache.h"
static Datum array_offset_common(FunctionCallInfo fcinfo);
static Datum array_position_common(FunctionCallInfo fcinfo);
/*
@ -659,7 +659,7 @@ array_agg_array_finalfn(PG_FUNCTION_ARGS)
}
/*-----------------------------------------------------------------------------
* array_offset, array_offset_start :
* array_position, array_position_start :
* return the offset of a value in an array.
*
* IS NOT DISTINCT FROM semantics are used for comparisons. Return NULL when
@ -667,26 +667,26 @@ array_agg_array_finalfn(PG_FUNCTION_ARGS)
*-----------------------------------------------------------------------------
*/
Datum
array_offset(PG_FUNCTION_ARGS)
array_position(PG_FUNCTION_ARGS)
{
return array_offset_common(fcinfo);
return array_position_common(fcinfo);
}
Datum
array_offset_start(PG_FUNCTION_ARGS)
array_position_start(PG_FUNCTION_ARGS)
{
return array_offset_common(fcinfo);
return array_position_common(fcinfo);
}
/*
* array_offset_common
* Common code for array_offset and array_offset_start
* array_position_common
* Common code for array_position and array_position_start
*
* These are separate wrappers for the sake of opr_sanity regression test.
* They are not strict so we have to test for null inputs explicitly.
*/
static Datum
array_offset_common(FunctionCallInfo fcinfo)
array_position_common(FunctionCallInfo fcinfo)
{
ArrayType *array;
Oid collation = PG_GET_COLLATION();
@ -694,8 +694,8 @@ array_offset_common(FunctionCallInfo fcinfo)
Datum searched_element,
value;
bool isnull;
int offset = 0,
offset_min;
int position,
position_min;
bool found = false;
TypeCacheEntry *typentry;
ArrayMetaState *my_extra;
@ -731,18 +731,20 @@ array_offset_common(FunctionCallInfo fcinfo)
null_search = false;
}
position = (ARR_LBOUND(array))[0] - 1;
/* figure out where to start */
if (PG_NARGS() == 3)
{
if (PG_ARGISNULL(2))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("initial offset should not be NULL")));
errmsg("initial position should not be NULL")));
offset_min = PG_GETARG_INT32(2);
position_min = PG_GETARG_INT32(2);
}
else
offset_min = 1;
position_min = (ARR_LBOUND(array))[0];
/*
* We arrange to look up type info for array_create_iterator only once per
@ -780,10 +782,10 @@ array_offset_common(FunctionCallInfo fcinfo)
array_iterator = array_create_iterator(array, 0, my_extra);
while (array_iterate(array_iterator, &value, &isnull))
{
offset += 1;
position++;
/* skip initial elements if caller requested so */
if (offset < offset_min)
if (position < position_min)
continue;
/*
@ -818,12 +820,12 @@ array_offset_common(FunctionCallInfo fcinfo)
if (!found)
PG_RETURN_NULL();
PG_RETURN_INT32(offset);
PG_RETURN_INT32(position);
}
/*-----------------------------------------------------------------------------
* array_offsets :
* return an array of offsets of a value in an array.
* array_positions :
* return an array of positions of a value in an array.
*
* IS NOT DISTINCT FROM semantics are used for comparisons. Returns NULL when
* the input array is NULL. When the value is not found in the array, returns
@ -833,7 +835,7 @@ array_offset_common(FunctionCallInfo fcinfo)
*-----------------------------------------------------------------------------
*/
Datum
array_offsets(PG_FUNCTION_ARGS)
array_positions(PG_FUNCTION_ARGS)
{
ArrayType *array;
Oid collation = PG_GET_COLLATION();
@ -841,7 +843,7 @@ array_offsets(PG_FUNCTION_ARGS)
Datum searched_element,
value;
bool isnull;
int offset = 0;
int position;
TypeCacheEntry *typentry;
ArrayMetaState *my_extra;
bool null_search;
@ -854,6 +856,8 @@ array_offsets(PG_FUNCTION_ARGS)
array = PG_GETARG_ARRAYTYPE_P(0);
element_type = ARR_ELEMTYPE(array);
position = (ARR_LBOUND(array))[0] - 1;
/*
* We refuse to search for elements in multi-dimensional arrays, since we
* have no good way to report the element's location in the array.
@ -912,12 +916,12 @@ array_offsets(PG_FUNCTION_ARGS)
}
/*
* Accumulate each array offset iff the element matches the given element.
* Accumulate each array position iff the element matches the given element.
*/
array_iterator = array_create_iterator(array, 0, my_extra);
while (array_iterate(array_iterator, &value, &isnull))
{
offset += 1;
position += 1;
/*
* Can't look at the array element's value if it's null; but if we
@ -927,7 +931,7 @@ array_offsets(PG_FUNCTION_ARGS)
{
if (isnull && null_search)
astate =
accumArrayResult(astate, Int32GetDatum(offset), false,
accumArrayResult(astate, Int32GetDatum(position), false,
INT4OID, CurrentMemoryContext);
continue;
@ -937,7 +941,7 @@ array_offsets(PG_FUNCTION_ARGS)
if (DatumGetBool(FunctionCall2Coll(&my_extra->proc, collation,
searched_element, value)))
astate =
accumArrayResult(astate, Int32GetDatum(offset), false,
accumArrayResult(astate, Int32GetDatum(position), false,
INT4OID, CurrentMemoryContext);
}