Thread: Domain Support -- another round

Domain Support -- another round

From
Rod Taylor
Date:
Ok....

gram.y is fixed (no more %expect usage)

Using the copyCreateDomainStmt in the proper place.

Evolution is the mail client of choice for different (improved?) mime
headers.

And attached is a regular diff -c, rather than a cvs diff -c.


I updated the poor descriptions of MergeDomainAttributes().  Hopefully
its current and future use is more obvious.


Am I getting close?


Attachment

Re: Domain Support -- another round

From
"Christopher Kings-Lynne"
Date:
Grr.  Figured out why the patch was pooched.  Basically SAVING it out of
Outlook adds CR's everywhere!  Believe it or not...

BTW, it failed when patching parsenodes.h - you might need to update the
patch against CVS...

Chris

> -----Original Message-----
> From: pgsql-patches-owner@postgresql.org
> [mailto:pgsql-patches-owner@postgresql.org]On Behalf Of Rod Taylor
> Sent: Friday, 8 March 2002 12:21 PM
> To: pgsql-patches@postgresql.org
> Subject: [PATCHES] Domain Support -- another round
>
>
> Ok....
>
> gram.y is fixed (no more %expect usage)
>
> Using the copyCreateDomainStmt in the proper place.
>
> Evolution is the mail client of choice for different (improved?) mime
> headers.
>
> And attached is a regular diff -c, rather than a cvs diff -c.
>
>
> I updated the poor descriptions of MergeDomainAttributes().  Hopefully
> its current and future use is more obvious.
>
>
> Am I getting close?
>
>


Re: Domain Support -- another round

From
"Rod Taylor"
Date:
Sorry, yes.

As much as I can I've been updating as I go.
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Gavin Sherry" <swm@linuxworld.com.au>
To: "Rod Taylor" <rbt@zort.ca>
Sent: Friday, March 08, 2002 1:23 AM
Subject: Re: [PATCHES] Domain Support -- another round


> Is this against latest CVS?
>
> Gavin
>
>
>


Re: Domain Support -- another round

From
"Rod Taylor"
Date:
Attached is a diff to the patch of the below message to use b_expr
rather than c_expr.

Also includes an improved regress set.  Less redundant failures, and
tests numeric types as they're different from the others enough to
warrent it.
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Rod Taylor" <rbt@zort.ca>
To: <pgsql-patches@postgresql.org>
Sent: Thursday, March 07, 2002 11:21 PM
Subject: [PATCHES] Domain Support -- another round


> Ok....
>
> gram.y is fixed (no more %expect usage)
>
> Using the copyCreateDomainStmt in the proper place.
>
> Evolution is the mail client of choice for different (improved?)
mime
> headers.
>
> And attached is a regular diff -c, rather than a cvs diff -c.
>
>
> I updated the poor descriptions of MergeDomainAttributes().
Hopefully
> its current and future use is more obvious.
>
>
> Am I getting close?
>
>


----------------------------------------------------------------------
----------


>
> ---------------------------(end of
broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to
majordomo@postgresql.org)
>

Attachment

Re: Domain Support -- another round

From
Bruce Momjian
Date:
Rod indicates this is his final version.

Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Rod Taylor wrote:
> Attached is a diff to the patch of the below message to use b_expr
> rather than c_expr.
>
> Also includes an improved regress set.  Less redundant failures, and
> tests numeric types as they're different from the others enough to
> warrent it.
> --
> Rod Taylor
>
> This message represents the official view of the voices in my head
>
> ----- Original Message -----
> From: "Rod Taylor" <rbt@zort.ca>
> To: <pgsql-patches@postgresql.org>
> Sent: Thursday, March 07, 2002 11:21 PM
> Subject: [PATCHES] Domain Support -- another round
>
>
> > Ok....
> >
> > gram.y is fixed (no more %expect usage)
> >
> > Using the copyCreateDomainStmt in the proper place.
> >
> > Evolution is the mail client of choice for different (improved?)
> mime
> > headers.
> >
> > And attached is a regular diff -c, rather than a cvs diff -c.
> >
> >
> > I updated the poor descriptions of MergeDomainAttributes().
> Hopefully
> > its current and future use is more obvious.
> >
> >
> > Am I getting close?
> >
> >
>
>
> ----------------------------------------------------------------------
> ----------
>
>
> >
> > ---------------------------(end of
> broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to
> majordomo@postgresql.org)
> >

[ Attachment, skipping... ]

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Domain Support -- another round

From
Peter Eisentraut
Date:
Random nitpicking below.  Also, have you created a regression test?


> diff -rc pgsql.orig/doc/src/sgml/catalogs.sgml pgsqldomain/doc/src/sgml/catalogs.sgml
> *** pgsql.orig/doc/src/sgml/catalogs.sgml    Thu Mar  7 11:35:32 2002
> --- pgsqldomain/doc/src/sgml/catalogs.sgml    Thu Mar  7 22:24:23 2002
> ***************
> *** 2511,2516 ****
> --- 2511,2563 ----
>        </row>
>
>        <row>
> +       <entry>typbasetype</entry>
> +       <entry><type>oid</type></entry>
> +       <entry></entry>
> +       <entry><para>
> +        <structfield>typbasetype</structfield> is the type that this one is based
> +        off of.  Normally references the domains parent type, and is 0 otherwise.

"based on"

> +       </para></entry>
> +      </row>
> +
> +      <row>
> +       <entry>typnotnull</entry>
> +       <entry><type>boolean</type></entry>
> +       <entry></entry>
> +       <entry><para>
> +        <structfield>typnotnull</structfield> represents a NOT NULL
> +        constraint on a type.  Normally used only for domains.

And unnormally...?

> +       </para></entry>
> +      </row>
> +
> +      <row>
> +       <entry>typmod</entry>
> +       <entry><type>integer</type></entry>
> +       <entry></entry>
> +       <entry><para>
> +        <structfield>typmod</structfield> records type-specific data
> +        supplied at table creation time (for example, the maximum
> +        length of a <type>varchar</type> column).  It is passed to
> +        type-specific input and output functions as the third
> +        argument. The value will generally be -1 for types that do not
> +        need typmod.  This data is copied to
> +        <structfield>pg_attribute.atttypmod</structfield> on creation
> +        of a table using a domain as it's field type.
> +        </para></entry>
> +      </row>
> +
> +      <row>
> +       <entry>typdefaultbin</entry>
> +       <entry><type>text</type></entry>
> +       <entry></entry>
> +       <entry><para>
> +        <structfield>typdefaultbin</structfield> is NULL for types without a
> +        default value.  If it's not NULL, it contains the internal string
> +        representation of the default expression node.
> +       </para></entry>
> +      </row>
> +
> +      <row>
>         <entry>typdefault</entry>
>         <entry><type>text</type></entry>
>         <entry></entry>
> diff -rc pgsql.orig/doc/src/sgml/ref/allfiles.sgml pgsqldomain/doc/src/sgml/ref/allfiles.sgml
> *** pgsql.orig/doc/src/sgml/ref/allfiles.sgml    Thu Mar  7 11:35:32 2002
> --- pgsqldomain/doc/src/sgml/ref/allfiles.sgml    Thu Mar  7 22:24:23 2002
> ***************
> *** 52,57 ****
> --- 52,58 ----
>   <!entity createAggregate    system "create_aggregate.sgml">
>   <!entity createConstraint   system "create_constraint.sgml">
>   <!entity createDatabase     system "create_database.sgml">
> + <!entity createDomain       system "create_domain.sgml">

I don't see this file included.

>   <!entity createFunction     system "create_function.sgml">
>   <!entity createGroup        system "create_group.sgml">
>   <!entity createIndex        system "create_index.sgml">
> ***************
> *** 69,74 ****
> --- 70,76 ----
>   <!entity delete             system "delete.sgml">
>   <!entity dropAggregate      system "drop_aggregate.sgml">
>   <!entity dropDatabase       system "drop_database.sgml">
> + <!entity dropDomain         system "drop_domain.sgml">
>   <!entity dropFunction       system "drop_function.sgml">
>   <!entity dropGroup          system "drop_group.sgml">
>   <!entity dropIndex          system "drop_index.sgml">
> diff -rc pgsql.orig/doc/src/sgml/ref/comment.sgml pgsqldomain/doc/src/sgml/ref/comment.sgml
> *** pgsql.orig/doc/src/sgml/ref/comment.sgml    Thu Mar  7 11:35:33 2002
> --- pgsqldomain/doc/src/sgml/ref/comment.sgml    Thu Mar  7 22:24:23 2002
> ***************
> *** 25,31 ****
>     <synopsis>
>   COMMENT ON
>   [
> !   [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable
class="PARAMETER">object_name</replaceable>| 
>     COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable
class="PARAMETER">column_name</replaceable>| 
>     AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable
class="PARAMETER">agg_type</replaceable>)| 
>     FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable
class="PARAMETER">arg1</replaceable>,<replaceable class="PARAMETER">arg2</replaceable>, ...) | 
> --- 25,31 ----
>     <synopsis>
>   COMMENT ON
>   [
> !   [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable
class="PARAMETER">object_name</replaceable>| 
>     COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable
class="PARAMETER">column_name</replaceable>| 
>     AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable
class="PARAMETER">agg_type</replaceable>)| 
>     FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable
class="PARAMETER">arg1</replaceable>,<replaceable class="PARAMETER">arg2</replaceable>, ...) | 
> ***************
> *** 33,39 ****
>     TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable
class="PARAMETER">table_name</replaceable>
>   ] IS <replaceable class="PARAMETER">'text'</replaceable>
>     </synopsis>
> !
>     <refsect2 id="R2-SQL-COMMENT-1">
>      <refsect2info>
>       <date>1999-10-25</date>
> --- 33,39 ----
>     TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable
class="PARAMETER">table_name</replaceable>
>   ] IS <replaceable class="PARAMETER">'text'</replaceable>
>     </synopsis>
> !
>     <refsect2 id="R2-SQL-COMMENT-1">
>      <refsect2info>
>       <date>1999-10-25</date>
> ***************
> *** 64,70 ****
>       </variablelist>
>      </para>
>     </refsect2>
> !
>     <refsect2 id="R2-SQL-COMMENT-2">
>      <refsect2info>
>       <date>1998-09-08</date>
> --- 64,70 ----
>       </variablelist>
>      </para>
>     </refsect2>
> !
>     <refsect2 id="R2-SQL-COMMENT-2">
>      <refsect2info>
>       <date>1998-09-08</date>
> ***************
> *** 99,105 ****
>     </title>
>     <para>
>      <command>COMMENT</command> stores a comment about a database object.
> !     Comments can be
>       easily retrieved with <command>psql</command>'s
>       <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
>       commands.  Other user interfaces to retrieve comments can be built atop
> --- 99,105 ----
>     </title>
>     <para>
>      <command>COMMENT</command> stores a comment about a database object.
> !     Comments can be
>       easily retrieved with <command>psql</command>'s
>       <command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
>       commands.  Other user interfaces to retrieve comments can be built atop
> ***************
> *** 141,146 ****
> --- 141,147 ----
>
>      <programlisting>
>   COMMENT ON DATABASE my_database IS 'Development Database';
> + COMMENT ON DOMAIN my_domain IS 'Domains are like abstracted fields';

