-
Bruce Momjian authored
comment line where output as too long, and update typedefs for /lib directory. Also fix case where identifiers were used as variable names in the backend, but as typedefs in ecpg (favor the backend for indenting). Backpatch to 8.1.X.
Bruce Momjian authoredcomment line where output as too long, and update typedefs for /lib directory. Also fix case where identifiers were used as variable names in the backend, but as typedefs in ecpg (favor the backend for indenting). Backpatch to 8.1.X.
arrayutils.c 4.53 KiB
/*-------------------------------------------------------------------------
*
* arrayutils.c
* This file contains some support routines required for array functions.
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayutils.c,v 1.20 2005/11/22 18:17:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/array.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)
{
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)
ereport(ERROR,
(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)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxArraySize)));
}
Assert(ret >= 0);
if ((Size) ret > MaxArraySize)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxArraySize)));
return (int) ret;
}
/*
* 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;
}