Thread: Fixing contrib/isn for float8-pass-by-value

Fixing contrib/isn for float8-pass-by-value

From
Tom Lane
Date:
The problem reported by Rushabh Lathia boils down to the fact that
contrib/isn intends to define a datatype that is represented "just like
int8", but it supposes that int8 must be pass by reference.  There is
not anything wrong with the C code; the problem is the CREATE TYPE
command in isn.sql.  To fix this we need some way of passing the state
of FLOAT8PASSBYVAL into that SQL script.

It seems reasonably likely that isn.sql isn't going to be the only
place with such a problem, either.

What I propose doing about this is to extend pgxs.mk's rule

%.sql: %.sql.insed 's,MODULE_PATHNAME,$$libdir/$*,g' $< >$@
endif

to also be prepared to replace "FLOAT8PASSBYVAL" with either
"PASSEDBYVALUE," (note the comma) or empty as appropriate.
Likewise for FLOAT4PASSBYVAL.  This will allow construction of
CREATE TYPE commands that properly reflect the attributes of the
various float and int64 types.

This is kinda ugly but I don't really see anything better.
Comments?
        regards, tom lane


Re: Fixing contrib/isn for float8-pass-by-value

From
Tom Lane
Date:
I wrote:
> The problem reported by Rushabh Lathia boils down to the fact that
> contrib/isn intends to define a datatype that is represented "just like
> int8", but it supposes that int8 must be pass by reference.  There is
> not anything wrong with the C code; the problem is the CREATE TYPE
> command in isn.sql.  To fix this we need some way of passing the state
> of FLOAT8PASSBYVAL into that SQL script.
> ...
> This is kinda ugly but I don't really see anything better.

I had a better but more invasive idea: invent a new attribute for
CREATE TYPE
LIKE   =  typename

which means "copy any unspecified representational details from the
given pre-existing type".  This would allow the .sql file to know
less instead of more about what's happening, so it seems more
future-proof.  It's a bit more work than the makefile hack I was
thinking about, but seems like a good investment.  (I wouldn't
propose this if I thought contrib/isn was the only user --- I expect
there are other third-party modules with similar needs.)

Comments?
        regards, tom lane


Re: Fixing contrib/isn for float8-pass-by-value

From
Greg Stark
Date:
I was going to say something like that but couldn't come up with a  
nice syntax. The syntax you gave seems obvious in retrospect.

I wonder if this should be tied in some way with creating binary- 
compatible casts or anything. Probably not since the data type can  
just make them itself.

greg

On 28 Nov 2008, at 08:02 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

> I wrote:
>> The problem reported by Rushabh Lathia boils down to the fact that
>> contrib/isn intends to define a datatype that is represented "just  
>> like
>> int8", but it supposes that int8 must be pass by reference.  There is
>> not anything wrong with the C code; the problem is the CREATE TYPE
>> command in isn.sql.  To fix this we need some way of passing the  
>> state
>> of FLOAT8PASSBYVAL into that SQL script.
>> ...
>> This is kinda ugly but I don't really see anything better.
>
> I had a better but more invasive idea: invent a new attribute for
> CREATE TYPE
>
>    LIKE   =  typename
>
> which means "copy any unspecified representational details from the
> given pre-existing type".  This would allow the .sql file to know
> less instead of more about what's happening, so it seems more
> future-proof.  It's a bit more work than the makefile hack I was
> thinking about, but seems like a good investment.  (I wouldn't
> propose this if I thought contrib/isn was the only user --- I expect
> there are other third-party modules with similar needs.)
>
> Comments?
>
>            regards, tom lane
>
> -- 
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers


Re: Fixing contrib/isn for float8-pass-by-value

From
Tom Lane
Date:
Greg Stark <greg.stark@enterprisedb.com> writes:
> I was going to say something like that but couldn't come up with a
> nice syntax. The syntax you gave seems obvious in retrospect.

Here's a draft patch for this.  It actually works out pretty well --
the bulk of the diff is just to allow processing the CREATE TYPE
parameters in an order that's independent of the syntax.

> I wonder if this should be tied in some way with creating binary-
> compatible casts or anything. Probably not since the data type can
> just make them itself.

Yeah.  I thought for awhile about copying *all* the create-type
parameters from the LIKE type, but soon decided it was a bad idea.
We should keep the inheritance to a minimal level, just the basic
type-storage parameters.

            regards, tom lane

