LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - arrayutils.c (source / functions) Coverage Total Hit UNC LBC UIC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 89.6 % 77 69 4 2 2 39 7 23 8 41 3
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 11 11 6 3 2 6 2
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * arrayutils.c
       4                 :  *    This file contains some support routines required for array functions.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *    src/backend/utils/adt/arrayutils.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : 
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include "catalog/pg_type.h"
      19                 : #include "common/int.h"
      20                 : #include "utils/array.h"
      21                 : #include "utils/builtins.h"
      22                 : #include "utils/memutils.h"
      23                 : 
      24                 : 
      25                 : /*
      26                 :  * Convert subscript list into linear element number (from 0)
      27                 :  *
      28                 :  * We assume caller has already range-checked the dimensions and subscripts,
      29                 :  * so no overflow is possible.
      30                 :  */
      31                 : int
      32 CBC      346148 : ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx)
      33                 : {
      34                 :     int         i,
      35          346148 :                 scale = 1,
      36          346148 :                 offset = 0;
      37                 : 
      38          692455 :     for (i = n - 1; i >= 0; i--)
      39                 :     {
      40          346307 :         offset += (indx[i] - lb[i]) * scale;
      41          346307 :         scale *= dim[i];
      42                 :     }
      43          346148 :     return offset;
      44                 : }
      45                 : 
      46                 : /*
      47                 :  * Same, but subscripts are assumed 0-based, and use a scale array
      48                 :  * instead of raw dimension data (see mda_get_prod to create scale array)
      49                 :  */
      50                 : int
      51          889351 : ArrayGetOffset0(int n, const int *tup, const int *scale)
      52                 : {
      53                 :     int         i,
      54          889351 :                 lin = 0;
      55                 : 
      56         1780047 :     for (i = 0; i < n; i++)
      57          890696 :         lin += tup[i] * scale[i];
      58          889351 :     return lin;
      59                 : }
      60                 : 
      61                 : /*
      62                 :  * Convert array dimensions into number of elements
      63                 :  *
      64                 :  * This must do overflow checking, since it is used to validate that a user
      65                 :  * dimensionality request doesn't overflow what we can handle.
      66                 :  *
      67                 :  * We limit array sizes to at most about a quarter billion elements,
      68                 :  * so that it's not necessary to check for overflow in quite so many
      69                 :  * places --- for instance when palloc'ing Datum arrays.
      70                 :  *
      71                 :  * The multiplication overflow check only works on machines that have int64
      72                 :  * arithmetic, but that is nearly all platforms these days, and doing check
      73                 :  * divides for those that don't seems way too expensive.
      74                 :  */
      75                 : int
      76        41421889 : ArrayGetNItems(int ndim, const int *dims)
      77                 : {
      78 GNC    41421889 :     return ArrayGetNItemsSafe(ndim, dims, NULL);
      79                 : }
      80                 : 
      81                 : /*
      82                 :  * This entry point can return the error into an ErrorSaveContext
      83                 :  * instead of throwing an exception.  -1 is returned after an error.
      84                 :  */
      85                 : int
      86        41604181 : ArrayGetNItemsSafe(int ndim, const int *dims, struct Node *escontext)
      87                 : {
      88 ECB             :     int32       ret;
      89                 :     int         i;
      90                 : 
      91                 : #define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
      92                 : 
      93 GIC    41604181 :     if (ndim <= 0)
      94         1189582 :         return 0;
      95        40414599 :     ret = 1;
      96 CBC    80831331 :     for (i = 0; i < ndim; i++)
      97                 :     {
      98                 :         int64       prod;
      99                 : 
     100                 :         /* A negative dimension implies that UB-LB overflowed ... */
     101 GIC    40416732 :         if (dims[i] < 0)
     102 UNC           0 :             ereturn(escontext, -1,
     103 ECB             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     104                 :                      errmsg("array size exceeds the maximum allowed (%d)",
     105                 :                             (int) MaxArraySize)));
     106                 : 
     107 GIC    40416732 :         prod = (int64) ret * (int64) dims[i];
     108                 : 
     109        40416732 :         ret = (int32) prod;
     110        40416732 :         if ((int64) ret != prod)
     111 UNC           0 :             ereturn(escontext, -1,
     112 EUB             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     113                 :                      errmsg("array size exceeds the maximum allowed (%d)",
     114                 :                             (int) MaxArraySize)));
     115                 :     }
     116 GIC    40414599 :     Assert(ret >= 0);
     117 CBC    40414599 :     if ((Size) ret > MaxArraySize)
     118 UNC           0 :         ereturn(escontext, -1,
     119 ECB             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     120                 :                  errmsg("array size exceeds the maximum allowed (%d)",
     121 EUB             :                         (int) MaxArraySize)));
     122 GIC    40414599 :     return (int) ret;
     123                 : }
     124                 : 
     125                 : /*
     126 ECB             :  * Verify sanity of proposed lower-bound values for an array
     127                 :  *
     128 EUB             :  * The lower-bound values must not be so large as to cause overflow when
     129                 :  * calculating subscripts, e.g. lower bound 2147483640 with length 10
     130                 :  * must be disallowed.  We actually insist that dims[i] + lb[i] be
     131                 :  * computable without overflow, meaning that an array with last subscript
     132 ECB             :  * equal to INT_MAX will be disallowed.
     133                 :  *
     134                 :  * It is assumed that the caller already called ArrayGetNItems, so that
     135                 :  * overflowed (negative) dims[] values have been eliminated.
     136                 :  */
     137                 : void
     138 GIC     1005046 : ArrayCheckBounds(int ndim, const int *dims, const int *lb)
     139                 : {
     140 GNC     1005046 :     (void) ArrayCheckBoundsSafe(ndim, dims, lb, NULL);
     141         1005046 : }
     142                 : 
     143                 : /*
     144                 :  * This entry point can return the error into an ErrorSaveContext
     145                 :  * instead of throwing an exception.
     146                 :  */
     147                 : bool
     148         1187338 : ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb,
     149                 :                      struct Node *escontext)
     150                 : {
     151                 :     int         i;
     152                 : 
     153 GIC     2353478 :     for (i = 0; i < ndim; i++)
     154                 :     {
     155                 :         /* PG_USED_FOR_ASSERTS_ONLY prevents variable-isn't-read warnings */
     156                 :         int32       sum PG_USED_FOR_ASSERTS_ONLY;
     157                 : 
     158         1166140 :         if (pg_add_s32_overflow(dims[i], lb[i], &sum))
     159 UNC           0 :             ereturn(escontext, false,
     160                 :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     161 ECB             :                      errmsg("array lower bound is too large: %d",
     162                 :                             lb[i])));
     163                 :     }
     164                 : 
     165 GNC     1187338 :     return true;
     166                 : }
     167                 : 
     168                 : /*
     169                 :  * Compute ranges (sub-array dimensions) for an array slice
     170                 :  *
     171 ECB             :  * We assume caller has validated slice endpoints, so overflow is impossible
     172                 :  */
     173                 : void
     174 GIC         508 : mda_get_range(int n, int *span, const int *st, const int *endp)
     175                 : {
     176 ECB             :     int         i;
     177                 : 
     178 GIC        1277 :     for (i = 0; i < n; i++)
     179             769 :         span[i] = endp[i] - st[i] + 1;
     180             508 : }
     181 ECB             : 
     182 EUB             : /*
     183                 :  * Compute products of array dimensions, ie, scale factors for subscripts
     184                 :  *
     185                 :  * We assume caller has validated dimensions, so overflow is impossible
     186                 :  */
     187                 : void
     188 CBC      178929 : mda_get_prod(int n, const int *range, int *prod)
     189                 : {
     190                 :     int         i;
     191                 : 
     192 GIC      178929 :     prod[n - 1] = 1;
     193          179245 :     for (i = n - 2; i >= 0; i--)
     194             316 :         prod[i] = prod[i + 1] * range[i + 1];
     195          178929 : }
     196                 : 
     197 ECB             : /*
     198                 :  * From products of whole-array dimensions and spans of a sub-array,
     199                 :  * compute offset distances needed to step through subarray within array
     200                 :  *
     201                 :  * We assume caller has validated dimensions, so overflow is impossible
     202                 :  */
     203                 : void
     204 GIC         180 : mda_get_offset_values(int n, int *dist, const int *prod, const int *span)
     205                 : {
     206                 :     int         i,
     207                 :                 j;
     208                 : 
     209             180 :     dist[n - 1] = 0;
     210             288 :     for (j = n - 2; j >= 0; j--)
     211 ECB             :     {
     212 GIC         108 :         dist[j] = prod[j] - 1;
     213             231 :         for (i = j + 1; i < n; i++)
     214             123 :             dist[j] -= (span[i] - 1) * prod[i];
     215 ECB             :     }
     216 CBC         180 : }
     217 ECB             : 
     218                 : /*
     219                 :  * Generates the tuple that is lexicographically one greater than the current
     220                 :  * n-tuple in "curr", with the restriction that the i-th element of "curr" is
     221                 :  * less than the i-th element of "span".
     222                 :  *
     223                 :  * Returns -1 if no next tuple exists, else the subscript position (0..n-1)
     224                 :  * corresponding to the dimension to advance along.
     225                 :  *
     226                 :  * We assume caller has validated dimensions, so overflow is impossible
     227                 :  */
     228                 : int
     229 GIC         645 : mda_next_tuple(int n, int *curr, const int *span)
     230                 : {
     231                 :     int         i;
     232 ECB             : 
     233 CBC         645 :     if (n <= 0)
     234 UIC           0 :         return -1;
     235 ECB             : 
     236 CBC         645 :     curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
     237             804 :     for (i = n - 1; i && curr[i] == 0; i--)
     238 GIC         159 :         curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];
     239 ECB             : 
     240 GIC         645 :     if (i)
     241             165 :         return i;
     242             480 :     if (curr[0])
     243             300 :         return 0;
     244                 : 
     245             180 :     return -1;
     246                 : }
     247                 : 
     248                 : /*
     249                 :  * ArrayGetIntegerTypmods: verify that argument is a 1-D cstring array,
     250                 :  * and get the contents converted to integers.  Returns a palloc'd array
     251                 :  * and places the length at *n.
     252 ECB             :  */
     253                 : int32 *
     254 GIC        4378 : ArrayGetIntegerTypmods(ArrayType *arr, int *n)
     255                 : {
     256 ECB             :     int32      *result;
     257 EUB             :     Datum      *elem_values;
     258                 :     int         i;
     259 ECB             : 
     260 CBC        4378 :     if (ARR_ELEMTYPE(arr) != CSTRINGOID)
     261 LBC           0 :         ereport(ERROR,
     262                 :                 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
     263 ECB             :                  errmsg("typmod array must be type cstring[]")));
     264                 : 
     265 CBC        4378 :     if (ARR_NDIM(arr) != 1)
     266 LBC           0 :         ereport(ERROR,
     267                 :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     268 ECB             :                  errmsg("typmod array must be one-dimensional")));
     269                 : 
     270 GIC        4378 :     if (array_contains_nulls(arr))
     271 UIC           0 :         ereport(ERROR,
     272                 :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     273                 :                  errmsg("typmod array must not contain nulls")));
     274                 : 
     275 GNC        4378 :     deconstruct_array_builtin(arr, CSTRINGOID, &elem_values, NULL, n);
     276                 : 
     277 GIC        4378 :     result = (int32 *) palloc(*n * sizeof(int32));
     278                 : 
     279            9713 :     for (i = 0; i < *n; i++)
     280 CBC        5335 :         result[i] = pg_strtoint32(DatumGetCString(elem_values[i]));
     281 EUB             : 
     282 GIC        4378 :     pfree(elem_values);
     283                 : 
     284            4378 :     return result;
     285 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a