Documentation improvements around domain types.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 24 Oct 2017 18:08:40 +0000 (14:08 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 24 Oct 2017 18:08:40 +0000 (14:08 -0400)
I was a bit surprised to find that domains were almost completely
unmentioned in the main SGML documentation, outside of the reference
pages for CREATE/ALTER/DROP DOMAIN.  In particular, noplace was it
mentioned that we don't support domains over composite, making it
hard to document the planned fix for that.

Hence, add a section about domains to chapter 8 (Data Types).

Also, modernize the type system overview in section 37.2; it had never
heard of range types, and insisted on calling arrays base types, which
seems a bit odd from a user's perspective; furthermore it didn't fit well
with the fact that we now support arrays over types other than base types.
It seems appropriate to use the term "container types" to describe all of
arrays, composites, and ranges, so let's do that.

Also a few other minor improvements, notably improve an example query
in rowtypes.sgml by using a LATERAL function instead of an ad-hoc
OFFSET 0 clause.

In part this is mop-up for commit c12d570fa, which missed updating 37.2
to reflect the fact that it added arrays of domains.  We could possibly
back-patch this without that claim, but I don't feel a strong need to.

doc/src/sgml/datatype.sgml
doc/src/sgml/extend.sgml
doc/src/sgml/ref/alter_domain.sgml
doc/src/sgml/rowtypes.sgml

index 6a15f9030c9dbac93c2e8fbc9d23f6bd9fa1b915..b397e18858347c4245484a0aa894f5f2a5d7e921 100644 (file)
@@ -4359,6 +4359,60 @@ SET xmloption TO { DOCUMENT | CONTENT };
 
   &rangetypes;
 
+  <sect1 id="domains">
+   <title>Domain Types</title>
+
+   <indexterm zone="domains">
+    <primary>domain</primary>
+   </indexterm>
+
+   <indexterm zone="domains">
+    <primary>data type</primary>
+    <secondary>domain</secondary>
+   </indexterm>
+
+   <para>
+    A <firstterm>domain</firstterm> is a user-defined data type that is
+    based on another <firstterm>underlying type</firstterm>.  Optionally,
+    it can have constraints that restrict its valid values to a subset of
+    what the underlying type would allow.  Otherwise it behaves like the
+    underlying type &mdash; for example, any operator or function that
+    can be applied to the underlying type will work on the domain type.
+    The underlying type can be any built-in or user-defined base type,
+    enum type, array or range type, or another domain.  (Currently, domains
+    over composite types are not implemented.)
+   </para>
+
+   <para>
+    For example, we could create a domain over integers that accepts only
+    positive integers:
+<programlisting>
+CREATE DOMAIN posint AS integer CHECK (VALUE &gt; 0);
+CREATE TABLE mytable (id posint);
+INSERT INTO mytable VALUES(1);   -- works
+INSERT INTO mytable VALUES(-1);  -- fails
+</programlisting>
+   </para>
+
+   <para>
+    When an operator or function of the underlying type is applied to a
+    domain value, the domain is automatically down-cast to the underlying
+    type.  Thus, for example, the result of <literal>mytable.id - 1</literal>
+    is considered to be of type <type>integer</type> not <type>posint</type>.
+    We could write <literal>(mytable.id - 1)::posint</literal> to cast the
+    result back to <type>posint</type>, causing the domain's constraints
+    to be rechecked.  In this case, that would result in an error if the
+    expression had been applied to an <structfield>id</structfield> value of
+    1.  Assigning a value of the underlying type to a field or variable of
+    the domain type is allowed without writing an explicit cast, but the
+    domain's constraints will be checked.
+   </para>
+
+   <para>
+    For additional information see <xref linkend="sql-createdomain">.
+   </para>
+  </sect1>
+
   <sect1 id="datatype-oid">
    <title>Object Identifier Types</title>
 
index c1bd03ad4c96fd42f9c2304e67fb5e10d6ea32bd..e8190108754bb49bce6bbce141e038af2f5c23af 100644 (file)
     <secondary>composite</secondary>
    </indexterm>
 
+   <indexterm zone="extend-type-system">
+    <primary>container type</primary>
+   </indexterm>
+
+   <indexterm zone="extend-type-system">
+    <primary>data type</primary>
+    <secondary>container</secondary>
+   </indexterm>
+
    <para>
-    <productname>PostgreSQL</productname> data types are divided into base
-    types, composite types, domains, and pseudo-types.
+    <productname>PostgreSQL</productname> data types can be divided into base
+    types, container types, domains, and pseudo-types.
    </para>
 
    <sect2>
     <title>Base Types</title>
 
     <para>
-     Base types are those, like <type>int4</type>, that are
+     Base types are those, like <type>integer</type>, that are
      implemented below the level of the <acronym>SQL</acronym> language
      (typically in a low-level language such as C).  They generally
      correspond to what are often known as abstract data types.
      <productname>PostgreSQL</productname> can only operate on such
      types through functions provided by the user and only understands
      the behavior of such types to the extent that the user describes
-     them.  Base types are further subdivided into scalar and array
-     types.  For each scalar type, a corresponding array type is
-     automatically created that can hold variable-size arrays of that
-     scalar type.
+     them.
+     The built-in base types are described in <xref linkend="datatype">.
+    </para>
+
+    <para>
+     Enumerated (enum) types can be considered as a subcategory of base
+     types.  The main difference is that they can be created using
+     just <acronym>SQL</acronym> commands, without any low-level programming.
+     Refer to <xref linkend="datatype-enum"> for more information.
     </para>
    </sect2>
 
    <sect2>
-    <title>Composite Types</title>
+    <title>Container Types</title>
+
+    <para>
+     <productname>PostgreSQL</productname> has three kinds
+     of <quote>container</quote> types, which are types that contain multiple
+     values of other types.  These are arrays, composites, and ranges.
+    </para>
+
+    <para>
+     Arrays can hold multiple values that are all of the same type.  An array
+     type is automatically created for each base type, composite type, range
+     type, and domain type.  But there are no arrays of arrays.  So far as
+     the type system is concerned, multi-dimensional arrays are the same as
+     one-dimensional arrays.  Refer to <xref linkend="arrays"> for more
+     information.
+    </para>
 
     <para>
      Composite types, or row types, are created whenever the user
      define a <quote>stand-alone</quote> composite type with no associated
      table.  A composite type is simply a list of types with
      associated field names.  A value of a composite type is a row or
-     record of field values.  The user can access the component fields
-     from <acronym>SQL</acronym> queries. Refer to <xref linkend="rowtypes">
-     for more information on composite types.
+     record of field values.  Refer to <xref linkend="rowtypes">
+     for more information.
+    </para>
+
+    <para>
+     A range type can hold two values of the same type, which are the lower
+     and upper bounds of the range.  Range types are user-created, although
+     a few built-in ones exist.  Refer to <xref linkend="rangetypes">
+     for more information.
     </para>
    </sect2>
 
     <title>Domains</title>
 
     <para>
-     A domain is based on a particular base type and for many purposes
-     is interchangeable with its base type.  However, a domain can
-     have constraints that restrict its valid values to a subset of
-     what the underlying base type would allow.
-    </para>
-
-    <para>
-     Domains can be created using the <acronym>SQL</acronym> command
-     <xref linkend="sql-createdomain">.
-     Their creation and use is not discussed in this chapter.
+     A domain is based on a particular underlying type and for many purposes
+     is interchangeable with its underlying type.  However, a domain can have
+     constraints that restrict its valid values to a subset of what the
+     underlying type would allow.  Domains are created using
+     the <acronym>SQL</acronym> command <xref linkend="sql-createdomain">.
+     Refer to <xref linkend="domains"> for more information.
     </para>
    </sect2>
 
 
     <para>
      There are a few <quote>pseudo-types</quote> for special purposes.
-     Pseudo-types cannot appear as columns of tables or attributes of
-     composite types, but they can be used to declare the argument and
+     Pseudo-types cannot appear as columns of tables or components of
+     container types, but they can be used to declare the argument and
      result types of functions.  This provides a mechanism within the
      type system to identify special classes of functions.  <xref
      linkend="datatype-pseudotypes-table"> lists the existing
    </indexterm>
 
    <indexterm zone="extend-types-polymorphic">
-    <primary>type</primary>
+    <primary>data type</primary>
     <secondary>polymorphic</secondary>
    </indexterm>
 
index 26e95aefcfd5afebcb7daaa07a1bcc4358d77ca6..9cd044de54047a6b91dae60529e9d583161cf9d8 100644 (file)
@@ -199,7 +199,7 @@ ALTER DOMAIN <replaceable class="parameter">name</replaceable>
      </varlistentry>
 
      <varlistentry>
-      <term><replaceable class="parameter">NOT VALID</replaceable></term>
+      <term><literal>NOT VALID</literal></term>
       <listitem>
        <para>
         Do not verify existing column data for constraint validity.
@@ -274,11 +274,11 @@ ALTER DOMAIN <replaceable class="parameter">name</replaceable>
 
   <para>
    Currently, <command>ALTER DOMAIN ADD CONSTRAINT</command>, <command>ALTER
-   DOMAIN VALIDATE CONSTRAINT</command>, and <command>ALTER DOMAIN SET NOT NULL</command>
-   will fail if the validated named domain or
-   any derived domain is used within a composite-type column of any
-   table in the database.  They should eventually be improved to be
-   able to verify the new constraint for such nested columns.
+   DOMAIN VALIDATE CONSTRAINT</command>, and <command>ALTER DOMAIN SET NOT
+   NULL</command> will fail if the named domain or any derived domain is used
+   within a container-type column (a composite, array, or range column) in
+   any table in the database.  They should eventually be improved to be able
+   to verify the new constraint for such nested values.
   </para>
 
  </refsect1>
index bc2fc9b88504cf944d681c30f186afd057fc042c..7e436a46065e644ebb977fcb6aefd84a096bf569 100644 (file)
@@ -328,11 +328,16 @@ SELECT (myfunc(x)).a, (myfunc(x)).b, (myfunc(x)).c FROM some_table;
     with either syntax.  If it's an expensive function you may wish to
     avoid that, which you can do with a query like:
 <programlisting>
-SELECT (m).* FROM (SELECT myfunc(x) AS m FROM some_table OFFSET 0) ss;
+SELECT m.* FROM some_table, LATERAL myfunc(x) AS m;
 </programlisting>
-    The <literal>OFFSET 0</literal> clause keeps the optimizer
-    from <quote>flattening</quote> the sub-select to arrive at the form with
-    multiple calls of <function>myfunc()</function>.
+    Placing the function in
+    a <literal>LATERAL</literal> <literal>FROM</literal> item keeps it from
+    being invoked more than once per row.  <literal>m.*</literal> is still
+    expanded into <literal>m.a, m.b, m.c</literal>, but now those variables
+    are just references to the output of the <literal>FROM</literal> item.
+    (The <literal>LATERAL</literal> keyword is optional here, but we show it
+    to clarify that the function is getting <structfield>x</structfield>
+    from <structname>some_table</structname>.)
    </para>
   </tip>