This comment describes domains in general, not a specific domain.

>   COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
>   COMMENT ON RULE my_rule IS 'Logs UPDATES of employee records';
>   COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
> ***************
> *** 155,166 ****
>      </programlisting>
>     </para>
>    </refsect1>
> !
>    <refsect1 id="R1-SQL-COMMENT-3">
>     <title>
>      Compatibility
>     </title>
> !
>     <refsect2 id="R2-SQL-COMMENT-4">
>      <refsect2info>
>       <date>1998-09-08</date>
> --- 156,167 ----
>      </programlisting>
>     </para>
>    </refsect1>
> !
>    <refsect1 id="R1-SQL-COMMENT-3">
>     <title>
>      Compatibility
>     </title>
> !
>     <refsect2 id="R2-SQL-COMMENT-4">
>      <refsect2info>
>       <date>1998-09-08</date>
> diff -rc pgsql.orig/doc/src/sgml/reference.sgml pgsqldomain/doc/src/sgml/reference.sgml
> *** pgsql.orig/doc/src/sgml/reference.sgml    Thu Mar  7 11:35:32 2002
> --- pgsqldomain/doc/src/sgml/reference.sgml    Thu Mar  7 22:24:23 2002
> ***************
> *** 61,66 ****
> --- 61,67 ----
>      &createAggregate;
>      &createConstraint;
>      &createDatabase;
> +    &createDomain;
>      &createFunction;
>      &createGroup;
>      &createIndex;
> ***************
> *** 78,83 ****
> --- 79,85 ----
>      &delete;
>      &dropAggregate;
>      &dropDatabase;
> +    &dropDomain;
>      &dropFunction;
>      &dropGroup;
>      &dropIndex;
> ***************
> *** 115,121 ****
>      &unlisten;
>      &update;
>      &vacuum;
> !
>    </reference>
>
>   <!--
> --- 117,123 ----
>      &unlisten;
>      &update;
>      &vacuum;
> !
>    </reference>
>
>   <!--
> diff -rc pgsql.orig/src/backend/catalog/heap.c pgsqldomain/src/backend/catalog/heap.c
> *** pgsql.orig/src/backend/catalog/heap.c    Thu Mar  7 11:35:33 2002
> --- pgsqldomain/src/backend/catalog/heap.c    Thu Mar  7 22:24:23 2002
> ***************
> *** 49,54 ****
> --- 49,55 ----
>   #include "optimizer/planmain.h"
>   #include "optimizer/prep.h"
>   #include "optimizer/var.h"
> + #include "parser/parse_coerce.h"
>   #include "parser/parse_expr.h"
>   #include "parser/parse_relation.h"
>   #include "parser/parse_target.h"
> ***************
> *** 698,707 ****
>                  "oidin",            /* receive procedure */
>                  "oidout",        /* send procedure */
>                  NULL,            /* array element type - irrelevant */
>                  NULL,            /* default type value - none */
>                  true,            /* passed by value */
>                  'i',                /* default alignment - same as for OID */
> !                'p');            /* Not TOASTable */
>   }
>
>   /* --------------------------------
> --- 699,713 ----
>                  "oidin",            /* receive procedure */
>                  "oidout",        /* send procedure */
>                  NULL,            /* array element type - irrelevant */
> +                NULL,            /* baseType Name -- typically for domaains */

spello