Index: contrib/isn/isn.sql.in
===================================================================
RCS file: /cvsroot/pgsql/contrib/isn/isn.sql.in,v
retrieving revision 1.8
diff -c -r1.8 isn.sql.in
*** contrib/isn/isn.sql.in    13 Nov 2007 04:24:28 -0000    1.8
--- contrib/isn/isn.sql.in    28 Nov 2008 22:03:45 -0000
***************
*** 28,36 ****
  CREATE TYPE ean13 (
      INPUT = ean13_in,
      OUTPUT = ean13_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE ean13
      IS 'International European Article Number (EAN13)';
--- 28,34 ----
  CREATE TYPE ean13 (
      INPUT = ean13_in,
      OUTPUT = ean13_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE ean13
      IS 'International European Article Number (EAN13)';
***************
*** 48,56 ****
  CREATE TYPE isbn13 (
      INPUT = isbn13_in,
      OUTPUT = ean13_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE isbn13
      IS 'International Standard Book Number 13 (ISBN13)';
--- 46,52 ----
  CREATE TYPE isbn13 (
      INPUT = isbn13_in,
      OUTPUT = ean13_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE isbn13
      IS 'International Standard Book Number 13 (ISBN13)';
***************
*** 68,76 ****
  CREATE TYPE ismn13 (
      INPUT = ismn13_in,
      OUTPUT = ean13_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE ismn13
      IS 'International Standard Music Number 13 (ISMN13)';
--- 64,70 ----
  CREATE TYPE ismn13 (
      INPUT = ismn13_in,
      OUTPUT = ean13_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE ismn13
      IS 'International Standard Music Number 13 (ISMN13)';
***************
*** 88,96 ****
  CREATE TYPE issn13 (
      INPUT = issn13_in,
      OUTPUT = ean13_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE issn13
      IS 'International Standard Serial Number 13 (ISSN13)';
--- 82,88 ----
  CREATE TYPE issn13 (
      INPUT = issn13_in,
      OUTPUT = ean13_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE issn13
      IS 'International Standard Serial Number 13 (ISSN13)';
***************
*** 110,118 ****
  CREATE TYPE isbn (
      INPUT = isbn_in,
      OUTPUT = isn_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE isbn
      IS 'International Standard Book Number (ISBN)';
--- 102,108 ----
  CREATE TYPE isbn (
      INPUT = isbn_in,
      OUTPUT = isn_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE isbn
      IS 'International Standard Book Number (ISBN)';
***************
*** 130,138 ****
  CREATE TYPE ismn (
      INPUT = ismn_in,
      OUTPUT = isn_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE ismn
      IS 'International Standard Music Number (ISMN)';
--- 120,126 ----
  CREATE TYPE ismn (
      INPUT = ismn_in,
      OUTPUT = isn_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE ismn
      IS 'International Standard Music Number (ISMN)';
***************
*** 150,158 ****
  CREATE TYPE issn (
      INPUT = issn_in,
      OUTPUT = isn_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE issn
      IS 'International Standard Serial Number (ISSN)';
--- 138,144 ----
  CREATE TYPE issn (
      INPUT = issn_in,
      OUTPUT = isn_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE issn
      IS 'International Standard Serial Number (ISSN)';
***************
*** 170,178 ****
  CREATE TYPE upc (
      INPUT = upc_in,
      OUTPUT = isn_out,
!     INTERNALLENGTH = 8,
!     ALIGNMENT = double,
!     STORAGE = PLAIN
  );
  COMMENT ON TYPE upc
      IS 'Universal Product Code (UPC)';
--- 156,162 ----
  CREATE TYPE upc (
      INPUT = upc_in,
      OUTPUT = isn_out,
!     LIKE = pg_catalog.int8
  );
  COMMENT ON TYPE upc
      IS 'Universal Product Code (UPC)';
Index: doc/src/sgml/ref/create_type.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v
retrieving revision 1.78
diff -c -r1.78 create_type.sgml
*** doc/src/sgml/ref/create_type.sgml    14 Nov 2008 10:22:46 -0000    1.78
--- doc/src/sgml/ref/create_type.sgml    28 Nov 2008 22:03:45 -0000
***************
*** 39,44 ****
--- 39,45 ----
      [ , PASSEDBYVALUE ]
      [ , ALIGNMENT = <replaceable class="parameter">alignment</replaceable> ]
      [ , STORAGE = <replaceable class="parameter">storage</replaceable> ]
+     [ , LIKE = <replaceable class="parameter">like_type</replaceable> ]
      [ , CATEGORY = <replaceable class="parameter">category</replaceable> ]
      [ , PREFERRED = <replaceable class="parameter">preferred</replaceable> ]
      [ , DEFAULT = <replaceable class="parameter">default</replaceable> ]
***************
*** 291,296 ****
--- 292,312 ----
    </para>

    <para>
+    The <replaceable class="parameter">like_type</replaceable> parameter
+    provides an alternative method for specifying the basic representation
+    properties of a data type: copy them from some existing type. The values of
+    <replaceable class="parameter">internallength</replaceable>,
+    <replaceable class="parameter">passedbyvalue</replaceable>,
+    <replaceable class="parameter">alignment</replaceable>, and
+    <replaceable class="parameter">storage</replaceable> are copied from the
+    named type.  (It is possible, though usually undesirable, to override
+    some of these values by specifying them along with the <literal>LIKE</>
+    clause.)  Specifying representation this way is especially useful when
+    the low-level implementation of the new type <quote>piggybacks</> on an
+    existing type in some fashion.
+   </para>
+
+   <para>
     The <replaceable class="parameter">category</replaceable> and
     <replaceable class="parameter">preferred</replaceable> parameters can be
     used to help control which implicit cast will be applied in ambiguous
***************
*** 525,530 ****
--- 541,562 ----
     </varlistentry>

     <varlistentry>
+     <term><replaceable class="parameter">like_type</replaceable></term>
+     <listitem>
+      <para>
+       The name of an existing data type that the new type will have the
+       same representation as.  The values of
+       <replaceable class="parameter">internallength</replaceable>,
+       <replaceable class="parameter">passedbyvalue</replaceable>,
+       <replaceable class="parameter">alignment</replaceable>, and
+       <replaceable class="parameter">storage</replaceable>
+       are copied from that type, unless overridden by explicit
+       specification elsewhere in this <command>CREATE TYPE</> command.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
      <term><replaceable class="parameter">category</replaceable></term>
      <listitem>
       <para>
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.126
diff -c -r1.126 typecmds.c
*** src/backend/commands/typecmds.c    2 Nov 2008 01:45:28 -0000    1.126
--- src/backend/commands/typecmds.c    28 Nov 2008 22:03:45 -0000
***************
*** 100,106 ****
      char       *typeName;
      Oid            typeNamespace;
      int16        internalLength = -1;    /* default: variable-length */
-     Oid            elemType = InvalidOid;
      List       *inputName = NIL;
      List       *outputName = NIL;
      List       *receiveName = NIL;
--- 100,105 ----
***************
*** 108,120 ****
      List       *typmodinName = NIL;
      List       *typmodoutName = NIL;
      List       *analyzeName = NIL;
-     char       *defaultValue = NULL;
-     bool        byValue = false;
      char        category = TYPCATEGORY_USER;
      bool        preferred = false;
      char        delimiter = DEFAULT_TYPDELIM;
      char        alignment = 'i';    /* default alignment */
      char        storage = 'p';    /* default TOAST storage method */
      Oid            inputOid;
      Oid            outputOid;
      Oid            receiveOid = InvalidOid;
--- 107,137 ----
      List       *typmodinName = NIL;
      List       *typmodoutName = NIL;
      List       *analyzeName = NIL;
      char        category = TYPCATEGORY_USER;
      bool        preferred = false;
      char        delimiter = DEFAULT_TYPDELIM;
+     Oid            elemType = InvalidOid;
+     char       *defaultValue = NULL;
+     bool        byValue = false;
      char        alignment = 'i';    /* default alignment */
      char        storage = 'p';    /* default TOAST storage method */
+     DefElem       *likeTypeEl = NULL;
+     DefElem       *internalLengthEl = NULL;
+     DefElem       *inputNameEl = NULL;
+     DefElem       *outputNameEl = NULL;
+     DefElem       *receiveNameEl = NULL;
+     DefElem       *sendNameEl = NULL;
+     DefElem       *typmodinNameEl = NULL;
+     DefElem       *typmodoutNameEl = NULL;
+     DefElem       *analyzeNameEl = NULL;
+     DefElem       *categoryEl = NULL;
+     DefElem       *preferredEl = NULL;
+     DefElem       *delimiterEl = NULL;
+     DefElem       *elemTypeEl = NULL;
+     DefElem       *defaultValueEl = NULL;
+     DefElem       *byValueEl = NULL;
+     DefElem       *alignmentEl = NULL;
+     DefElem       *storageEl = NULL;
      Oid            inputOid;
      Oid            outputOid;
      Oid            receiveOid = InvalidOid;
***************
*** 124,133 ****
      Oid            analyzeOid = InvalidOid;
      char       *array_type;
      Oid            array_oid;
-     ListCell   *pl;
      Oid            typoid;
      Oid            resulttype;
      Relation    pg_type;

      /*
       * As of Postgres 8.4, we require superuser privilege to create a base
--- 141,150 ----
      Oid            analyzeOid = InvalidOid;
      char       *array_type;
      Oid            array_oid;
      Oid            typoid;
      Oid            resulttype;
      Relation    pg_type;
+     ListCell   *pl;

      /*
       * As of Postgres 8.4, we require superuser privilege to create a base
***************
*** 202,312 ****
                       errmsg("type \"%s\" already exists", typeName)));
      }

      foreach(pl, parameters)
      {
          DefElem    *defel = (DefElem *) lfirst(pl);

!         if (pg_strcasecmp(defel->defname, "internallength") == 0)
!             internalLength = defGetTypeLength(defel);
          else if (pg_strcasecmp(defel->defname, "input") == 0)
!             inputName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "output") == 0)
!             outputName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "receive") == 0)
!             receiveName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "send") == 0)
!             sendName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
!             typmodinName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
!             typmodoutName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
                   pg_strcasecmp(defel->defname, "analyse") == 0)
!             analyzeName = defGetQualifiedName(defel);
          else if (pg_strcasecmp(defel->defname, "category") == 0)
!         {
!             char       *p = defGetString(defel);
!
!             category = p[0];
!             /* restrict to non-control ASCII */
!             if (category < 32 || category > 126)
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                          errmsg("invalid type category \"%s\": must be simple ASCII",
!                                 p)));
!         }
          else if (pg_strcasecmp(defel->defname, "preferred") == 0)
!             preferred = defGetBoolean(defel);
          else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
!         {
!             char       *p = defGetString(defel);
!
!             delimiter = p[0];
!             /* XXX shouldn't we restrict the delimiter? */
!         }
          else if (pg_strcasecmp(defel->defname, "element") == 0)
!         {
!             elemType = typenameTypeId(NULL, defGetTypeName(defel), NULL);
!             /* disallow arrays of pseudotypes */
!             if (get_typtype(elemType) == TYPTYPE_PSEUDO)
!                 ereport(ERROR,
!                         (errcode(ERRCODE_DATATYPE_MISMATCH),
!                          errmsg("array element type cannot be %s",
!                                 format_type_be(elemType))));
!         }
          else if (pg_strcasecmp(defel->defname, "default") == 0)
!             defaultValue = defGetString(defel);
          else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
!             byValue = defGetBoolean(defel);
          else if (pg_strcasecmp(defel->defname, "alignment") == 0)
!         {
!             char       *a = defGetString(defel);
!
!             /*
!              * Note: if argument was an unquoted identifier, parser will have
!              * applied translations to it, so be prepared to recognize
!              * translated type names as well as the nominal form.
!              */
!             if (pg_strcasecmp(a, "double") == 0 ||
!                 pg_strcasecmp(a, "float8") == 0 ||
!                 pg_strcasecmp(a, "pg_catalog.float8") == 0)
!                 alignment = 'd';
!             else if (pg_strcasecmp(a, "int4") == 0 ||
!                      pg_strcasecmp(a, "pg_catalog.int4") == 0)
!                 alignment = 'i';
!             else if (pg_strcasecmp(a, "int2") == 0 ||
!                      pg_strcasecmp(a, "pg_catalog.int2") == 0)
!                 alignment = 's';
!             else if (pg_strcasecmp(a, "char") == 0 ||
!                      pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
!                 alignment = 'c';
!             else
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                          errmsg("alignment \"%s\" not recognized", a)));
!         }
          else if (pg_strcasecmp(defel->defname, "storage") == 0)
!         {
!             char       *a = defGetString(defel);
!
!             if (pg_strcasecmp(a, "plain") == 0)
!                 storage = 'p';
!             else if (pg_strcasecmp(a, "external") == 0)
!                 storage = 'e';
!             else if (pg_strcasecmp(a, "extended") == 0)
!                 storage = 'x';
!             else if (pg_strcasecmp(a, "main") == 0)
!                 storage = 'm';
!             else
!                 ereport(ERROR,
!                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                          errmsg("storage \"%s\" not recognized", a)));
!         }
          else
              ereport(WARNING,
                      (errcode(ERRCODE_SYNTAX_ERROR),
                       errmsg("type attribute \"%s\" not recognized",
                              defel->defname)));
      }

      /*
--- 219,393 ----
                       errmsg("type \"%s\" already exists", typeName)));
      }

+     /* Extract the parameters from the parameter list */
      foreach(pl, parameters)
      {
          DefElem    *defel = (DefElem *) lfirst(pl);
+         DefElem   **defelp;

!         if (pg_strcasecmp(defel->defname, "like") == 0)
!             defelp = &likeTypeEl;
!         else if (pg_strcasecmp(defel->defname, "internallength") == 0)
!             defelp = &internalLengthEl;
          else if (pg_strcasecmp(defel->defname, "input") == 0)
!             defelp = &inputNameEl;
          else if (pg_strcasecmp(defel->defname, "output") == 0)
!             defelp = &outputNameEl;
          else if (pg_strcasecmp(defel->defname, "receive") == 0)
!             defelp = &receiveNameEl;
          else if (pg_strcasecmp(defel->defname, "send") == 0)
!             defelp = &sendNameEl;
          else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
!             defelp = &typmodinNameEl;
          else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
!             defelp = &typmodoutNameEl;
          else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
                   pg_strcasecmp(defel->defname, "analyse") == 0)
!             defelp = &analyzeNameEl;
          else if (pg_strcasecmp(defel->defname, "category") == 0)
!             defelp = &categoryEl;
          else if (pg_strcasecmp(defel->defname, "preferred") == 0)
!             defelp = &preferredEl;
          else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
!             defelp = &delimiterEl;
          else if (pg_strcasecmp(defel->defname, "element") == 0)
!             defelp = &elemTypeEl;
          else if (pg_strcasecmp(defel->defname, "default") == 0)
!             defelp = &defaultValueEl;
          else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
!             defelp = &byValueEl;
          else if (pg_strcasecmp(defel->defname, "alignment") == 0)
!             defelp = &alignmentEl;
          else if (pg_strcasecmp(defel->defname, "storage") == 0)
!             defelp = &storageEl;
          else
+         {
+             /* WARNING, not ERROR, for historical backwards-compatibility */
              ereport(WARNING,
                      (errcode(ERRCODE_SYNTAX_ERROR),
                       errmsg("type attribute \"%s\" not recognized",
                              defel->defname)));
+             continue;
+         }
+         if (*defelp != NULL)
+             ereport(ERROR,
+                     (errcode(ERRCODE_SYNTAX_ERROR),
+                      errmsg("conflicting or redundant options")));
+         *defelp = defel;
+     }
+
+     /*
+      * Now interpret the options; we do this separately so that LIKE can
+      * be overridden by other options regardless of the ordering in the
+      * parameter list.
+      */
+     if (likeTypeEl)
+     {
+         Type     likeType;
+         Form_pg_type likeForm;
+
+         likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
+         likeForm = (Form_pg_type) GETSTRUCT(likeType);
+         internalLength = likeForm->typlen;
+         byValue = likeForm->typbyval;
+         alignment = likeForm->typalign;
+         storage = likeForm->typstorage;
+         ReleaseSysCache(likeType);
+     }
+     if (internalLengthEl)
+         internalLength = defGetTypeLength(internalLengthEl);
+     if (inputNameEl)
+         inputName = defGetQualifiedName(inputNameEl);
+     if (outputNameEl)
+         outputName = defGetQualifiedName(outputNameEl);
+     if (receiveNameEl)
+         receiveName = defGetQualifiedName(receiveNameEl);
+     if (sendNameEl)
+         sendName = defGetQualifiedName(sendNameEl);
+     if (typmodinNameEl)
+         typmodinName = defGetQualifiedName(typmodinNameEl);
+     if (typmodoutNameEl)
+         typmodoutName = defGetQualifiedName(typmodoutNameEl);
+     if (analyzeNameEl)
+         analyzeName = defGetQualifiedName(analyzeNameEl);
+     if (categoryEl)
+     {
+         char       *p = defGetString(categoryEl);
+
+         category = p[0];
+         /* restrict to non-control ASCII */
+         if (category < 32 || category > 126)
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("invalid type category \"%s\": must be simple ASCII",
+                             p)));
+     }
+     if (preferredEl)
+         preferred = defGetBoolean(preferredEl);
+     if (delimiterEl)
+     {
+         char       *p = defGetString(delimiterEl);
+
+         delimiter = p[0];
+         /* XXX shouldn't we restrict the delimiter? */
+     }
+     if (elemTypeEl)
+     {
+         elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl), NULL);
+         /* disallow arrays of pseudotypes */
+         if (get_typtype(elemType) == TYPTYPE_PSEUDO)
+             ereport(ERROR,
+                     (errcode(ERRCODE_DATATYPE_MISMATCH),
+                      errmsg("array element type cannot be %s",
+                             format_type_be(elemType))));
+     }
+     if (defaultValueEl)
+         defaultValue = defGetString(defaultValueEl);
+     if (byValueEl)
+         byValue = defGetBoolean(byValueEl);
+     if (alignmentEl)
+     {
+         char       *a = defGetString(alignmentEl);
+
+         /*
+          * Note: if argument was an unquoted identifier, parser will have
+          * applied translations to it, so be prepared to recognize
+          * translated type names as well as the nominal form.
+          */
+         if (pg_strcasecmp(a, "double") == 0 ||
+             pg_strcasecmp(a, "float8") == 0 ||
+             pg_strcasecmp(a, "pg_catalog.float8") == 0)
+             alignment = 'd';
+         else if (pg_strcasecmp(a, "int4") == 0 ||
+                  pg_strcasecmp(a, "pg_catalog.int4") == 0)
+             alignment = 'i';
+         else if (pg_strcasecmp(a, "int2") == 0 ||
+                  pg_strcasecmp(a, "pg_catalog.int2") == 0)
+             alignment = 's';
+         else if (pg_strcasecmp(a, "char") == 0 ||
+                  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
+             alignment = 'c';
+         else
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("alignment \"%s\" not recognized", a)));
+     }
+     if (storageEl)
+     {
+         char       *a = defGetString(storageEl);
+
+         if (pg_strcasecmp(a, "plain") == 0)
+             storage = 'p';
+         else if (pg_strcasecmp(a, "external") == 0)
+             storage = 'e';
+         else if (pg_strcasecmp(a, "extended") == 0)
+             storage = 'x';
+         else if (pg_strcasecmp(a, "main") == 0)
+             storage = 'm';
+         else
+             ereport(ERROR,
+                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                      errmsg("storage \"%s\" not recognized", a)));
      }

      /*

Re: Fixing contrib/isn for float8-pass-by-value

From
Peter Eisentraut
Date:
On Friday 28 November 2008 22:02:52 Tom Lane wrote:
> I had a better but more invasive idea: invent a new attribute for
> CREATE TYPE
>
>     LIKE   =  typename
>
> which means "copy any unspecified representational details from the
> given pre-existing type".  This would allow the .sql file to know
> less instead of more about what's happening, so it seems more
> future-proof.  It's a bit more work than the makefile hack I was
> thinking about, but seems like a good investment.  (I wouldn't
> propose this if I thought contrib/isn was the only user --- I expect
> there are other third-party modules with similar needs.)

Well, this is basically what I had planned with distinct types, at least in a 
future phase.  You will notice that the existing distinct type patch already 
pretty much has the effect of copying another types represenation.  From 
there the difference is essentially only the casting behavior: distinct types 
per SQL have fewer casts, domains have more casts.  I was also planning to 
devise some in-between cases for various use cases, such as creating 
compatibility types.

I'm going to try to write up a wiki page collecting various use cases and 
requirements so the bigger picture becomes clearer.