Header And Logo

PostgreSQL
| The world's most advanced open source database.

arrayutils.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * arrayutils.c
00004  *    This file contains some support routines required for array functions.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/arrayutils.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "postgres.h"
00017 
00018 #include "catalog/pg_type.h"
00019 #include "utils/array.h"
00020 #include "utils/builtins.h"
00021 #include "utils/memutils.h"
00022 
00023 
00024 /*
00025  * Convert subscript list into linear element number (from 0)
00026  *
00027  * We assume caller has already range-checked the dimensions and subscripts,
00028  * so no overflow is possible.
00029  */
00030 int
00031 ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
00032 {
00033     int         i,
00034                 scale = 1,
00035                 offset = 0;
00036 
00037     for (i = n - 1; i >= 0; i--)
00038     {
00039         offset += (indx[i] - lb[i]) * scale;
00040         scale *= dim[i];
00041     }
00042     return offset;
00043 }
00044 
00045 /*
00046  * Same, but subscripts are assumed 0-based, and use a scale array
00047  * instead of raw dimension data (see mda_get_prod to create scale array)
00048  */
00049 int
00050 ArrayGetOffset0(int n, const int *tup, const int *scale)
00051 {
00052     int         i,
00053                 lin = 0;
00054 
00055     for (i = 0; i < n; i++)
00056         lin += tup[i] * scale[i];
00057     return lin;
00058 }
00059 
00060 /*
00061  * Convert array dimensions into number of elements
00062  *
00063  * This must do overflow checking, since it is used to validate that a user
00064  * dimensionality request doesn't overflow what we can handle.
00065  *
00066  * We limit array sizes to at most about a quarter billion elements,
00067  * so that it's not necessary to check for overflow in quite so many
00068  * places --- for instance when palloc'ing Datum arrays.
00069  *
00070  * The multiplication overflow check only works on machines that have int64
00071  * arithmetic, but that is nearly all platforms these days, and doing check
00072  * divides for those that don't seems way too expensive.
00073  */
00074 int
00075 ArrayGetNItems(int ndim, const int *dims)
00076 {
00077     int32       ret;
00078     int         i;
00079 
00080 #define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
00081 
00082     if (ndim <= 0)
00083         return 0;
00084     ret = 1;
00085     for (i = 0; i < ndim; i++)
00086     {
00087         int64       prod;
00088 
00089         /* A negative dimension implies that UB-LB overflowed ... */
00090         if (dims[i] < 0)
00091             ereport(ERROR,
00092                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00093                      errmsg("array size exceeds the maximum allowed (%d)",
00094                             (int) MaxArraySize)));
00095 
00096         prod = (int64) ret *(int64) dims[i];
00097 
00098         ret = (int32) prod;
00099         if ((int64) ret != prod)
00100             ereport(ERROR,
00101                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00102                      errmsg("array size exceeds the maximum allowed (%d)",
00103                             (int) MaxArraySize)));
00104     }
00105     Assert(ret >= 0);
00106     if ((Size) ret > MaxArraySize)
00107         ereport(ERROR,
00108                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00109                  errmsg("array size exceeds the maximum allowed (%d)",
00110                         (int) MaxArraySize)));
00111     return (int) ret;
00112 }
00113 
00114 /*
00115  * Compute ranges (sub-array dimensions) for an array slice
00116  *
00117  * We assume caller has validated slice endpoints, so overflow is impossible
00118  */
00119 void
00120 mda_get_range(int n, int *span, const int *st, const int *endp)
00121 {
00122     int         i;
00123 
00124     for (i = 0; i < n; i++)
00125         span[i] = endp[i] - st[i] + 1;
00126 }
00127 
00128 /*
00129  * Compute products of array dimensions, ie, scale factors for subscripts
00130  *
00131  * We assume caller has validated dimensions, so overflow is impossible
00132  */
00133 void
00134 mda_get_prod(int n, const int *range, int *prod)
00135 {
00136     int         i;
00137 
00138     prod[n - 1] = 1;
00139     for (i = n - 2; i >= 0; i--)
00140         prod[i] = prod[i + 1] * range[i + 1];
00141 }
00142 
00143 /*
00144  * From products of whole-array dimensions and spans of a sub-array,
00145  * compute offset distances needed to step through subarray within array
00146  *
00147  * We assume caller has validated dimensions, so overflow is impossible
00148  */
00149 void
00150 mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
00151 {
00152     int         i,
00153                 j;
00154 
00155     dist[n - 1] = 0;
00156     for (j = n - 2; j >= 0; j--)
00157     {
00158         dist[j] = prod[j] - 1;
00159         for (i = j + 1; i < n; i++)
00160             dist[j] -= (span[i] - 1) * prod[i];
00161     }
00162 }
00163 
00164 /*
00165  * Generates the tuple that is lexicographically one greater than the current
00166  * n-tuple in "curr", with the restriction that the i-th element of "curr" is
00167  * less than the i-th element of "span".
00168  *
00169  * Returns -1 if no next tuple exists, else the subscript position (0..n-1)
00170  * corresponding to the dimension to advance along.
00171  *
00172  * We assume caller has validated dimensions, so overflow is impossible
00173  */
00174 int
00175 mda_next_tuple(int n, int *curr, const int *span)
00176 {
00177     int         i;
00178 
00179     if (n <= 0)
00180         return -1;
00181 
00182     curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
00183     for (i = n - 1; i && curr[i] == 0; i--)
00184         curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];
00185 
00186     if (i)
00187         return i;
00188     if (curr[0])
00189         return 0;
00190 
00191     return -1;
00192 }
00193 
00194 /*
00195  * ArrayGetIntegerTypmods: verify that argument is a 1-D cstring array,
00196  * and get the contents converted to integers.  Returns a palloc'd array
00197  * and places the length at *n.
00198  */
00199 int32 *
00200 ArrayGetIntegerTypmods(ArrayType *arr, int *n)
00201 {
00202     int32      *result;
00203     Datum      *elem_values;
00204     int         i;
00205 
00206     if (ARR_ELEMTYPE(arr) != CSTRINGOID)
00207         ereport(ERROR,
00208                 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
00209                  errmsg("typmod array must be type cstring[]")));
00210 
00211     if (ARR_NDIM(arr) != 1)
00212         ereport(ERROR,
00213                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00214                  errmsg("typmod array must be one-dimensional")));
00215 
00216     if (array_contains_nulls(arr))
00217         ereport(ERROR,
00218                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
00219                  errmsg("typmod array must not contain nulls")));
00220 
00221     /* hardwired knowledge about cstring's representation details here */
00222     deconstruct_array(arr, CSTRINGOID,
00223                       -2, false, 'c',
00224                       &elem_values, NULL, n);
00225 
00226     result = (int32 *) palloc(*n * sizeof(int32));
00227 
00228     for (i = 0; i < *n; i++)
00229         result[i] = pg_atoi(DatumGetCString(elem_values[i]),
00230                             sizeof(int32), '\0');
00231 
00232     pfree(elem_values);
00233 
00234     return result;
00235 }