>                  NULL,            /* default type value - none */
> +                NULL,            /* default type binary representation */
>                  true,            /* passed by value */
>                  'i',                /* default alignment - same as for OID */
> !                'p',                /* Not TOASTable */
> !                -1,                /* Type mod length */
> !                0,                /* array dimensions for typBaseType */
> !                false);            /* Type NOT NULL */
>   }
>
>   /* --------------------------------
> ***************
> *** 1584,1589 ****
> --- 1590,1599 ----
>       int            numchecks;
>       List       *listptr;
>
> +     /* Probably shouldn't be null by default */
> +     Node       *expr = NULL;
> +
> +
>       /*
>        * Get info about existing constraints.
>        */
> ***************
> *** 1614,1681 ****
>       foreach(listptr, rawColDefaults)
>       {
>           RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
> -         Node       *expr;
> -         Oid            type_id;
>
> -         Assert(colDef->raw_default != NULL);
>
> !         /*
> !          * Transform raw parsetree to executable expression.
> !          */
> !         expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
>
> !         /*
> !          * Make sure default expr does not refer to any vars.
> !          */
> !         if (contain_var_clause(expr))
> !             elog(ERROR, "cannot use column references in DEFAULT clause");
> !
> !         /*
> !          * No subplans or aggregates, either...
> !          */
> !         if (contain_subplans(expr))
> !             elog(ERROR, "cannot use subselects in DEFAULT clause");
> !         if (contain_agg_clause(expr))
> !             elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
> !
> !         /*
> !          * Check that it will be possible to coerce the expression to the
> !          * column's type.  We store the expression without coercion,
> !          * however, to avoid premature coercion in cases like
> !          *
> !          * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
> !          *
> !          * NB: this should match the code in optimizer/prep/preptlist.c that
> !          * will actually do the coercion, to ensure we don't accept an
> !          * unusable default expression.
> !          */
> !         type_id = exprType(expr);
> !         if (type_id != InvalidOid)
> !         {
> !             Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
> !
> !             if (type_id != atp->atttypid)
> !             {
> !                 if (CoerceTargetExpr(NULL, expr, type_id,
> !                                   atp->atttypid, atp->atttypmod) == NULL)
> !                     elog(ERROR, "Column \"%s\" is of type %s"
> !                          " but default expression is of type %s"
> !                     "\n\tYou will need to rewrite or cast the expression",
> !                          NameStr(atp->attname),
> !                          format_type_be(atp->atttypid),
> !                          format_type_be(type_id));
> !             }
> !         }
> !
> !         /*
> !          * Might as well try to reduce any constant expressions.
> !          */
> !         expr = eval_const_expressions(expr);
> !
> !         /*
> !          * Must fix opids, in case any operators remain...
> !          */
> !         fix_opids(expr);
>
>           /*
>            * OK, store it.
> --- 1624,1636 ----
>       foreach(listptr, rawColDefaults)
>       {
>           RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
>
>
> !         Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
>
> !         expr = cookDefault(pstate, colDef->raw_default
> !                         , atp->atttypid, atp->atttypmod
> !                         , NameStr(atp->attname));
>
>           /*
>            * OK, store it.
> ***************
> *** 1891,1896 ****
> --- 1846,1933 ----
>       heap_freetuple(reltup);
>       heap_close(relrel, RowExclusiveLock);
>   }
> +
> + /*
> +  * Take a raw default and convert it to a cooked format ready for
> +  * storage.
> +  *
> +  * Parse state, attypid, attypmod and attname are required for
> +  * CoerceTargetExpr() and more importantly transformExpr().
> +  */
> + Node *
> + cookDefault(ParseState *pstate
> +             , Node *raw_default
> +             , Oid atttypid
> +             , int32 atttypmod
> +             , char *attname) {

Stick to the formatting please.

> +
> +     Oid            type_id;
> +     Node        *expr;
> +
> +     Assert(raw_default != NULL);
> +
> +     /*
> +      * Transform raw parsetree to executable expression.
> +      */
> +     expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
> +
> +     /*
> +      * Make sure default expr does not refer to any vars.
> +      */
> +     if (contain_var_clause(expr))
> +         elog(ERROR, "cannot use column references in DEFAULT clause");
> +
> +     /*
> +      * No subplans or aggregates, either...
> +      */
> +     if (contain_subplans(expr))
> +         elog(ERROR, "cannot use subselects in DEFAULT clause");
> +     if (contain_agg_clause(expr))
> +         elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
> +
> +     /*
> +      * Check that it will be possible to coerce the expression to the
> +      * column's type.  We store the expression without coercion,
> +      * however, to avoid premature coercion in cases like
> +      *
> +      * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
> +      *
> +      * NB: this should match the code in optimizer/prep/preptlist.c that
> +      * will actually do the coercion, to ensure we don't accept an
> +      * unusable default expression.
> +      */
> +     type_id = exprType(expr);
> +     if (type_id != InvalidOid && atttypid != InvalidOid) {
> +         if (type_id != atttypid) {
> +
> +             /* Try coercing to the base type of the domain if available */
> +             if (CoerceTargetExpr(pstate, expr, type_id,
> +                                  getBaseType(atttypid),
> +                                  atttypmod) == NULL) {
> +
> +                 elog(ERROR, "Column \"%s\" is of type %s"
> +                     " but default expression is of type %s"
> +                     "\n\tYou will need to rewrite or cast the expression",
> +                      attname,
> +                      format_type_be(atttypid),
> +                      format_type_be(type_id));
> +             }
> +         }
> +     }
> +
> +     /*
> +      * Might as well try to reduce any constant expressions.
> +      */
> +     expr = eval_const_expressions(expr);
> +
> +     /*
> +      * Must fix opids, in case any operators remain...
> +      */
> +     fix_opids(expr);
> +
> +     return(expr);
> + }
> +
>
>   static void
>   RemoveAttrDefaults(Relation rel)

> diff -rc pgsql.orig/src/backend/commands/creatinh.c pgsqldomain/src/backend/commands/creatinh.c
> *** pgsql.orig/src/backend/commands/creatinh.c    Thu Mar  7 11:35:34 2002
> --- pgsqldomain/src/backend/commands/creatinh.c    Thu Mar  7 23:16:06 2002
> ***************
> *** 39,45 ****
>   static void StoreCatalogInheritance(Oid relationId, List *supers);
>   static int    findAttrByName(const char *attributeName, List *schema);
>   static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
> !
>
>   /* ----------------------------------------------------------------
>    *        DefineRelation
> --- 39,45 ----
>   static void StoreCatalogInheritance(Oid relationId, List *supers);
>   static int    findAttrByName(const char *attributeName, List *schema);
>   static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
> ! static List *MergeDomainAttributes(List *schema);
>
>   /* ----------------------------------------------------------------
>    *        DefineRelation
> ***************
> *** 70,75 ****
> --- 70,82 ----
>       StrNCpy(relname, stmt->relname, NAMEDATALEN);
>
>       /*
> +      * Inherit domain attributes into the known columns before table inheritance
> +      * applies it's changes otherwise we risk adding double constraints
> +      * to a domain thats inherited.
> +      */
> +     schema = MergeDomainAttributes(schema);
> +
> +     /*
>        * Look up inheritance ancestors and generate relation schema,
>        * including inherited attributes.
>        */
> ***************
> *** 235,240 ****
> --- 242,307 ----
>   {
>       AssertArg(name);
>       heap_truncate(name);
> + }
> +
> +
> + /*
> +  * MergeDomainAttributes
> +  *      Returns a new table schema with the constraints, types, and other
> +  *      attributes of the domain resolved for fields using the domain as
> +  *        their type.

I didn't know we had schemas yet.  You should probably not overload that
term to mean "a list of database objects".

> +  *
> +  * Defaults are pulled out by the table attribute as required, similar to
> +  * how all types defaults are processed.
> +  */
> + static List *
> + MergeDomainAttributes(List *schema)
> + {
> +     List       *entry;
> +
> +     /*
> +      * Loop through the table elements supplied. These should
> +      * never include inherited domains else they'll be
> +      * double (or more) processed.
> +      */
> +     foreach(entry, schema)
> +     {
> +         ColumnDef  *coldef = lfirst(entry);
> +         HeapTuple  tuple;
> +         Form_pg_type typeTup;
> +
> +
> +         tuple = SearchSysCache(TYPENAME,
> +                                CStringGetDatum(coldef->typename->name),
> +                                0,0,0);
> +
> +         if (!HeapTupleIsValid(tuple))
> +             elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
> +                  coldef->typename->name);
> +
> +         typeTup = (Form_pg_type) GETSTRUCT(tuple);
> +         if (typeTup->typtype == 'd') {
> +             /*
> +              * This is a domain, lets force the properties of the domain on to
> +              * the new column.
> +              */
> +
> +             /* Enforce the typmod value */
> +             coldef->typename->typmod = typeTup->typmod;
> +
> +             /* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
> +             coldef->is_not_null |= typeTup->typnotnull;
> +
> +             /* Enforce the element type in the event the domain is an array
> +              *
> +              * BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
> +              */
> +
> +         }
> +         ReleaseSysCache(tuple);
> +     }
> +
> +     return schema;
>   }
>
>   /*----------
> diff -rc pgsql.orig/src/backend/commands/define.c pgsqldomain/src/backend/commands/define.c
> *** pgsql.orig/src/backend/commands/define.c    Thu Mar  7 11:35:34 2002
> --- pgsqldomain/src/backend/commands/define.c    Thu Mar  7 22:24:23 2002
> ***************
> *** 40,45 ****
> --- 40,46 ----
>
>   #include "access/heapam.h"
>   #include "catalog/catname.h"
> + #include "catalog/heap.h"
>   #include "catalog/pg_aggregate.h"
>   #include "catalog/pg_language.h"
>   #include "catalog/pg_operator.h"
> ***************
> *** 476,481 ****
> --- 477,798 ----
>   }
>
>   /*
> +  * DefineDomain
> +  *        Registers a new domain.
> +  */
> + void
> + DefineDomain(CreateDomainStmt *stmt)
> + {
> +     int16        internalLength = -1;    /* int2 */
> +     int16        externalLength = -1;    /* int2 */
> +     char       *inputName = NULL;
> +     char       *outputName = NULL;
> +     char       *sendName = NULL;
> +     char       *receiveName = NULL;
> +
> +     /*
> +      * Domains store the external representation in defaultValue
> +      * and the interal Node representation in defaultValueBin
> +      */
> +     char       *defaultValue = NULL;
> +     char       *defaultValueBin = NULL;
> +
> +     bool        byValue = false;
> +     char        delimiter = DEFAULT_TYPDELIM;
> +     char        alignment = 'i';    /* default alignment */
> +     char        storage = 'p';    /* default TOAST storage method */
> +     char        typtype;
> +     Datum        datum;
> +     bool        typNotNull = false;
> +     char        *elemName = NULL;
> +     int32        typNDims = 0;    /* No array dimensions by default */
> +
> +     bool        isnull;
> +     Relation    pg_type_rel;
> +     TupleDesc    pg_type_dsc;
> +     HeapTuple    typeTup;
> +     char       *typeName = stmt->typename->name;
> +
> +     List       *listptr;
> +     List       *schema = stmt->constraints;
> +
> +     /*
> +      * Domainnames, unlike typenames don't need to account for the '_'
> +      * prefix.  So they can be one character longer.
> +      */
> +     if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
> +         elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
> +              NAMEDATALEN - 1);
> +
> +
> +     /* Test for existing Domain (or type) of that name */
> +     typeTup = SearchSysCache( TYPENAME
> +                             , PointerGetDatum(stmt->domainname)
> +                             , 0, 0, 0
> +                             );
> +
> +     if (HeapTupleIsValid(typeTup))
> +     {
> +         elog(ERROR, "CREATE DOMAIN: domain or type  %s already exists",
> +              stmt->domainname);
> +     }
> +
> +     /*
> +      * Get the information about old types
> +      */
> +     pg_type_rel = heap_openr(TypeRelationName, RowExclusiveLock);
> +     pg_type_dsc = RelationGetDescr(pg_type_rel);
> +
> +
> +     /*
> +      * When the type is an array for some reason we don't actually receive
> +      * the name here.  We receive the base types name.  Lets set Dims while
> +      * were at it.
> +      */
> +     if (stmt->typename->arrayBounds > 0) {
> +         typeName = makeArrayTypeName(stmt->typename->name);
> +
> +         typNDims = length(stmt->typename->arrayBounds);
> +     }
> +
> +
> +     typeTup = SearchSysCache( TYPENAME
> +                             , PointerGetDatum(typeName)
> +                             , 0, 0, 0
> +                             );
> +
> +     if (!HeapTupleIsValid(typeTup))
> +     {
> +         elog(ERROR, "CREATE DOMAIN: type %s does not exist",
> +              stmt->typename->name);
> +     }
> +
> +
> +     /* Check that this is a basetype */
> +     typtype = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typtype, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /*
> +      * What we really don't want is domains of domains.  This could cause all sorts
> +      * of neat issues if we allow that.
> +      *
> +      * With testing, we may determine complex types should be allowed
> +      */
> +     if (typtype != 'b') {
> +         elog(ERROR, "DefineDomain: %s is not a basetype", stmt->typename->name);
> +     }
> +
> +     /* passed by value */
> +     byValue =             DatumGetBool(heap_getattr(typeTup, Anum_pg_type_typbyval, pg_type_dsc, &isnull));
> +     Assert(!isnull);

You don't have to use heap_getattr here.  You can use

    byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval

Same for all the other ones that are fixed-length.

