|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* arrayutils.c
|
|
|
|
* This file contains some support routines required for array functions.
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/adt/arrayutils.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "common/int.h"
|
|
|
|
#include "utils/array.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert subscript list into linear element number (from 0)
|
|
|
|
*
|
|
|
|
* We assume caller has already range-checked the dimensions and subscripts,
|
|
|
|
* so no overflow is possible.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
|
|
|
|
{
|
|
|
|
int i,
|
|
|
|
scale = 1,
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
for (i = n - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
offset += (indx[i] - lb[i]) * scale;
|
|
|
|
scale *= dim[i];
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Same, but subscripts are assumed 0-based, and use a scale array
|
|
|
|
* instead of raw dimension data (see mda_get_prod to create scale array)
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ArrayGetOffset0(int n, const int *tup, const int *scale)
|
|
|
|
{
|
|
|
|
int i,
|
|
|
|
lin = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
lin += tup[i] * scale[i];
|
|
|
|
return lin;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert array dimensions into number of elements
|
|
|
|
*
|
|
|
|
* This must do overflow checking, since it is used to validate that a user
|
|
|
|
* dimensionality request doesn't overflow what we can handle.
|
|
|
|
*
|
|
|
|
* We limit array sizes to at most about a quarter billion elements,
|
|
|
|
* so that it's not necessary to check for overflow in quite so many
|
|
|
|
* places --- for instance when palloc'ing Datum arrays.
|
|
|
|
*
|
|
|
|
* The multiplication overflow check only works on machines that have int64
|
|
|
|
* arithmetic, but that is nearly all platforms these days, and doing check
|
|
|
|
* divides for those that don't seems way too expensive.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ArrayGetNItems(int ndim, const int *dims)
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
{
|
|
|
|
return ArrayGetNItemsSafe(ndim, dims, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This entry point can return the error into an ErrorSaveContext
|
|
|
|
* instead of throwing an exception. -1 is returned after an error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ArrayGetNItemsSafe(int ndim, const int *dims, struct Node *escontext)
|
|
|
|
{
|
|
|
|
int32 ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
#define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
|
|
|
|
|
|
|
|
if (ndim <= 0)
|
|
|
|
return 0;
|
|
|
|
ret = 1;
|
|
|
|
for (i = 0; i < ndim; i++)
|
|
|
|
{
|
|
|
|
int64 prod;
|
|
|
|
|
|
|
|
/* A negative dimension implies that UB-LB overflowed ... */
|
|
|
|
if (dims[i] < 0)
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
ereturn(escontext, -1,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
|
|
|
errmsg("array size exceeds the maximum allowed (%d)",
|
|
|
|
(int) MaxArraySize)));
|
|
|
|
|
|
|
|
prod = (int64) ret * (int64) dims[i];
|
|
|
|
|
|
|
|
ret = (int32) prod;
|
|
|
|
if ((int64) ret != prod)
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
ereturn(escontext, -1,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
|
|
|
errmsg("array size exceeds the maximum allowed (%d)",
|
|
|
|
(int) MaxArraySize)));
|
|
|
|
}
|
|
|
|
Assert(ret >= 0);
|
|
|
|
if ((Size) ret > MaxArraySize)
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
ereturn(escontext, -1,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
|
|
|
errmsg("array size exceeds the maximum allowed (%d)",
|
|
|
|
(int) MaxArraySize)));
|
|
|
|
return (int) ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify sanity of proposed lower-bound values for an array
|
|
|
|
*
|
|
|
|
* The lower-bound values must not be so large as to cause overflow when
|
|
|
|
* calculating subscripts, e.g. lower bound 2147483640 with length 10
|
|
|
|
* must be disallowed. We actually insist that dims[i] + lb[i] be
|
|
|
|
* computable without overflow, meaning that an array with last subscript
|
|
|
|
* equal to INT_MAX will be disallowed.
|
|
|
|
*
|
|
|
|
* It is assumed that the caller already called ArrayGetNItems, so that
|
|
|
|
* overflowed (negative) dims[] values have been eliminated.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ArrayCheckBounds(int ndim, const int *dims, const int *lb)
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
{
|
|
|
|
(void) ArrayCheckBoundsSafe(ndim, dims, lb, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This entry point can return the error into an ErrorSaveContext
|
|
|
|
* instead of throwing an exception.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb,
|
|
|
|
struct Node *escontext)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ndim; i++)
|
|
|
|
{
|
|
|
|
/* PG_USED_FOR_ASSERTS_ONLY prevents variable-isn't-read warnings */
|
|
|
|
int32 sum PG_USED_FOR_ASSERTS_ONLY;
|
|
|
|
|
|
|
|
if (pg_add_s32_overflow(dims[i], lb[i], &sum))
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
ereturn(escontext, false,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
|
|
|
errmsg("array lower bound is too large: %d",
|
|
|
|
lb[i])));
|
|
|
|
}
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute ranges (sub-array dimensions) for an array slice
|
|
|
|
*
|
|
|
|
* We assume caller has validated slice endpoints, so overflow is impossible
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mda_get_range(int n, int *span, const int *st, const int *endp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
span[i] = endp[i] - st[i] + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute products of array dimensions, ie, scale factors for subscripts
|
|
|
|
*
|
|
|
|
* We assume caller has validated dimensions, so overflow is impossible
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mda_get_prod(int n, const int *range, int *prod)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
prod[n - 1] = 1;
|
|
|
|
for (i = n - 2; i >= 0; i--)
|
|
|
|
prod[i] = prod[i + 1] * range[i + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* From products of whole-array dimensions and spans of a sub-array,
|
|
|
|
* compute offset distances needed to step through subarray within array
|
|
|
|
*
|
|
|
|
* We assume caller has validated dimensions, so overflow is impossible
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
|
|
|
|
{
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
|
|
|
|
dist[n - 1] = 0;
|
|
|
|
for (j = n - 2; j >= 0; j--)
|
|
|
|
{
|
|
|
|
dist[j] = prod[j] - 1;
|
|
|
|
for (i = j + 1; i < n; i++)
|
|
|
|
dist[j] -= (span[i] - 1) * prod[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generates the tuple that is lexicographically one greater than the current
|
|
|
|
* n-tuple in "curr", with the restriction that the i-th element of "curr" is
|
|
|
|
* less than the i-th element of "span".
|
|
|
|
*
|
|
|
|
* Returns -1 if no next tuple exists, else the subscript position (0..n-1)
|
|
|
|
* corresponding to the dimension to advance along.
|
|
|
|
*
|
|
|
|
* We assume caller has validated dimensions, so overflow is impossible
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mda_next_tuple(int n, int *curr, const int *span)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (n <= 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
|
|
|
|
for (i = n - 1; i && curr[i] == 0; i--)
|
|
|
|
curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];
|
|
|
|
|
|
|
|
if (i)
|
|
|
|
return i;
|
|
|
|
if (curr[0])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ArrayGetIntegerTypmods: verify that argument is a 1-D cstring array,
|
|
|
|
* and get the contents converted to integers. Returns a palloc'd array
|
|
|
|
* and places the length at *n.
|
|
|
|
*/
|
|
|
|
int32 *
|
|
|
|
ArrayGetIntegerTypmods(ArrayType *arr, int *n)
|
|
|
|
{
|
|
|
|
int32 *result;
|
|
|
|
Datum *elem_values;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (ARR_ELEMTYPE(arr) != CSTRINGOID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
|
|
|
|
errmsg("typmod array must be type cstring[]")));
|
|
|
|
|
|
|
|
if (ARR_NDIM(arr) != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
|
|
|
errmsg("typmod array must be one-dimensional")));
|
|
|
|
|
|
|
|
if (array_contains_nulls(arr))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
|
|
|
errmsg("typmod array must not contain nulls")));
|
|
|
|
|
|
|
|
deconstruct_array_builtin(arr, CSTRINGOID, &elem_values, NULL, n);
|
|
|
|
|
|
|
|
result = (int32 *) palloc(*n * sizeof(int32));
|
|
|
|
|
|
|
|
for (i = 0; i < *n; i++)
|
|
|
|
result[i] = pg_strtoint32(DatumGetCString(elem_values[i]));
|
|
|
|
|
|
|
|
pfree(elem_values);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|