Project: YugabyteDB (App Definition and Development / Database)
File: properties.md

title: Array properties linkTitle: Array properties headerTitle: Functions for reporting the geometric properties of an array description: Functions for reporting the geometric properties of an array menu: v2.18: identifier: array-properties parent: array-functions-operators type: docs These functions return the various dimensional properties that jointly characterize an array. These three together completely specify the shape and size: its dimensionality (`int`) the lower bound along each dimension (`int`) the upper bound along each dimension (`int`). There are functions for returning two other properties: the length along each dimension (`int`); and its cardinality (`int`). But each of these can be derived from the set of the lower and upper bounds for all the dimensions. There is also a function that returns the values for the lower and upper bounds for all the dimensions as a single `text` value. The behavior of each of the functions for reporting the geometric properties of an array is illustrated by supplying the same two arrays as the first actual argument to two invocations of the function. The return value, in all cases, is insensitive to the array's data type and the values within the array. Create and populate "table t" thus: ```plpgsql create table t(k int primary key, arr1 text[], arr2 text[]); insert into t(k, arr1, arr2) values(1, '[3:10]={ 1, 2, 3, 4, 5, 6, 7, 8}', '={{1, 2, 3, 4}, {5, 6, 7, 8}}' ); ``` You will use it in the example for each of the functions. (The optional syntax items `. Run the `SELECT` statement for each function to illustrate what produces for the same pair of input arrays. Purpose: Return the number of dimensions (that is, the dimensionality) of the specified array. Signature: ``` input value: anyarray return value: int ``` Example: ```plpgsql select arrayndims(arr1) as ndims_1, arrayndims(arr2) as ndims_2 from t where k = 1; ``` It produces this result: ``` ndims1 | ndims2 1 | 2 ``` Purpose: Return the lower bound of the specified array along the specified dimension. Signature: ``` input value: anyarray, int return value: int ``` Example: ```plpgsql select arraylower(arr1, 1) as arr1lb, arraylower(arr2, 1) as arr2lb_1, arraylower(arr2, 2) as arr2lb_2 from t where k = 1; ``` It produces this result: ``` arr1lb | arr2lb1 | arr2lb2 -++ 3 | 2 | 4 ``` Purpose: Return the upper bound of the specified array along the specified dimension. Signature: ``` input value: anyarray, int return value: int ``` Example: The use of `arrayupper()` is exactly symmetrical with the use of `arraylower()`. ```plpgsql select arrayupper(arr1, 1) as arr1ub, arrayupper(arr2, 1) as arr2ub_1, arrayupper(arr2, 2) as arr2ub_2 from t where k = 1; ``` It produces this result: ``` arr1ub | arr2ub1 | arr2ub2 -++ 10 | 3 | 7 ``` Purpose: Return the length of the specified array along the specified

Notice that, among `arraylower()` and `arrayupper()` and `arraylength()`, the result of any two of them determines the result of the third. You could therefore decide, for example, only to use `arraylower()` and `array_upper()` and to determine the length, when you need it, by subtraction. But, for code clarity and brevity, you may as well use exactly the one that matches your present purpose. Signature: ``` input value: anyarray, int return value: int ``` Example: The use of `arraylength()` is exactly symmetrical with the use of `arraylower()` and `array_upper()`. ```plpgsql select arraylength(arr1, 1) as arr1len, arraylength(arr2, 1) as arr2len_1, arraylength(arr2, 2) as arr2len_2 from t where k = 1; ``` It produces this result: ``` arr1len | arr2len1 | arr2len2 --+-+- 8 | 2 | 4 ``` Purpose: Return the total number of values in the specified array. Notice that the value that this function returns can be computed as the product of values returned by the `array_length()` function along each direction. Signature: ``` input value: anyarray return value: int ``` Example: ```plpgsql select cardinality(arr1) as card1, cardinality(arr2) as card2 from t where k = 1; ``` It produces this result: ``` card1 | card2 --+-- 8 | 8 ``` Purpose: Return a text representation of the same information as `arraylower()` and `arraylength()` return, for all dimensions, in a single text value. Signature: ``` input value: anyarray return value: text ``` Example: The `arraydims()` function is useful to produce a result that is easily humanly readable. If you want to use the information that it returns programmatically, then you should use `arraylower()`, `arrayupper()`, or `arraylength()`. ```plpgsql select arraydims(arr1) as arr1dims, arraydims(arr2) as arr2dims from t where k = 1; ``` It produces this result: ``` arr1dims | arr2dims ``` Create the procedure "assert&#95;semantics&#95;and&#95;traverse&#95;values()" and then invoke it for each of the three provided data sets. You supply it with a one-dimensional array and a two dimensional array and, for each, your humanly determined estimates of these values: what `array_ndims()` returns what `array_lower()` returns for each dimension what `array_upper()` returns for each dimension. The procedure obtains the actual values, programmatically, for all of the values that you supply and asserts that they agree. Notice that the cardinality and the length along each dimension are omitted, by design, from this list. The procedure also obtains these values, programmatically, and checks that these agree with the values that are computed from, respectively, the length along each dimension and the upper and lower bounds along each dimension. Notice, too, that the value that `arraydims()` returns can be computed from the upper and lower bounds along each dimension. So the procedure does this too and checks that the value returned by `arraydims()` is consistent with the values returned by `arraylower()` and `arrayupper()`. The procedure has some particular requirements: The cardinality of each of the two supplied arrays must be the