> +
> +     /* Required Alignment */
> +     alignment =         DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typalign, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /* Storage Length */
> +     internalLength =     DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typlen, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /* External Length (unused) */
> +     externalLength =     DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typprtlen, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /* Array element Delimiter */
> +     delimiter =         DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typdelim, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /* Input Function Name */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typinput, pg_type_dsc, &isnull);
> +     Assert(!isnull);
> +
> +     inputName =         DatumGetCString(DirectFunctionCall1(regprocout, datum));
> +
> +     /* Output Function Name */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typoutput, pg_type_dsc, &isnull);
> +     Assert(!isnull);
> +
> +     outputName =         DatumGetCString(DirectFunctionCall1(regprocout, datum));
> +
> +     /* ReceiveName */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typreceive, pg_type_dsc, &isnull);
> +     Assert(!isnull);
> +
> +     receiveName =         DatumGetCString(DirectFunctionCall1(regprocout, datum));
> +
> +     /* SendName */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typsend, pg_type_dsc, &isnull);
> +     Assert(!isnull);
> +
> +     sendName =             DatumGetCString(DirectFunctionCall1(regprocout, datum));
> +
> +     /* TOAST Strategy */
> +     storage =             DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typstorage, pg_type_dsc, &isnull));
> +     Assert(!isnull);
> +
> +     /* Inherited default value */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typdefault, pg_type_dsc, &isnull);
> +     if (!isnull) {
> +         defaultValue =     DatumGetCString(DirectFunctionCall1(textout, datum));
> +     }
> +
> +     /*
> +      * Pull out the typelem name of the parent OID.
> +      *
> +      * This is what enables us to make a domain of an array
> +      */
> +     datum =             heap_getattr(typeTup, Anum_pg_type_typelem, pg_type_dsc, &isnull);
> +     Assert(!isnull);
> +
> +     if (DatumGetObjectId(datum) != InvalidOid) {
> +         HeapTuple tup;
> +
> +         tup = SearchSysCache( TYPEOID
> +                             , datum
> +                             , 0, 0, 0
> +                             );
> +
> +         elemName = NameStr(((Form_pg_type) GETSTRUCT(tup))->typname);
> +
> +         ReleaseSysCache(tup);
> +     }
> +
> +
> +     /*
> +      * Run through constraints manually avoids the additional
> +      * processing conducted by DefineRelation() and friends.
> +      *
> +      * Besides, we don't want any constraints to be cooked.  We'll
> +      * do that when the table is created via MergeDomainAttributes().
> +      */
> +     foreach(listptr, schema)
> +     {
> +         bool nullDefined = false;
> +         Node       *expr;
> +         Constraint *colDef = lfirst(listptr);
> +
> +         /* Used for the statement transformation */
> +         ParseState *pstate;
> +
> +         /*
> +          * Create a dummy ParseState and insert the target relation as its
> +          * sole rangetable entry.  We need a ParseState for transformExpr.
> +          */
> +         pstate = make_parsestate(NULL);
> +
> +         switch(colDef->contype) {
> +             /*
> +               * The inherited default value may be overridden by the user
> +              * with the DEFAULT <expr> statement.
> +              *
> +               * We have to search the entire constraint tree returned as we
> +              * don't want to cook or fiddle too much.
> +              */
> +             case CONSTR_DEFAULT:
> +
> +                 /*
> +                  * Cook the colDef->raw_expr into an expression to ensure
> +                  * that it can be done.  We store the text version of the
> +                  * raw value.
> +                  *
> +                  * Note: Name is strictly for error message
> +                  */
> +                 expr = cookDefault(pstate, colDef->raw_expr
> +                                 , typeTup->t_data->t_oid
> +                                 , stmt->typename->typmod
> +                                 , stmt->typename->name);
> +
> +                 /* Binary default required */
> +                 defaultValue = deparse_expression(expr,
> +                                 deparse_context_for(stmt->domainname,
> +                                                     InvalidOid),
> +                                                    false);
> +
> +                 defaultValueBin = nodeToString(expr);
> +
> +                 break;
> +
> +             /*
> +              * Find the NULL constraint.
> +              */
> +             case CONSTR_NOTNULL:
> +                 if (nullDefined) {
> +                     elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
> +                 } else {
> +                     typNotNull = true;
> +                     nullDefined = true;
> +                 }
> +
> +                   break;
> +
> +             case CONSTR_NULL:
> +                 if (nullDefined) {
> +                     elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
> +                 } else {
> +                     typNotNull = false;
> +                     nullDefined = true;
> +                 }
> +
> +                   break;
> +
> +               case CONSTR_UNIQUE:
> +                   elog(ERROR, "CREATE DOMAIN / UNIQUE indecies not supported");
> +                   break;
> +
> +               case CONSTR_PRIMARY:
> +                   elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indecies not supported");
> +                   break;
> +
> +
> +               case CONSTR_CHECK:
> +
> +                   elog(ERROR, "defineDomain: CHECK Constraints not supported");
> +                   break;
> +
> +               case CONSTR_ATTR_DEFERRABLE:
> +               case CONSTR_ATTR_NOT_DEFERRABLE:
> +               case CONSTR_ATTR_DEFERRED:
> +               case CONSTR_ATTR_IMMEDIATE:
> +                   elog(ERROR, "defineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
> +                   break;
> +         }
> +
> +     }
> +
> +     /*
> +      * Have TypeCreate do all the real work.
> +      */
> +     TypeCreate(stmt->domainname,    /* type name */
> +                InvalidOid,            /* preassigned type oid (not done here) */
> +                InvalidOid,            /* relation oid (n/a here) */
> +                internalLength,        /* internal size */
> +                externalLength,        /* external size */
> +                'd',                    /* type-type (domain type) */
> +                delimiter,            /* array element delimiter */
> +                inputName,            /* input procedure */
> +                outputName,            /* output procedure */
> +                receiveName,            /* receive procedure */
> +                sendName,            /* send procedure */
> +                elemName,            /* element type name */
> +                typeName,            /* base type name */
> +                defaultValue,        /* default type value */
> +                defaultValueBin,        /* default type value */
> +                byValue,                /* passed by value */
> +                alignment,            /* required alignment */
> +                storage,                /* TOAST strategy */
> +                stmt->typename->typmod, /* typeMod value */
> +                typNDims,            /* Array dimensions for base type */
> +                typNotNull);    /* Type NOT NULL */
> +
> +     /*
> +      * Now we can clean up.
> +      */
> +     ReleaseSysCache(typeTup);
> +     heap_close(pg_type_rel, NoLock);
> + }
> +
> +
> + /*
>    * DefineType
>    *        Registers a new type.
>    */
> ***************
> *** 490,495 ****
> --- 807,814 ----
>       char       *sendName = NULL;
>       char       *receiveName = NULL;
>       char       *defaultValue = NULL;
> +     char       *defaultValueBin = NULL;
> +     Node       *defaultRaw = (Node *) NULL;
>       bool        byValue = false;
>       char        delimiter = DEFAULT_TYPDELIM;
>       char       *shadow_type;
> ***************
> *** 531,537 ****
>           else if (strcasecmp(defel->defname, "element") == 0)
>               elemName = defGetString(defel);
>           else if (strcasecmp(defel->defname, "default") == 0)
> !             defaultValue = defGetString(defel);
>           else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
>               byValue = true;
>           else if (strcasecmp(defel->defname, "alignment") == 0)
> --- 850,856 ----
>           else if (strcasecmp(defel->defname, "element") == 0)
>               elemName = defGetString(defel);
>           else if (strcasecmp(defel->defname, "default") == 0)
> !             defaultRaw = defel->arg;
>           else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
>               byValue = true;
>           else if (strcasecmp(defel->defname, "alignment") == 0)
> ***************
> *** 591,596 ****
> --- 910,941 ----
>       if (outputName == NULL)
>           elog(ERROR, "Define: \"output\" unspecified");
>
> +
> +     if (defaultRaw) {
> +         Node   *expr;
> +         ParseState *pstate;
> +
> +         /*
> +          * Create a dummy ParseState and insert the target relation as its
> +          * sole rangetable entry.  We need a ParseState for transformExpr.
> +          */
> +         pstate = make_parsestate(NULL);
> +
> +         expr = cookDefault(pstate, defaultRaw,
> +                            InvalidOid,
> +                            -1,
> +                            typeName);
> +
> +         /* Binary default required */
> +         defaultValue = deparse_expression(expr,
> +                         deparse_context_for(typeName,
> +                                             InvalidOid),
> +                                            false);
> +
> +         defaultValueBin = nodeToString(expr);
> +     }
> +
> +
>       /*
>        * now have TypeCreate do all the real work.
>        */
> ***************
> *** 606,615 ****
>                  receiveName,        /* receive procedure */
>                  sendName,        /* send procedure */
>                  elemName,        /* element type name */
>                  defaultValue,    /* default type value */
>                  byValue,            /* passed by value */
>                  alignment,        /* required alignment */
> !                storage);        /* TOAST strategy */
>
>       /*
>        * When we create a base type (as opposed to a complex type) we need
> --- 951,965 ----
>                  receiveName,        /* receive procedure */
>                  sendName,        /* send procedure */
>                  elemName,        /* element type name */
> +                NULL,            /* base type name (Non-zero for domains) */
>                  defaultValue,    /* default type value */
> +                defaultValueBin,    /* default type value (Binary form) */
>                  byValue,            /* passed by value */
>                  alignment,        /* required alignment */
> !                storage,            /* TOAST strategy */
> !                -1,                /* typMod (Domains only) */
> !                0,                /* Array Dimensions of typbasetype */
> !                'f');            /* Type NOT NULL */
>
>       /*
>        * When we create a base type (as opposed to a complex type) we need
> ***************
> *** 632,641 ****
>                  "array_in",        /* receive procedure */
>                  "array_out",        /* send procedure */
>                  typeName,        /* element type name */
>                  NULL,            /* never a default type value */
>                  false,            /* never passed by value */
>                  alignment,        /* see above */
> !                'x');            /* ARRAY is always toastable */
>
>       pfree(shadow_type);
>   }
> --- 982,996 ----
>                  "array_in",        /* receive procedure */
>                  "array_out",        /* send procedure */
>                  typeName,        /* element type name */
> +                NULL,            /* base type name */
>                  NULL,            /* never a default type value */
> +                NULL,            /* binary default isn't sent either */
>                  false,            /* never passed by value */
>                  alignment,        /* see above */
> !                'x',                /* ARRAY is always toastable */
> !                -1,                /* typMod (Domains only) */
> !                0,                /* Array dimensions of typbasetype */
> !                'f');            /* Type NOT NULL */
>
>       pfree(shadow_type);
>   }

