<!--
$Header: /cvsroot/pgsql/doc/src/sgml/array.sgml,v 1.8 2000/12/18 23:39:37 tgl Exp $
-->

<Chapter Id="arrays">
<Title>Arrays</Title>

<Para>
<Note>
<Para>
This must become a chapter on array behavior. Volunteers? - thomas 1998-01-12
</Para>
</Note>
</Para>

<Para>
     <ProductName>Postgres</ProductName> allows attributes of a class
     to be defined as variable-length multi-dimensional
     arrays. Arrays of any built-in type  or  user-defined  type
     can  be created.  To illustrate their use, we create this class:
     
<ProgramListing>
CREATE TABLE sal_emp (
    name            text,
    pay_by_quarter  int4[],
    schedule        text[][]
);
</ProgramListing>
</Para>

<Para>
     The above query will create a class named <FirstTerm>sal_emp</FirstTerm>  with
     a  <FirstTerm>text</FirstTerm>  string (name), a one-dimensional array of <FirstTerm>int4</FirstTerm>
     (pay_by_quarter),  which  represents   the   employee's
     salary by quarter, and a two-dimensional array of <FirstTerm>text</FirstTerm>
     (schedule),  which  represents  the  employee's  weekly
     schedule.   Now  we  do  some  <FirstTerm>INSERT</FirstTerm>s; note that when
     appending to an array, we  enclose  the  values  within
     braces  and  separate  them  by commas.  If you know <FirstTerm>C</FirstTerm>,
     this is not unlike the syntax for  initializing  structures.
     
<ProgramListing>
INSERT INTO sal_emp
    VALUES ('Bill',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {}}');

INSERT INTO sal_emp
    VALUES ('Carol',
    '{20000, 25000, 25000, 25000}',
    '{{"talk", "consult"}, {"meeting"}}');
</ProgramListing>

     Now,  we  can  run  some queries on sal_emp.  First, we
     show how to access a single element of an  array  at  a
     time.   This query retrieves the names of the employees
     whose pay changed in the second quarter:
     
<ProgramListing>
SELECT name FROM sal_emp WHERE pay_by_quarter[1] &lt;&gt; pay_by_quarter[2];

 name
-------
 Carol
(1 row)
</ProgramListing>

     <ProductName>Postgres</ProductName>  uses  the "one-based" numbering
     convention for arrays --- that is, an array  of  n  elements starts with
     array[1] and ends with array[n].
</Para>

<Para>
     This query retrieves  the  third  quarter  pay  of  all
     employees:
     
<ProgramListing>
SELECT pay_by_quarter[3] FROM sal_emp;

 pay_by_quarter
----------------
          10000
          25000
(2 rows)
</ProgramListing>
</Para>

<Para>
     We  can  also  access  arbitrary rectangular slices of an array, or
     subarrays.  An array slice is denoted by writing
     <replaceable>lower subscript</replaceable> <literal>:</literal>
     <replaceable>upper subscript</replaceable> for one or more array
     dimensions.  This query  retrieves  the  first  item  on
     Bill's schedule for the first two days of the week:
     
<ProgramListing>
SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';

      schedule
--------------------
 {{"meeting"},{""}}
(1 row)
</ProgramListing>

     We could also have written

<ProgramListing>
SELECT schedule[1:2][1] FROM sal_emp WHERE name = 'Bill';
</ProgramListing>

     with the same result.  An array subscripting operation is taken to
     represent an array slice if any of the subscripts are written in
     the form <replaceable>lower</replaceable> <literal>:</literal>
     <replaceable>upper</replaceable>.  A lower bound of 1 is assumed
     for any subscript where only one value is specified.
</Para>

<Para>
     An array value can be replaced completely:

<ProgramListing>
UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
    WHERE name = 'Carol';
</ProgramListing>

     or updated at a single element:

<ProgramListing>
UPDATE sal_emp SET pay_by_quarter[4] = 15000
    WHERE name = 'Bill';
</ProgramListing>

     or updated in a slice:

<ProgramListing>
UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
    WHERE name = 'Carol';
</ProgramListing>
</Para>

<Para>
     An array can be enlarged by assigning to an element adjacent to
     those already present, or by assigning to a slice that is adjacent
     to or overlaps the data already present.
     For example, if an array value currently has 4 elements, it will
     have five elements after an update that assigns to array[5].
     Currently, enlargement in this fashion is only
     allowed for one-dimensional arrays, not multidimensional arrays.
</Para>

<Para>
     The syntax for CREATE TABLE allows fixed-length arrays to be
     defined:

<ProgramListing>
CREATE TABLE tictactoe (
    squares   int4[3][3]
);
</ProgramListing>

     However, the current implementation does not enforce the array
     size limits --- the behavior is the same as for arrays of
     unspecified length.
</Para>

<Para>
     Actually, the current implementation doesn't enforce the declared
     number of dimensions either.  Arrays of a particular base type
     are all considered to be of the same type, regardless of size or
     number of dimensions.
</Para>

<Para>
     The current dimensions of any array value can be retrieved with
     the <function>array_dims</function> function:

<ProgramListing>
SELECT array_dims(schedule) FROM sal_emp WHERE name = 'Carol';

 array_dims
------------
 [1:2][1:1]
(1 row)
</ProgramListing>

     <function>array_dims</function> produces a <type>text</type> result,
     which is convenient for people to read but perhaps not so convenient
     for programs.
</Para>

</Chapter>