The actual array values, in row-major order, must be the same, pairwise. Briefly, "row-major" order is the order in which the last subscript varies most rapidly. Meeting these requirements are allows the procedure to deliver two bonus benefits. First, it demonstrates how to traverse array values in row-major order using the values returned by the functions that this section describes, thereby demonstrating what the term "row-major order" means. Second. it compares the values, pairwise, for equality. This comparison rule is the basis of the semantics of the comparison operations described in . Note: There are no built-in functions for computing, for example, the product of two matrices or the product of a vector and a matrix. (A vector is a one-dimensional array, and a matrix is a two-dimensional array.) But, as long as you know how to traverse the values in a matrix in row-major order, you can implement the missing vector and matrix multiplication functionality for yourself. ```plpgsql create procedure assertsemanticsandtraversevalues( a in int[], b in int[], andims in int, alb in int, a_ub in int, bndims in int, blb1 in int, bub_1 in int, blb2 in int, bub2 in int) language plpgsql as $body$ declare -- Get the facts that are implied by the user-supplied facts. alen constant int := arraylength(a, 1); blen1 constant int := array_length(b, 1); blen2 constant int := array_length(b, 2); adims constant text := '['||alb::text||':'||a_ub::text||']'; bdims constant text := '['||blb1::text||':'||bub_1::text||']'|| '['||blb2::text||':'||bub2::text||']'; begin -- Confirm that the supplied arrays meet the basic -- dimensionalities requirement. assert andims = 1 and bndims = 2, 'ndims assert failed'; -- Confirm the user-supplied facts about the shape and size of "a". assert arrayndims(a) = andims and arraylower(a, 1) = alb and arrayupper(a, 1) = aub , '"a" dimensions assert failed'; -- Confirm the user-supplied facts about the shape and size of "b". assert arrayndims(b) = bndims and arraylower(b, 1) = blb_1 and arrayupper(b, 1) = bub_1 and arraylower(b, 2) = blb_2 and arrayupper(b, 2) = bub_2 , '"b" dimensions assert failed'; -- Confirm the length overspecification rule. assert (aub - alb + 1 ) = a_len and (bub1 - blb1 + 1) = blen1 and (bub2 - blb2 + 1) = blen2 , 'Length overspecification rule assert failed.'; -- Confirm the cardinality overspecification rule. assert cardinality(a) = a_len and cardinality(b) = blen1 * blen2 , 'Cardinality overspecification rule assert failed.'; -- Confirm the "dims" overspecification rule. assert arraydims(a) = adims and arraydims(b) = bdims , '"dims" overspecification rule assert failed.'; -- Do the row-major order traversal and -- check that the values are pairwise-identical. for j in 0..(a_len - 1) loop declare -- Traversing a 1-d array is trivial. aidx constant int := j + alb; -- Traversing a 2-d array is need a bit more

bidx1 constant int := floor(j/blen2) + blb1; bidx2 constant int := ((j + blen2) % blen2) + blb2; atxt constant text := lpad(aidx::text, 2); btxt1 constant text := lpad(bidx1::text, 2); btxt2 constant text := lpad(bidx2::text, 2); val constant text := lpad(a[a_idx]::text, 2); line constant text := 'a['||a_txt||'] = '|| 'b = '|| val; begin assert a, 'Row-major order pairwise equality assert failed'; raise info '%', line; end; end loop; end; $body$; ``` Try it on the first data set: ```plpgsql do $body$ declare a constant int[] := '{ 1, 2, 3, 4, 5, 6}'; b constant int[] := '{{1, 2}, {3, 4}, {5, 6}}'; a_ndims constant int := 1; a_lb constant int := 1; a_ub constant int := 6; b_ndims constant int := 2; blb1 constant int := 1; bub1 constant int := 3; blb2 constant int := 1; bub2 constant int := 2; begin call assertsemanticsandtraversevalues( a, b, andims, alb, a_ub, bndims, blb1, bub_1, blb2, bub2); end; $body$; ``` It produces this result (after manually removing the "INFO:" prompts): ``` a = 1 a = 2 a = 3 a = 4 a = 5 a = 6 ``` Try it on the second data set: ```plpgsql do $body$ declare a constant int[] := '[3:14]={ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}'; b constant int={{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}'; a_ndims constant int := 1; a_lb constant int := 3; a_ub constant int := 14; b_ndims constant int := 2; blb1 constant int := 3; bub1 constant int := 6; blb2 constant int := 6; bub2 constant int := 8; begin call assertsemanticsandtraversevalues( a, b, andims, alb, a_ub, bndims, blb1, bub_1, blb2, bub2); end; $body$; ``` It produces this result: ``` a = 1 a = 2 a = 3 a = 4 a = 5 a = 6 a = 7 a = 8 a = 9 a = 10 a = 11 a = 12 ``` Try it on the third data set: ```plpgsql do $body$ declare a constant int[] := '[3:18]={ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}'; b constant int={{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}'; a_ndims constant int := 1; a_lb constant int := 3; a_ub constant int := 18; b_ndims constant int := 2; blb1 constant int := 3; bub1 constant int := 6; blb2 constant int := 2; bub2 constant int := 5; begin call assertsemanticsandtraversevalues( a, b, andims, alb, a_ub, bndims, blb1, bub_1, blb2, bub2); end; $body$; ``` It produces this result: ``` a = 1 a = 2 a = 3 a = 4 a = 5 a = 6 a = 7 a = 8 a = 9 a = 10 a = 11 a = 12 a = 13 a = 14 a = 15 a = 16 ```