> diff -rc pgsql.orig/src/backend/nodes/copyfuncs.c pgsqldomain/src/backend/nodes/copyfuncs.c
> *** pgsql.orig/src/backend/nodes/copyfuncs.c    Thu Mar  7 11:35:34 2002
> --- pgsqldomain/src/backend/nodes/copyfuncs.c    Thu Mar  7 22:53:19 2002
> ***************
> *** 2227,2232 ****
> --- 2227,2247 ----
>       return newnode;
>   }
>
> + static CreateDomainStmt *
> + _copyCreateDomainStmt(CreateDomainStmt *from)
> + {
> +     CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
> +
> +     if (from->domainname)
> +         newnode->domainname = pstrdup(from->domainname);
> +     if (from->typename)
> +         newnode->typename = from->typename;

That's not a copy.

> +     if (from->constraints)
> +         newnode->constraints = from->constraints;
> +
> +     return newnode;
> + }
> +
>   static CreatedbStmt *
>   _copyCreatedbStmt(CreatedbStmt *from)
>   {
> ***************
> *** 3026,3031 ****
> --- 3041,3049 ----
>               break;
>           case T_FuncWithArgs:
>               retval = _copyFuncWithArgs(from);
> +             break;
> +         case T_CreateDomainStmt:
> +             retval = _copyCreateDomainStmt(from);
>               break;
>
>           default:

> diff -rc pgsql.orig/src/backend/parser/gram.y pgsqldomain/src/backend/parser/gram.y
> *** pgsql.orig/src/backend/parser/gram.y    Thu Mar  7 11:35:35 2002
> --- pgsqldomain/src/backend/parser/gram.y    Thu Mar  7 22:34:00 2002
> ***************
> *** 97,103 ****
>
>   %}
>
> -
>   %union
>   {
>       int                    ival;
> --- 97,102 ----
> ***************
> *** 135,141 ****
>           ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
>           CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
>           CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
> !         CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
>           DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
>           DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
>           GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
> --- 134,141 ----
>           ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
>           CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
>           CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
> !         CreateUserStmt, CreateDomainStmt, CreatedbStmt, CursorStmt,

Alphabetical order?

> !         DefineStmt, DeleteStmt,
>           DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
>           DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
>           GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
> ***************
> *** 289,294 ****
> --- 289,296 ----
>   %type <list>    constraints_set_namelist
>   %type <boolean>    constraints_set_mode
>
> + %type <boolean> opt_as
> +
>   /*
>    * If you make any token changes, remember to:
>    *        - use "yacc -d" and update parse.h
> ***************
> *** 343,349 ****
>           WITHOUT
>
>   /* Keywords (in SQL92 non-reserved words) */
> ! %token    COMMITTED, SERIALIZABLE, TYPE_P
>
>   /* Keywords for Postgres support (not in SQL92 reserved words)
>    *
> --- 345,351 ----
>           WITHOUT
>
>   /* Keywords (in SQL92 non-reserved words) */
> ! %token    COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P
>
>   /* Keywords for Postgres support (not in SQL92 reserved words)
>    *
> ***************
> *** 446,451 ****
> --- 448,454 ----
>           | CopyStmt
>           | CreateStmt
>           | CreateAsStmt
> +         | CreateDomainStmt
>           | CreateSchemaStmt
>           | CreateGroupStmt
>           | CreateSeqStmt
> ***************
> *** 776,783 ****
> --- 779,789 ----
>                       n->dbname = $3;
>                       $$ = (Node *)n;
>                   }
> +         ;
>
>
> +
> +
>   /*****************************************************************************
>    *
>    * Set PG internal variable
> ***************
> *** 1461,1467 ****
>                       n->name = NULL;
>                       if (exprIsNullConstant($2))
>                       {
> !                         /* DEFAULT NULL should be reported as empty expr */
>                           n->raw_expr = NULL;
>                       }
>                       else
> --- 1467,1476 ----
>                       n->name = NULL;
>                       if (exprIsNullConstant($2))
>                       {
> !                         /*
> !                          * DEFAULT NULL should be reported as empty expr
> !                          * Required for NOT NULL Domain overrides
> !                          */
>                           n->raw_expr = NULL;
>                       }
>                       else
> ***************
> *** 2043,2055 ****
>           | def_list ',' def_elem                { $$ = lappend($1, $3); }
>           ;
>
> ! def_elem:  ColLabel '=' def_arg
>                   {
>                       $$ = makeNode(DefElem);
>                       $$->defname = $1;
>                       $$->arg = (Node *)$3;
>                   }
> !         | ColLabel
>                   {
>                       $$ = makeNode(DefElem);
>                       $$->defname = $1;
> --- 2052,2073 ----
>           | def_list ',' def_elem                { $$ = lappend($1, $3); }
>           ;
>
> ! def_elem:  DEFAULT '=' c_expr
> !                 {
> !                     $$ = makeNode(DefElem);
> !                     $$->defname = "default";
> !                     if (exprIsNullConstant($3))
> !                         $$->arg = (Node *)NULL;
> !                     else
> !                         $$->arg = $3;
> !                 }
> !         | ColId '=' def_arg
>                   {
>                       $$ = makeNode(DefElem);
>                       $$->defname = $1;
>                       $$->arg = (Node *)$3;
>                   }
> !         | ColId
>                   {
>                       $$ = makeNode(DefElem);
>                       $$->defname = $1;
> ***************
> *** 2078,2083 ****
> --- 2096,2110 ----
>                       DropStmt *n = makeNode(DropStmt);
>                       n->removeType = $2;
>                       n->names = $3;
> +                     n->behavior = RESTRICT;        /* Restricted by default */
> +                     $$ = (Node *)n;
> +                 }
> +         | DROP DOMAIN_P name_list drop_behavior
> +                 {
> +                     DropStmt *n = makeNode(DropStmt);
> +                     n->removeType = DROP_DOMAIN_P;
> +                     n->names = $3;
> +                     n->behavior = $4;
>                       $$ = (Node *)n;
>                   }
>           ;
> ***************
> *** 2110,2116 ****
>    *  The COMMENT ON statement can take different forms based upon the type of
>    *  the object associated with the comment. The form of the statement is:
>    *
> !  *  COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
>    *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
>    *         <funcname> (arg1, arg2, ...) | OPERATOR <op>
>    *         (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
> --- 2137,2143 ----
>    *  The COMMENT ON statement can take different forms based upon the type of
>    *  the object associated with the comment. The form of the statement is:
>    *
> !  *  COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
>    *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
>    *         <funcname> (arg1, arg2, ...) | OPERATOR <op>
>    *         (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
> ***************
> *** 2196,2201 ****
> --- 2223,2229 ----
>           | RULE { $$ = RULE; }
>           | SEQUENCE { $$ = SEQUENCE; }
>           | TABLE { $$ = TABLE; }
> +         | DOMAIN_P { $$ = TYPE_P; }
>           | TYPE_P { $$ = TYPE_P; }
>           | VIEW { $$ = VIEW; }
>           ;
> ***************
> *** 3178,3183 ****
> --- 3206,3227 ----
>                   {
>                       $$ = lconsi(3, makeListi1(-1));
>                   }
> +         ;
> +
> +
> + /*****************************************************************************
> +  *
> +  *        DROP DATABASE
> +  *
> +  *
> +  *****************************************************************************/
> +
> + DropdbStmt:    DROP DATABASE database_name
> +                 {
> +                     DropdbStmt *n = makeNode(DropdbStmt);
> +                     n->dbname = $3;
> +                     $$ = (Node *)n;
> +                 }
>           | OWNER opt_equal name
>                   {
>                       $$ = lconsi(4, makeList1($3));

This doesn't look right.

> ***************
> *** 3222,3243 ****
>                   }
>           ;
>
> -
>   /*****************************************************************************
>    *
> !  *        DROP DATABASE
>    *
>    *
>    *****************************************************************************/
>
> ! DropdbStmt:    DROP DATABASE database_name
>                   {
> !                     DropdbStmt *n = makeNode(DropdbStmt);
> !                     n->dbname = $3;
>                       $$ = (Node *)n;
>                   }
>           ;
>
>
>   /*****************************************************************************
>    *
> --- 3266,3295 ----
>                   }
>           ;
>
>   /*****************************************************************************
>    *
> !  * Manipulate a domain
>    *
>    *
>    *****************************************************************************/
>
> ! CreateDomainStmt:  CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
>                   {
> !                     CreateDomainStmt *n = makeNode(CreateDomainStmt);
> !                     n->domainname = $3;
> !                     n->typename = $5;
> !                     n->constraints = $6;
> !
> !                     if ($7 != NULL)
> !                         elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
> !                             "implemented; clause ignored", $7);
>                       $$ = (Node *)n;
>                   }
>           ;
>
> + opt_as:    AS    {$$ = TRUE; }
> +     | /* EMPTY */    {$$ = FALSE; }
> +     ;
>
>   /*****************************************************************************
>    *
> ***************
> *** 5879,5884 ****
> --- 5931,5937 ----
>           | DEFERRED                        { $$ = "deferred"; }
>           | DELETE                        { $$ = "delete"; }
>           | DELIMITERS                    { $$ = "delimiters"; }
> +         | DOMAIN_P                        { $$ = "domain"; }
>           | DOUBLE                        { $$ = "double"; }
>           | DROP                            { $$ = "drop"; }
>           | EACH                            { $$ = "each"; }

> diff -rc pgsql.orig/src/backend/parser/parse_coerce.c pgsqldomain/src/backend/parser/parse_coerce.c
> *** pgsql.orig/src/backend/parser/parse_coerce.c    Thu Mar  7 11:35:35 2002
> --- pgsqldomain/src/backend/parser/parse_coerce.c    Thu Mar  7 22:24:24 2002
> ***************
> *** 38,43 ****
> --- 38,44 ----
>   {
>       Node       *result;
>
> +

No.

>       if (targetTypeId == inputTypeId ||
>           targetTypeId == InvalidOid ||
>           node == NULL)
> ***************
> *** 605,607 ****
> --- 606,637 ----
>       }
>       return result;
>   }    /* PreferredType() */
> +
> +
> + /*
> +  * If the targetTypeId is a domain, we really want to coerce
> +  * the tuple to the domain type -- not the domain itself
> +  */
> + Oid
> + getBaseType(Oid inType)
> + {
> +     HeapTuple    tup;
> +     Form_pg_type typTup;
> +
> +     tup = SearchSysCache(TYPEOID,
> +                          ObjectIdGetDatum(inType),
> +                          0, 0, 0);
> +
> +     typTup = ((Form_pg_type) GETSTRUCT(tup));
> +
> +     /*
> +      * Assume that typbasetype exists and is a base type, where inType
> +      * was a domain
> +      */
> +     if (typTup->typtype == 'd')
> +         inType = typTup->typbasetype;
> +
> +     ReleaseSysCache(tup);
> +
> +     return inType;
> + }

> diff -rc pgsql.orig/src/backend/tcop/postgres.c pgsqldomain/src/backend/tcop/postgres.c
> *** pgsql.orig/src/backend/tcop/postgres.c    Wed Mar  6 01:10:09 2002
> --- pgsqldomain/src/backend/tcop/postgres.c    Thu Mar  7 22:24:24 2002
> ***************
> *** 2212,2217 ****
> --- 2212,2218 ----
>               }
>               break;
>
> +         case T_CreateDomainStmt:
>           case T_CreateStmt:
>               tag = "CREATE";
>               break;

The result tag for CREATE DOMAIN is CREATE DOMAIN.  (Yes, there's actually
a standard about this.)

--
Peter Eisentraut   peter_e@gmx.net


Re: Domain Support -- another round

From
"Rod Taylor"
Date:
New set with most of Peters comments corrected.  Left the deal about
schema though :)  Took nearly an hour to do a cvs diff for some reason
this time (normally a couple of minutes is enough).

> Random nitpicking below.  Also, have you created a regression test?

They had been posted a few times and haven't changed.  (Attached
anyway)


> > +    <structfield>typnotnull</structfield> represents a NOT NULL
> > +    constraint on a type.  Normally used only for domains.
>
> And unnormally...?

Unnormally is when someone sets it by hand on a type which isn't a
domain -- I guess.  Corrected.

> > + <!entity createDomain       system "create_domain.sgml">
>
> I don't see this file included.

Other messages.  Full package included on this one however.



> > +  * MergeDomainAttributes
> > +  *      Returns a new table schema with the constraints, types,
and other
> > +  *      attributes of the domain resolved for fields using the
domain as
> > +  * their type.
>
> I didn't know we had schemas yet.  You should probably not overload
that
> term to mean "a list of database objects".

Merge attributes says something very similar about inheritance and
table schemas.  Kinda correct considering
the variable used in both cases is *schema.


The diff weirdness in regards to DROP DATABASE is probably because I
started by copying the DROP DATABASE element, then altered it.  I
don't know why it chose that method to do the diff though, but it is
accurate.  Using -cd flags didn't make it any prettier.

Attachment

Re: Domain Support -- another round

From
Bruce Momjian
Date:
Removed, superceeded by new versions.

---------------------------------------------------------------------------

Rod Taylor wrote:
> Attached is a diff to the patch of the below message to use b_expr
> rather than c_expr.
>
> Also includes an improved regress set.  Less redundant failures, and
> tests numeric types as they're different from the others enough to
> warrent it.
> --
> Rod Taylor
>
> This message represents the official view of the voices in my head
>
> ----- Original Message -----
> From: "Rod Taylor" <rbt@zort.ca>
> To: <pgsql-patches@postgresql.org>
> Sent: Thursday, March 07, 2002 11:21 PM
> Subject: [PATCHES] Domain Support -- another round
>
>
> > Ok....
> >
> > gram.y is fixed (no more %expect usage)
> >
> > Using the copyCreateDomainStmt in the proper place.
> >
> > Evolution is the mail client of choice for different (improved?)
> mime
> > headers.
> >
> > And attached is a regular diff -c, rather than a cvs diff -c.
> >
> >
> > I updated the poor descriptions of MergeDomainAttributes().
> Hopefully
> > its current and future use is more obvious.
> >
> >
> > Am I getting close?
> >
> >
>
>
> ----------------------------------------------------------------------
> ----------
>
>
> >
> > ---------------------------(end of
> broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to
> majordomo@postgresql.org)
> >

[ Attachment, skipping... ]

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Domain Support -- another round

From
Bruce Momjian
Date:
Your patch has been added to the PostgreSQL unapplied patches list at:

    http://candle.pha.pa.us/cgi-bin/pgpatches

I will try to apply it within the next 48 hours.

---------------------------------------------------------------------------


Rod Taylor wrote:
> New set with most of Peters comments corrected.  Left the deal about
> schema though :)  Took nearly an hour to do a cvs diff for some reason
> this time (normally a couple of minutes is enough).
>
> > Random nitpicking below.  Also, have you created a regression test?
>
> They had been posted a few times and haven't changed.  (Attached
> anyway)
>
>
> > > +    <structfield>typnotnull</structfield> represents a NOT NULL
> > > +    constraint on a type.  Normally used only for domains.
> >
> > And unnormally...?
>
> Unnormally is when someone sets it by hand on a type which isn't a
> domain -- I guess.  Corrected.
>
> > > + <!entity createDomain       system "create_domain.sgml">
> >
> > I don't see this file included.
>
> Other messages.  Full package included on this one however.
>
>
>
> > > +  * MergeDomainAttributes
> > > +  *      Returns a new table schema with the constraints, types,
> and other
> > > +  *      attributes of the domain resolved for fields using the
> domain as
> > > +  * their type.
> >
> > I didn't know we had schemas yet.  You should probably not overload
> that
> > term to mean "a list of database objects".
>
> Merge attributes says something very similar about inheritance and
> table schemas.  Kinda correct considering
> the variable used in both cases is *schema.
>
>
> The diff weirdness in regards to DROP DATABASE is probably because I
> started by copying the DROP DATABASE element, then altered it.  I
> don't know why it chose that method to do the diff though, but it is
> accurate.  Using -cd flags didn't make it any prettier.

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Domain Support -- another round

From
Bruce Momjian
Date:
Patch applied.  I am attaching the expected/domain.out file that I
generated when I added your domain test file to the regression tests.
Please verify that the output is correct.  Thanks.

---------------------------------------------------------------------------

Rod Taylor wrote:
> New set with most of Peters comments corrected.  Left the deal about
> schema though :)  Took nearly an hour to do a cvs diff for some reason
> this time (normally a couple of minutes is enough).
>
> > Random nitpicking below.  Also, have you created a regression test?
>
> They had been posted a few times and haven't changed.  (Attached
> anyway)
>
>
> > > +    <structfield>typnotnull</structfield> represents a NOT NULL
> > > +    constraint on a type.  Normally used only for domains.
> >
> > And unnormally...?
>
> Unnormally is when someone sets it by hand on a type which isn't a
> domain -- I guess.  Corrected.
>
> > > + <!entity createDomain       system "create_domain.sgml">
> >
> > I don't see this file included.
>
> Other messages.  Full package included on this one however.
>
>
>
> > > +  * MergeDomainAttributes
> > > +  *      Returns a new table schema with the constraints, types,
> and other
> > > +  *      attributes of the domain resolved for fields using the
> domain as
> > > +  * their type.
> >
> > I didn't know we had schemas yet.  You should probably not overload
> that
> > term to mean "a list of database objects".
>
> Merge attributes says something very similar about inheritance and
> table schemas.  Kinda correct considering
> the variable used in both cases is *schema.
>
>
> The diff weirdness in regards to DROP DATABASE is probably because I
> started by copying the DROP DATABASE element, then altered it.  I
> don't know why it chose that method to do the diff though, but it is
> accurate.  Using -cd flags didn't make it any prettier.

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

[ Attachment, skipping... ]

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
-- Test Comment / Drop
create domain domaindroptest int4;
comment on domain domaindroptest is 'About to drop this..';
create domain basetypetest domaindroptest;
ERROR:  DefineDomain: domaindroptest is not a basetype
drop domain domaindroptest;
ERROR:  parser: parse error at or near ";"
drop domain domaindroptest restrict;
-- TEST Domains.
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test tables using domains
create table basictest
           ( testint4 domainint4
           , testtext domaintext
           , testvarchar domainvarchar
           , testnumeric domainnumeric
           );
INSERT INTO basictest values ('88', 'haha', 'short', '123.12');      -- Good
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
ERROR:  value too long for type character varying(5)
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212');    -- Truncate numeric
select * from basictest;
 testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
 88       | haha     | short       | 123.12
 88       | haha     | short       | 123.12
(2 rows)

drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext restrict;
-- Array Test
create domain domainint4arr int4[1];
create domain domaintextarr text[2][3];
create table domarrtest
           ( testint4arr domainint4arr
           , testtextarr domaintextarr
            );
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
INSERT INTO domarrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}{"e"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a"}{"c"}}');
INSERT INTO domarrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
drop table domarrtest;
drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull    varchar(15) NULL;
create table nulltest
           ( col1 dnotnull
           , col2 dnotnull NULL  -- NOT NULL in the domain cannot be overridden
           , col3 dnull    NOT NULL
           , col4 dnull
           );
INSERT INTO nulltest DEFAULT VALUES;
ERROR:  ExecAppend: Fail to add null value in not null attribute col1
INSERT INTO nulltest values ('a', 'b', 'c', 'd');  -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
ERROR:  ExecAppend: Fail to add null value in not null attribute col1
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
ERROR:  ExecAppend: Fail to add null value in not null attribute col2
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
ERROR:  ExecAppend: Fail to add null value in not null attribute col3
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
select * from nulltest;
 col1 | col2 | col3 | col4
------+------+------+------
 a    | b    | c    | d
 a    | b    | c    |
(2 rows)

drop table nulltest;
drop domain dnotnull restrict;
drop domain dnull restrict;
create domain ddef1 int4 DEFAULT 3;
create domain ddef2 oid DEFAULT '12';
-- Type mixing, function returns int8
create domain ddef3 text DEFAULT 5;
create sequence ddef4_seq;
create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
create table defaulttest
            ( col1 ddef1
            , col2 ddef2
            , col3 ddef3
            , col4 ddef4
            , col5 ddef1 NOT NULL DEFAULT NULL
            , col6 ddef2 DEFAULT '88'
            , col7 ddef4 DEFAULT 8000
        , col8 ddef5
            );
insert into defaulttest default values;
insert into defaulttest default values;
insert into defaulttest default values;
select * from defaulttest;
 col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
------+------+------+------+------+------+------+-------
 3    | 12   | 5    | 1    | 3    | 88   | 8000 | 12.12
 3    | 12   | 5    | 2    | 3    | 88   | 8000 | 12.12
 3    | 12   | 5    | 3    | 3    | 88   | 8000 | 12.12
(3 rows)

drop sequence ddef4_seq;
drop table defaulttest;
drop domain ddef1 restrict;
drop domain ddef2 restrict;
drop domain ddef3 restrict;
drop domain ddef4 restrict;
drop domain ddef5 restrict;

Re: Domain Support -- another round

From
Bruce Momjian
Date:
Rod Taylor wrote:
> Output looks good, but I always got a bunch of NOTICE statements.
>
> I'll assume the lack of those is related to the logging changes that
> have been going on?

Uh, that is very possible, though the messages would now be INFO
perhaps.  I don't think we actually removed messages in the default
install.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Domain Support -- another round

From
"Rod Taylor"
Date:
Output looks good, but I always got a bunch of NOTICE statements.

I'll assume the lack of those is related to the logging changes that
have been going on?
--
Rod Taylor

This message represents the official view of the voices in my head

----- Original Message -----
From: "Bruce Momjian" <pgman@candle.pha.pa.us>
To: "Rod Taylor" <rbt@zort.ca>
Cc: "Peter Eisentraut" <peter_e@gmx.net>;
<pgsql-patches@postgresql.org>
Sent: Monday, March 18, 2002 9:16 PM
Subject: Re: [PATCHES] Domain Support -- another round


>
> Patch applied.  I am attaching the expected/domain.out file that I
> generated when I added your domain test file to the regression
tests.
> Please verify that the output is correct.  Thanks.
>
> --------------------------------------------------------------------
-------
>
> Rod Taylor wrote:
> > New set with most of Peters comments corrected.  Left the deal
about
> > schema though :)  Took nearly an hour to do a cvs diff for some
reason
> > this time (normally a couple of minutes is enough).
> >
> > > Random nitpicking below.  Also, have you created a regression
test?
> >
> > They had been posted a few times and haven't changed.  (Attached
> > anyway)
> >
> >
> > > > +    <structfield>typnotnull</structfield> represents a NOT
NULL
> > > > +    constraint on a type.  Normally used only for domains.
> > >
> > > And unnormally...?
> >
> > Unnormally is when someone sets it by hand on a type which isn't a
> > domain -- I guess.  Corrected.
> >
> > > > + <!entity createDomain       system "create_domain.sgml">
> > >
> > > I don't see this file included.
> >
> > Other messages.  Full package included on this one however.
> >
> >
> >
> > > > +  * MergeDomainAttributes
> > > > +  *      Returns a new table schema with the constraints,
types,
> > and other
> > > > +  *      attributes of the domain resolved for fields using
the
> > domain as
> > > > +  * their type.
> > >
> > > I didn't know we had schemas yet.  You should probably not
overload
> > that
> > > term to mean "a list of database objects".
> >
> > Merge attributes says something very similar about inheritance and
> > table schemas.  Kinda correct considering
> > the variable used in both cases is *schema.
> >
> >
> > The diff weirdness in regards to DROP DATABASE is probably because
I
> > started by copying the DROP DATABASE element, then altered it.  I
> > don't know why it chose that method to do the diff though, but it
is
> > accurate.  Using -cd flags didn't make it any prettier.
>
> [ Attachment, skipping... ]
>
> [ Attachment, skipping... ]
>
> [ Attachment, skipping... ]
>
> [ Attachment, skipping... ]
>
> --
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   pgman@candle.pha.pa.us               |  (610) 853-3000
>   +  If your life is a hard drive,     |  830 Blythe Avenue
>   +  Christ can be your backup.        |  Drexel Hill, Pennsylvania
19026
>


----------------------------------------------------------------------
----------


> -- Test Comment / Drop
> create domain domaindroptest int4;
> comment on domain domaindroptest is 'About to drop this..';
> create domain basetypetest domaindroptest;
> ERROR:  DefineDomain: domaindroptest is not a basetype
> drop domain domaindroptest;
> ERROR:  parser: parse error at or near ";"
> drop domain domaindroptest restrict;
> -- TEST Domains.
> create domain domainvarchar varchar(5);
> create domain domainnumeric numeric(8,2);
> create domain domainint4 int4;
> create domain domaintext text;
> -- Test tables using domains
> create table basictest
>            ( testint4 domainint4
>            , testtext domaintext
>            , testvarchar domainvarchar
>            , testnumeric domainnumeric
>            );
> INSERT INTO basictest values ('88', 'haha', 'short',
12');      -- Good
> INSERT INTO basictest values ('88', 'haha', 'short text',
'123.12'); -- Bad varchar
> ERROR:  value too long for type character varying(5)
> INSERT INTO basictest values ('88', 'haha', 'short',
3.1212');    -- Truncate numeric
> select * from basictest;
>  testint4 | testtext | testvarchar | testnumeric
> ----------+----------+-------------+-------------
>  88       | haha     | short       | 123.12
>  88       | haha     | short       | 123.12
> (2 rows)
>
> drop table basictest;
> drop domain domainvarchar restrict;
> drop domain domainnumeric restrict;
> drop domain domainint4 restrict;
> drop domain domaintext restrict;
> -- Array Test
> create domain domainint4arr int4[1];
> create domain domaintextarr text[2][3];
> create table domarrtest
>            ( testint4arr domainint4arr
>            , testtextarr domaintextarr
>             );
> INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
> INSERT INTO domarrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
> INSERT INTO domarrtest values ('{2,2}',
'{{"a","b"}{"c","d"}{"e"}}');
> INSERT INTO domarrtest values ('{2,2}', '{{"a"}{"c"}}');
> INSERT INTO domarrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
> drop table domarrtest;
> drop domain domainint4arr restrict;
> drop domain domaintextarr restrict;
> create domain dnotnull varchar(15) NOT NULL;
> create domain dnull    varchar(15) NULL;
> create table nulltest
>            ( col1 dnotnull
>            , col2 dnotnull NULL  -- NOT NULL in the domain cannot be
overridden
>            , col3 dnull    NOT NULL
>            , col4 dnull
>            );
> INSERT INTO nulltest DEFAULT VALUES;
> ERROR:  ExecAppend: Fail to add null value in not null attribute
col1
> INSERT INTO nulltest values ('a', 'b', 'c', 'd');  -- Good
> INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
> ERROR:  ExecAppend: Fail to add null value in not null attribute
col1
> INSERT INTO nulltest values ('a', NULL, 'c', 'd');
> ERROR:  ExecAppend: Fail to add null value in not null attribute
col2
> INSERT INTO nulltest values ('a', 'b', NULL, 'd');
> ERROR:  ExecAppend: Fail to add null value in not null attribute
col3
> INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
> select * from nulltest;
>  col1 | col2 | col3 | col4
> ------+------+------+------
>  a    | b    | c    | d
>  a    | b    | c    |
> (2 rows)
>
> drop table nulltest;
> drop domain dnotnull restrict;
> drop domain dnull restrict;
> create domain ddef1 int4 DEFAULT 3;
> create domain ddef2 oid DEFAULT '12';
> -- Type mixing, function returns int8
> create domain ddef3 text DEFAULT 5;
> create sequence ddef4_seq;
> create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
> create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
> create table defaulttest
>             ( col1 ddef1
>             , col2 ddef2
>             , col3 ddef3
>             , col4 ddef4
>             , col5 ddef1 NOT NULL DEFAULT NULL
>             , col6 ddef2 DEFAULT '88'
>             , col7 ddef4 DEFAULT 8000
> , col8 ddef5
>             );
> insert into defaulttest default values;
> insert into defaulttest default values;
> insert into defaulttest default values;
> select * from defaulttest;
>  col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
> ------+------+------+------+------+------+------+-------
>  3    | 12   | 5    | 1    | 3    | 88   | 8000 | 12.12
>  3    | 12   | 5    | 2    | 3    | 88   | 8000 | 12.12
>  3    | 12   | 5    | 3    | 3    | 88   | 8000 | 12.12
> (3 rows)
>
> drop sequence ddef4_seq;
> drop table defaulttest;
> drop domain ddef1 restrict;
> drop domain ddef2 restrict;
> drop domain ddef3 restrict;
> drop domain ddef4 restrict;
> drop domain ddef5 restrict;
>


Re: Domain Support -- another round

From
Tom Lane
Date:
I've committed a bunch of changes after code review of your DOMAIN
patch.  There were a number of minor bugs as well as some stylistic
things I didn't like.

Probably the largest change was that I concluded we had to revert the
handling of default values for base types to the old way: simple literal
stored as a string.  You can't meaningfully deal with an expression that
represents a value of a type you haven't defined yet --- since you
surely haven't defined any functions or operators that yield it, either.
Therefore the apparent flexibility is illusory.  Also, the code just
plain didn't work: after I fixed preptlist.c to do what it should be
doing, I was getting "can't coerce" failures in the create_type
regression test.  (For example, it didn't believe that an int4 literal
"42" was a valid default for the test's type int42, which is correct
given that the test doesn't define any conversion function...)  So all
in all I just don't see any way that can work.  I've set it up so that
you can have *either* an expression default (if typdefaultbin is not
null) *or* a simple literal default (if typdefaultbin is null but
typdefault isn't).  The former case will work for domains, the latter
for base types.

There are still some things that need to be worked on:

1. pg_dump.  We *cannot* release this feature in 7.3 if there's not
pg_dump support for it.

2. Arrays.  I don't much care for the fact that arrays of domain-type
values aren't supported.  The handling of domains that are themselves
arrays seems a tad odd as well: the array-ish nature of the domain is
exposed, which doesn't make a lot of sense to me.  Perhaps we'd be
better off to forbid array domains.

3. Domains on domains.  Why shouldn't I be able to make a domain that's
a further restriction of another domain?

4. CHECK constraints for domains (which after all is the real point,
no?)

            regards, tom lane

Re: Domain Support -- another round

From
Fernando Nasser
Date:
Tom Lane wrote:
>
> 2. Arrays.  I don't much care for the fact that arrays of domain-type
> values aren't supported.  The handling of domains that are themselves
> arrays seems a tad odd as well: the array-ish nature of the domain is
> exposed, which doesn't make a lot of sense to me.  Perhaps we'd be
> better off to forbid array domains.
>

From SQL99 11.23 Syntax Rule 6)

"<data type> should not specify a reference type, user-defined type,
or an array type."
      ==========

--
Fernando Nasser
Red Hat - Toronto                       E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9

Re: Domain Support -- another round

From
"Rod Taylor"
Date:
> There are still some things that need to be worked on:
>
> 1. pg_dump.  We *cannot* release this feature in 7.3 if there's not
> pg_dump support for it.

I intend to try to do this next week.

> 2. Arrays.  I don't much care for the fact that arrays of
domain-type
> values aren't supported.  The handling of domains that are
themselves
> arrays seems a tad odd as well: the array-ish nature of the domain
is
> exposed, which doesn't make a lot of sense to me.  Perhaps we'd be
> better off to forbid array domains.

The reason I didn't make array types for domains is that I have
absolutly no idea how to manage the below case once point 4 is
implemented.

create domain dom as int4 check (VALUE > 5);
create table tab (col1 dom[2][3]);


> 3. Domains on domains.  Why shouldn't I be able to make a domain
that's
> a further restriction of another domain?

Not entirely sure, except the book I had (SQL99 Complete, Really)
specifically forbids it.

> 4. CHECK constraints for domains (which after all is the real point,
> no?)

Yes, I'm slow and only capable of one step at a time.  Foreign key
constraints are the other real point.


Re: Domain Support -- another round

From
Fernando Nasser
Date:
Rod Taylor wrote:
>
> > 2. Arrays.  I don't much care for the fact that arrays of
> domain-type
> > values aren't supported.  The handling of domains that are
> themselves
> > arrays seems a tad odd as well: the array-ish nature of the domain
> is
> > exposed, which doesn't make a lot of sense to me.  Perhaps we'd be
> > better off to forbid array domains.
>
> The reason I didn't make array types for domains is that I have
> absolutly no idea how to manage the below case once point 4 is
> implemented.
>
> create domain dom as int4 check (VALUE > 5);
> create table tab (col1 dom[2][3]);
>

SQL'99 explicitly forbids it.  Please refer to my posting to HACKERS
for the SQL document reference.



> > 3. Domains on domains.  Why shouldn't I be able to make a domain
> that's
> > a further restriction of another domain?
>
> Not entirely sure, except the book I had (SQL99 Complete, Really)
> specifically forbids it.
>

Yes, but this is their interpretation of the standard. There is an
error in that page anyway, as the standard explicitly forbids
arrays and UDTs and they list REF and ARRAY as valid data types.
(they also get confused with SESSION_USER and CURENT_USER on page
281, so it does not surprise me).

I couldn't find anything in the standard explicitly forbidden it.
But I don't think this is a very useful feature anyway.  As one is
creating another domain, he /she can as well specify constraints
that represent a further reduction of the valid values range.



--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9

Re: Domain Support -- another round

From
Thomas Lockhart
Date:
> SQL'99 explicitly forbids it.  Please refer to my posting to HACKERS
> for the SQL document reference.

The fact that a standard "forbids" something does not necessarily mean
it is a bad idea, as I'm sure you know. Is there any reason that the
standard forbids using domains inside arrays, other than someone on the
standards committee realized that it would be hard for their company to
implement it? That is, does allowing domains in arrays lead to
inconsistancies or fundamental issues with relational algebra or other
set logic that should keep it out of the next set of standards?

If Postgres was developed to only the current standard, it would never
have been written. And since the start of the open source days, if we
had worked solely to get it to conform to the current standard we'd be
starting at ground zero for implementing SQL99, since many of our
features now appear in that standard. Someone cheated and looked at what
we could already do... ;)

                     - Thomas

Re: Domain Support -- another round

From
Fernando Nasser
Date:
Thomas Lockhart wrote:
>
> > SQL'99 explicitly forbids it.  Please refer to my posting to HACKERS
> > for the SQL document reference.
>
> The fact that a standard "forbids" something does not necessarily mean
> it is a bad idea, as I'm sure you know. Is there any reason that the
> standard forbids using domains inside arrays, other than someone on the
> standards committee realized that it would be hard for their company to
> implement it? That is, does allowing domains in arrays lead to
> inconsistancies or fundamental issues with relational algebra or other
> set logic that should keep it out of the next set of standards?
>

I partially agree, but I guess Tom has already given some of the reasons
not to do it.


> If Postgres was developed to only the current standard, it would never
> have been written. And since the start of the open source days, if we
> had worked solely to get it to conform to the current standard we'd be
> starting at ground zero for implementing SQL99, since many of our
> features now appear in that standard. Someone cheated and looked at what
> we could already do... ;)
>

Again, I only partially agree with that,  Adding significant features
that
will allow people to solve significantly different problems that can not
be solved with the vanilla standard is a good think.  And I believe it
is
acknowledged in many places that many SQL3 features were inspired on
Postgres.

However, adding extensions to the SQL standard otherwise is a bad thing.
If affects portability.  Actually, "extending" standards has been a
weapon
used by some proprietary companies to hurt the competition.  Standards
are
friends of Open Source software and we should try to stick to them
whenever possible.

In the case of DOMAINS, which are already considered by some as not very
useful and passive of removal from next editions of the standard (by one
SQL editor, at least -- I can give you the book reference this
afternoon),
adding extension to the SQL to it would just aggravate the issue.

So, although I agree with you in principle, I believe that in these
cases
we should stick to the standard and avoid gratuitous extensions.


--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9

Re: Domain Support -- another round

From
Thomas Lockhart
Date:
...
> So, although I agree with you in principle, I believe that in these
> cases we should stick to the standard and avoid gratuitous extensions.

Hmm. In any case, supporting arrays (esp. if it is not allowed in the
standard) should not be a requirement for implementing the DOMAIN
functionality. No point in arguing principles on just, uh, principles,
when we could actually be getting something good done ;)

                    - Thomas

Re: Domain Support -- another round

From
Fernando Nasser
Date:
Thomas Lockhart wrote:
>
> ...
> > So, although I agree with you in principle, I believe that in these
> > cases we should stick to the standard and avoid gratuitous extensions.
>
> Hmm. In any case, supporting arrays (esp. if it is not allowed in the
> standard) should not be a requirement for implementing the DOMAIN
> functionality. No point in arguing principles on just, uh, principles,
> when we could actually be getting something good done ;)
>

I couldn't agree more.

Cheers,
Fernando

--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9