The cstring datatype can now be copied, passed around, etc. The typlen
authorTom Lane
Sat, 24 Aug 2002 15:00:47 +0000 (15:00 +0000)
committerTom Lane
Sat, 24 Aug 2002 15:00:47 +0000 (15:00 +0000)
value '-2' is used to indicate a variable-width type whose width is
computed as strlen(datum)+1.  Everything that looks at typlen is updated
except for array support, which Joe Conway is working on; at the moment
it wouldn't work to try to create an array of cstring.

23 files changed:
doc/src/sgml/catalogs.sgml
src/backend/access/common/heaptuple.c
src/backend/access/common/indextuple.c
src/backend/access/common/printtup.c
src/backend/catalog/pg_type.c
src/backend/commands/analyze.c
src/backend/commands/copy.c
src/backend/commands/tablecmds.c
src/backend/executor/nodeHash.c
src/backend/nodes/copyfuncs.c
src/backend/tcop/fastpath.c
src/backend/utils/adt/datum.c
src/backend/utils/adt/format_type.c
src/backend/utils/adt/pseudotypes.c
src/backend/utils/sort/tuplesort.c
src/bin/psql/describe.c
src/include/access/tupmacs.h
src/include/catalog/catversion.h
src/include/catalog/pg_type.h
src/interfaces/libpq/fe-exec.c
src/pl/plpgsql/src/pl_exec.c
src/test/regress/expected/type_sanity.out
src/test/regress/sql/type_sanity.sql

index e62493b525772635f9bbcff62d129dc42f24e875..58027891c8273be8d3f212935bf8ca1ba335936c 100644 (file)
@@ -1,6 +1,6 @@
 
 
 
       typlen
       int2
       
-      Length of the storage representation of the type, -1 if variable length
+      
+       For a fixed-size type, typlen is the number
+       of bytes in the internal representation of the type.  But for a
+       variable-length type, typlen is negative.
+       -1 indicates a varlena type (one that has a length word),
+       -2 indicates a null-terminated C string.
+      
      
 
      
       char
       
       
-       typstorage tells for variable-length
+       typstorage tells for varlena
        types (those with typlen = -1) if
        the type is prepared for toasting and what the default strategy
        for attributes of this type should be.
index 19e02dee67e310495210637919c258c3b96e06ca..4aa66879feb097462694b019e8d7f17390ad79ff 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.78 2002/07/20 05:16:56 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.79 2002/08/24 15:00:45 tgl Exp $
  *
  * NOTES
  *   The old interface functions have been converted to macros
@@ -48,7 +48,7 @@ ComputeDataSize(TupleDesc tupleDesc,
        if (nulls[i] != ' ')
            continue;
 
-       data_length = att_align(data_length, att[i]->attlen, att[i]->attalign);
+       data_length = att_align(data_length, att[i]->attalign);
        data_length = att_addlength(data_length, att[i]->attlen, value[i]);
    }
 
@@ -69,7 +69,7 @@ DataFill(char *data,
 {
    bits8      *bitP = 0;
    int         bitmask = 0;
-   uint32      data_length;
+   Size        data_length;
    int         i;
    int         numberOfAttributes = tupleDesc->natts;
    Form_pg_attribute *att = tupleDesc->attrs;
@@ -105,12 +105,13 @@ DataFill(char *data,
        }
 
        /* XXX we are aligning the pointer itself, not the offset */
-       data = (char *) att_align((long) data, att[i]->attlen, att[i]->attalign);
+       data = (char *) att_align((long) data, att[i]->attalign);
 
        if (att[i]->attbyval)
        {
            /* pass-by-value */
            store_att_byval(data, value[i], att[i]->attlen);
+           data_length = att[i]->attlen;
        }
        else if (att[i]->attlen == -1)
        {
@@ -123,15 +124,22 @@ DataFill(char *data,
            data_length = VARATT_SIZE(DatumGetPointer(value[i]));
            memcpy(data, DatumGetPointer(value[i]), data_length);
        }
+       else if (att[i]->attlen == -2)
+       {
+           /* cstring */
+           *infomask |= HEAP_HASVARLENA;
+           data_length = strlen(DatumGetCString(value[i])) + 1;
+           memcpy(data, DatumGetPointer(value[i]), data_length);
+       }
        else
        {
            /* fixed-length pass-by-reference */
-           Assert(att[i]->attlen >= 0);
-           memcpy(data, DatumGetPointer(value[i]),
-                  (size_t) (att[i]->attlen));
+           Assert(att[i]->attlen > 0);
+           data_length = att[i]->attlen;
+           memcpy(data, DatumGetPointer(value[i]), data_length);
        }
 
-       data = (char *) att_addlength((long) data, att[i]->attlen, value[i]);
+       data += data_length;
    }
 }
 
@@ -235,7 +243,8 @@ nocachegetattr(HeapTuple tuple,
        if (att[attnum]->attcacheoff != -1)
        {
            return fetchatt(att[attnum],
-                 (char *) tup + tup->t_hoff + att[attnum]->attcacheoff);
+                           (char *) tup + tup->t_hoff +
+                           att[attnum]->attcacheoff);
        }
 #endif
    }
@@ -243,9 +252,7 @@ nocachegetattr(HeapTuple tuple,
    {
        /*
         * there's a null somewhere in the tuple
-        */
-
-       /*
+        *
         * check to see if desired att is null
         */
 
@@ -346,11 +353,7 @@ nocachegetattr(HeapTuple tuple,
              (HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
              (HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
        {
-           /*
-            * Fix me when going to a machine with more than a four-byte
-            * word!
-            */
-           off = att_align(off, att[j]->attlen, att[j]->attalign);
+           off = att_align(off, att[j]->attalign);
 
            att[j]->attcacheoff = off;
 
@@ -391,7 +394,7 @@ nocachegetattr(HeapTuple tuple,
                off = att[i]->attcacheoff;
            else
            {
-               off = att_align(off, att[i]->attlen, att[i]->attalign);
+               off = att_align(off, att[i]->attalign);
 
                if (usecache)
                    att[i]->attcacheoff = off;
@@ -399,11 +402,11 @@ nocachegetattr(HeapTuple tuple,
 
            off = att_addlength(off, att[i]->attlen, tp + off);
 
-           if (usecache && att[i]->attlen == -1)
+           if (usecache && att[i]->attlen <= 0)
                usecache = false;
        }
 
-       off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
+       off = att_align(off, att[attnum]->attalign);
 
        return fetchatt(att[attnum], tp + off);
    }
index d47c2e2d2f93f89d67fd0d3f00430c6179f4d0b4..a0d2dc8ef7ebcbf35d12c8c60a5ee00e165f251b 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.57 2002/06/20 20:29:24 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.58 2002/08/24 15:00:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,7 +64,7 @@ index_formtuple(TupleDesc tupleDescriptor,
        untoasted_free[i] = false;
 
        /* Do nothing if value is NULL or not of varlena type */
-       if (null[i] != ' ' || att->attlen >= 0)
+       if (null[i] != ' ' || att->attlen != -1)
            continue;
 
        /*
@@ -243,9 +243,10 @@ nocache_index_getattr(IndexTuple tup,
 #endif
    }
    else
-   {                           /* there's a null somewhere in the tuple */
-
+   {
        /*
+        * there's a null somewhere in the tuple
+        *
         * check to see if desired att is null
         */
 
@@ -291,8 +292,9 @@ nocache_index_getattr(IndexTuple tup,
 
    tp = (char *) tup + data_off;
 
-   /* now check for any non-fixed length attrs before our attribute */
-
+   /*
+    * now check for any non-fixed length attrs before our attribute
+    */
    if (!slow)
    {
        if (att[attnum]->attcacheoff != -1)
@@ -305,11 +307,13 @@ nocache_index_getattr(IndexTuple tup,
            int         j;
 
            for (j = 0; j < attnum; j++)
+           {
                if (att[j]->attlen <= 0)
                {
                    slow = true;
                    break;
                }
+           }
        }
    }
 
@@ -337,12 +341,7 @@ nocache_index_getattr(IndexTuple tup,
 
        for (; j <= attnum; j++)
        {
-           /*
-            * Fix me when going to a machine with more than a four-byte
-            * word!
-            */
-
-           off = att_align(off, att[j]->attlen, att[j]->attalign);
+           off = att_align(off, att[j]->attalign);
 
            att[j]->attcacheoff = off;
 
@@ -377,22 +376,19 @@ nocache_index_getattr(IndexTuple tup,
                off = att[i]->attcacheoff;
            else
            {
-               off = att_align(off, att[i]->attlen, att[i]->attalign);
+               off = att_align(off, att[i]->attalign);
 
                if (usecache)
                    att[i]->attcacheoff = off;
            }
 
-           if (att[i]->attlen == -1)
-           {
-               off += VARSIZE(tp + off);
+           off = att_addlength(off, att[i]->attlen, tp + off);
+
+           if (usecache && att[i]->attlen <= 0)
                usecache = false;
-           }
-           else
-               off += att[i]->attlen;
        }
 
-       off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
+       off = att_align(off, att[attnum]->attalign);
 
        return fetchatt(att[attnum], tp + off);
    }
index 6fbce87be7cab41dcb0fe1076f35b7e5a1cbb921..db4187dba4414f0202c5ed99c1f70000464ef284 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.63 2002/08/22 00:01:41 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -457,9 +457,15 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
        }
        else
        {
-           /* fixed size */
+           /* fixed size or cstring */
            attr = origattr;
            len = typeinfo->attrs[i]->attlen;
+           if (len <= 0)
+           {
+               /* it's a cstring */
+               Assert(len == -2 && !typeinfo->attrs[i]->attbyval);
+               len = strlen(DatumGetCString(attr)) + 1;
+           }
            pq_sendint(&buf, len, sizeof(int32));
            if (typeinfo->attrs[i]->attbyval)
            {
index 8482c43ca278629b3d6275873550cafe390ecac0..6c6a135a0b9a0e567d0219f6fbbd5576d39f5bfc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.78 2002/08/15 16:36:01 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.79 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -157,14 +157,25 @@ TypeCreate(const char *typeName,
    int         i;
 
    /*
-    * validate size specifications: either positive (fixed-length) or -1
-    * (variable-length).
+    * We assume that the caller validated the arguments individually,
+    * but did not check for bad combinations.
+    *
+    * Validate size specifications: either positive (fixed-length) or -1
+    * (varlena) or -2 (cstring).  Pass-by-value types must have a fixed
+    * length not more than sizeof(Datum).
     */
-   if (!(internalSize > 0 || internalSize == -1))
+   if (!(internalSize > 0 ||
+         internalSize == -1 ||
+         internalSize == -2))
+       elog(ERROR, "TypeCreate: invalid type internal size %d",
+            internalSize);
+   if (passedByValue &&
+       (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
        elog(ERROR, "TypeCreate: invalid type internal size %d",
             internalSize);
 
-   if (internalSize != -1 && storage != 'p')
+   /* Only varlena types can be toasted */
+   if (storage != 'p' && internalSize != -1)
        elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
 
    /*
index 5dafb1a42adf03e6073f19aa0e3a98332f686b62..c7dbe44f7804e331e420d578fadb3845d55f2309 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.42 2002/08/11 00:08:48 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.43 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -860,6 +860,8 @@ compute_minimal_stats(VacAttrStats *stats,
    double      total_width = 0;
    bool        is_varlena = (!stats->attr->attbyval &&
                              stats->attr->attlen == -1);
+   bool        is_varwidth = (!stats->attr->attbyval &&
+                              stats->attr->attlen < 0);
    FmgrInfo    f_cmpeq;
    typedef struct
    {
@@ -905,7 +907,7 @@ compute_minimal_stats(VacAttrStats *stats,
        nonnull_cnt++;
 
        /*
-        * If it's a varlena field, add up widths for average width
+        * If it's a variable-width field, add up widths for average width
         * calculation.  Note that if the value is toasted, we use the
         * toasted width.  We don't bother with this calculation if it's a
         * fixed-width type.
@@ -928,6 +930,11 @@ compute_minimal_stats(VacAttrStats *stats,
            }
            value = PointerGetDatum(PG_DETOAST_DATUM(value));
        }
+       else if (is_varwidth)
+       {
+           /* must be cstring */
+           total_width += strlen(DatumGetCString(value)) + 1;
+       }
 
        /*
         * See if the value matches anything we're already tracking.
@@ -984,7 +991,7 @@ compute_minimal_stats(VacAttrStats *stats,
        stats->stats_valid = true;
        /* Do the simple null-frac and width stats */
        stats->stanullfrac = (double) null_cnt / (double) numrows;
-       if (is_varlena)
+       if (is_varwidth)
            stats->stawidth = total_width / (double) nonnull_cnt;
        else
            stats->stawidth = stats->attrtype->typlen;
@@ -1157,6 +1164,8 @@ compute_scalar_stats(VacAttrStats *stats,
    double      total_width = 0;
    bool        is_varlena = (!stats->attr->attbyval &&
                              stats->attr->attlen == -1);
+   bool        is_varwidth = (!stats->attr->attbyval &&
+                              stats->attr->attlen < 0);
    double      corr_xysum;
    RegProcedure cmpFn;
    SortFunctionKind cmpFnKind;
@@ -1196,7 +1205,7 @@ compute_scalar_stats(VacAttrStats *stats,
        nonnull_cnt++;
 
        /*
-        * If it's a varlena field, add up widths for average width
+        * If it's a variable-width field, add up widths for average width
         * calculation.  Note that if the value is toasted, we use the
         * toasted width.  We don't bother with this calculation if it's a
         * fixed-width type.
@@ -1219,6 +1228,11 @@ compute_scalar_stats(VacAttrStats *stats,
            }
            value = PointerGetDatum(PG_DETOAST_DATUM(value));
        }
+       else if (is_varwidth)
+       {
+           /* must be cstring */
+           total_width += strlen(DatumGetCString(value)) + 1;
+       }
 
        /* Add it to the list to be sorted */
        values[values_cnt].value = value;
@@ -1311,7 +1325,7 @@ compute_scalar_stats(VacAttrStats *stats,
        stats->stats_valid = true;
        /* Do the simple null-frac and width stats */
        stats->stanullfrac = (double) null_cnt / (double) numrows;
-       if (is_varlena)
+       if (is_varwidth)
            stats->stawidth = total_width / (double) nonnull_cnt;
        else
            stats->stawidth = stats->attrtype->typlen;
index e0bbe7560bb6a4e6331abba8ec37c0ad2062b97e..c0b40c6e1431d34e41f41da090ccc131f9338746 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.166 2002/08/22 00:01:42 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.167 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -567,6 +567,8 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
            elog(ERROR, "COPY: couldn't lookup info for type %u",
                 attr[attnum-1]->atttypid);
        fmgr_info(out_func_oid, &out_functions[attnum-1]);
+       if (binary && attr[attnum-1]->attlen == -2)
+           elog(ERROR, "COPY BINARY: cstring not supported");
    }
 
    if (binary)
@@ -820,9 +822,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
        fmgr_info(in_func_oid, &in_functions[i]);
        elements[i] = GetTypeElement(attr[i]->atttypid);
 
-       /* if column not specified, use default value if one exists */
-       if (!intMember(i + 1, attnumlist))
+       if (intMember(i + 1, attnumlist))
        {
+           /* attribute is to be copied */
+           if (binary && attr[i]->attlen == -2)
+               elog(ERROR, "COPY BINARY: cstring not supported");
+       }
+       else
+       {
+           /* attribute is NOT to be copied */
+           /* use default value if one exists */
            defexprs[num_defaults] = build_column_default(rel, i + 1);
            if (defexprs[num_defaults] != NULL)
            {
index ee2df73f21ee5396498bdebb56f62fc5c1d9245d..94c687721b0f387bac1262fa43fcae469c380201 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.32 2002/08/22 14:23:36 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.33 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3504,8 +3504,8 @@ needs_toast_table(Relation rel)
 
    for (i = 0; i < tupdesc->natts; i++)
    {
-       data_length = att_align(data_length, att[i]->attlen, att[i]->attalign);
-       if (att[i]->attlen >= 0)
+       data_length = att_align(data_length, att[i]->attalign);
+       if (att[i]->attlen > 0)
        {
            /* Fixed-length types are never toastable */
            data_length += att[i]->attlen;
index b91c70ab10a3ca53e211fa8c9a95ee27775c71b5..92102486c2199a62741f814133dd36fe0d7afc5c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $Id: nodeHash.c,v 1.63 2002/06/20 20:29:28 momjian Exp $
+ * $Id: nodeHash.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,7 +32,7 @@
 #include "utils/lsyscache.h"
 
 
-static uint32  hashFunc(Datum key, int len, bool byVal);
+static uint32  hashFunc(Datum key, int typLen, bool byVal);
 
 /* ----------------------------------------------------------------
  *     ExecHash
@@ -632,7 +632,7 @@ ExecScanHashBucket(HashJoinState *hjstate,
  * ----------------------------------------------------------------
  */
 static uint32
-hashFunc(Datum key, int len, bool byVal)
+hashFunc(Datum key, int typLen, bool byVal)
 {
    unsigned char *k;
 
@@ -647,33 +647,47 @@ hashFunc(Datum key, int len, bool byVal)
         * would get the wrong bytes on a big-endian machine.
         */
        k = (unsigned char *) &key;
-       len = sizeof(Datum);
+       typLen = sizeof(Datum);
    }
    else
    {
-       /*
-        * If this is a variable length type, then 'key' points to a
-        * "struct varlena" and len == -1.  NOTE: VARSIZE returns the
-        * "real" data length plus the sizeof the "vl_len" attribute of
-        * varlena (the length information). 'key' points to the beginning
-        * of the varlena struct, so we have to use "VARDATA" to find the
-        * beginning of the "real" data.  Also, we have to be careful to
-        * detoast the datum if it's toasted.  (We don't worry about
-        * freeing the detoasted copy; that happens for free when the
-        * per-tuple memory context is reset in ExecHashGetBucket.)
-        */
-       if (len < 0)
+       if (typLen > 0)
+       {
+           /* fixed-width pass-by-reference type */
+           k = (unsigned char *) DatumGetPointer(key);
+       }
+       else if (typLen == -1)
        {
+           /*
+            * It's a varlena type, so 'key' points to a
+            * "struct varlena".    NOTE: VARSIZE returns the
+            * "real" data length plus the sizeof the "vl_len" attribute of
+            * varlena (the length information). 'key' points to the beginning
+            * of the varlena struct, so we have to use "VARDATA" to find the
+            * beginning of the "real" data.  Also, we have to be careful to
+            * detoast the datum if it's toasted.  (We don't worry about
+            * freeing the detoasted copy; that happens for free when the
+            * per-tuple memory context is reset in ExecHashGetBucket.)
+            */
            struct varlena *vkey = PG_DETOAST_DATUM(key);
 
-           len = VARSIZE(vkey) - VARHDRSZ;
+           typLen = VARSIZE(vkey) - VARHDRSZ;
            k = (unsigned char *) VARDATA(vkey);
        }
-       else
+       else if (typLen == -2)
+       {
+           /* It's a null-terminated C string */
+           typLen = strlen(DatumGetCString(key)) + 1;
            k = (unsigned char *) DatumGetPointer(key);
+       }
+       else
+       {
+           elog(ERROR, "hashFunc: Invalid typLen %d", typLen);
+           k = NULL;           /* keep compiler quiet */
+       }
    }
 
-   return DatumGetUInt32(hash_any(k, len));
+   return DatumGetUInt32(hash_any(k, typLen));
 }
 
 /* ----------------------------------------------------------------
index 4153bb73af8a7b391f1415c1f1c9e6de9a0020d4..49af1f90c8e5c0c85b7f9da449a8fc188b6e3160 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.204 2002/08/19 15:08:46 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.205 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,6 +24,7 @@
 
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
+#include "utils/datum.h"
 
 
 /*
@@ -791,23 +792,17 @@ _copyConst(Const *from)
        /*
         * passed by value so just copy the datum. Also, don't try to copy
         * struct when value is null!
-        *
         */
        newnode->constvalue = from->constvalue;
    }
    else
    {
        /*
-        * not passed by value. datum contains a pointer.
+        * not passed by value.  We need a palloc'd copy.
         */
-       int         length = from->constlen;
-
-       if (length == -1)       /* variable-length type? */
-           length = VARSIZE(from->constvalue);
-       newnode->constvalue = PointerGetDatum(palloc(length));
-       memcpy(DatumGetPointer(newnode->constvalue),
-              DatumGetPointer(from->constvalue),
-              length);
+       newnode->constvalue = datumCopy(from->constvalue,
+                                       from->constbyval,
+                                       from->constlen);
    }
 
    newnode->constisnull = from->constisnull;
index a402f197d6534b7a21b764a1351ac60fa7357f52..23cc25fc6de441af13c4fd20d49aaae2fa1ebcb2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.53 2002/06/20 20:29:36 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.54 2002/08/24 15:00:46 tgl Exp $
  *
  * NOTES
  *   This cruft is the server side of PQfn.
 
 /* ----------------
  *     SendFunctionResult
+ *
+ * retlen is 0 if returning NULL, else the typlen according to the catalogs
  * ----------------
  */
 static void
-SendFunctionResult(Datum retval,   /* actual return value */
-                  bool retbyval,
-                  int retlen)  /* the length according to the catalogs */
+SendFunctionResult(Datum retval, bool retbyval, int retlen)
 {
    StringInfoData buf;
 
@@ -93,7 +93,7 @@ SendFunctionResult(Datum retval,  /* actual return value */
        }
        else
        {                       /* by-reference ... */
-           if (retlen < 0)
+           if (retlen == -1)
            {                   /* ... varlena */
                struct varlena *v = (struct varlena *) DatumGetPointer(retval);
 
@@ -177,12 +177,15 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
 
    for (i = 0; i < pp->pronargs; ++i)
    {
-       if (OidIsValid(argtypes[i]))
-           get_typlenbyval(argtypes[i], &fip->arglen[i], &fip->argbyval[i]);
+       get_typlenbyval(argtypes[i], &fip->arglen[i], &fip->argbyval[i]);
+       /* We don't support cstring in fastpath protocol */
+       if (fip->arglen[i] == -2)
+           elog(ERROR, "CSTRING not supported in fastpath protocol");
    }
 
-   if (OidIsValid(rettype))
-       get_typlenbyval(rettype, &fip->retlen, &fip->retbyval);
+   get_typlenbyval(rettype, &fip->retlen, &fip->retbyval);
+   if (fip->retlen == -2)
+       elog(ERROR, "CSTRING not supported in fastpath protocol");
 
    ReleaseSysCache(func_htp);
 
@@ -297,7 +300,7 @@ HandleFunctionRequest(void)
        }
        else
        {                       /* by-reference ... */
-           if (fip->arglen[i] < 0)
+           if (fip->arglen[i] == -1)
            {                   /* ... varlena */
                if (argsize < 0)
                    elog(ERROR, "HandleFunctionRequest: bogus argsize %d",
index 7c0dbeeb49c47708bd4969b72198db9fa8cbf178..0a751ff1dffc4cc0229beef4215af5f982d1a978 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.23 2002/06/20 20:29:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.24 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  * Datum itself (i.e. no pointers involved!). In this case the
  * length of the type is always greater than zero and not more than
  * "sizeof(Datum)"
- * B) if a type is not "byVal" and it has a fixed length, then
- * the "Datum" always contain a pointer to a stream of bytes.
- * The number of significant bytes are always equal to the length of the
- * type.
- * C) if a type is not "byVal" and is of variable length (i.e. it has
- * length == -1) then "Datum" always points to a "struct varlena".
+ *
+ * B) if a type is not "byVal" and it has a fixed length (typlen > 0),
+ * then the "Datum" always contains a pointer to a stream of bytes.
+ * The number of significant bytes are always equal to the typlen.
+ *
+ * C) if a type is not "byVal" and has typlen == -1,
+ * then the "Datum" always points to a "struct varlena".
  * This varlena structure has information about the actual length of this
  * particular instance of the type and about its value.
  *
+ * D) if a type is not "byVal" and has typlen == -2,
+ * then the "Datum" always points to a null-terminated C string.
+ *
  * Note that we do not treat "toasted" datums specially; therefore what
  * will be copied or compared is the compressed data or toast reference.
  */
 
 #include "utils/datum.h"
 
+
 /*-------------------------------------------------------------------------
  * datumGetSize
  *
  * Find the "real" size of a datum, given the datum value,
- * whether it is a "by value", and its length.
+ * whether it is a "by value", and the declared type length.
  *
- * To cut a long story short, usually the real size is equal to the
- * type length, with the exception of variable length types which have
- * a length equal to -1. In this case, we have to look at the value of
- * the datum itself (which is a pointer to a 'varlena' struct) to find
- * its size.
+ * This is essentially an out-of-line version of the att_addlength()
+ * macro in access/tupmacs.h.  We do a tad more error checking though.
  *-------------------------------------------------------------------------
  */
 Size
@@ -62,19 +64,33 @@ datumGetSize(Datum value, bool typByVal, int typLen)
    }
    else
    {
-       if (typLen == -1)
+       if (typLen > 0)
+       {
+           /* Fixed-length pass-by-ref type */
+           size = (Size) typLen;
+       }
+       else if (typLen == -1)
        {
-           /* Assume it is a varlena datatype */
+           /* It is a varlena datatype */
            struct varlena *s = (struct varlena *) DatumGetPointer(value);
 
            if (!PointerIsValid(s))
                elog(ERROR, "datumGetSize: Invalid Datum Pointer");
-           size = (Size) VARSIZE(s);
+           size = (Size) VARATT_SIZE(s);
+       }
+       else if (typLen == -2)
+       {
+           /* It is a cstring datatype */
+           char *s = (char *) DatumGetPointer(value);
+
+           if (!PointerIsValid(s))
+               elog(ERROR, "datumGetSize: Invalid Datum Pointer");
+           size = (Size) (strlen(s) + 1);
        }
        else
        {
-           /* Fixed-length pass-by-ref type */
-           size = (Size) typLen;
+           elog(ERROR, "datumGetSize: Invalid typLen %d", typLen);
+           size = 0;           /* keep compiler quiet */
        }
    }
 
@@ -159,7 +175,9 @@ datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
        /*
         * just compare the two datums. NOTE: just comparing "len" bytes
         * will not do the work, because we do not know how these bytes
-        * are aligned inside the "Datum".
+        * are aligned inside the "Datum".  We assume instead that any
+        * given datatype is consistent about how it fills extraneous
+        * bits in the Datum.
         */
        res = (value1 == value2);
    }
index e3d78f1f90818890c444b9315dc23699c88fa491..2aca3d7fc5fe0f8ebf00776fb81bcad864372d75 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.31 2002/08/04 06:44:47 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.32 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -149,7 +149,7 @@ format_type_internal(Oid type_oid, int32 typemod,
    array_base_type = typeform->typelem;
 
    if (array_base_type != InvalidOid &&
-       typeform->typlen < 0 &&
+       typeform->typlen == -1 &&
        typeform->typtype != 'd')
    {
        /* Switch our attention to the array element type */
@@ -411,11 +411,11 @@ format_type_internal(Oid type_oid, int32 typemod,
 
 
 /*
- * type_maximum_size --- determine maximum width of a varlena column
+ * type_maximum_size --- determine maximum width of a variable-width column
  *
  * If the max width is indeterminate, return -1.  In particular, we return
  * -1 for any type not known to this routine.  We assume the caller has
- * already determined that the type is a varlena type, so it's not
+ * already determined that the type is a variable-width type, so it's not
  * necessary to look up the type's pg_type tuple here.
  *
  * This may appear unrelated to format_type(), but in fact the two routines
index 7e5cd2950d85d246dec65fdff0ffa9531516b3ba..cb374e8f93c1ec25b58598353d022c11bf7f2fff 100644 (file)
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.1 2002/08/22 00:01:43 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.2 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,24 +50,29 @@ record_out(PG_FUNCTION_ARGS)
 
 /*
  * cstring_in      - input routine for pseudo-type CSTRING.
+ *
+ * We might as well allow this to support constructs like "foo_in('blah')".
  */
 Datum
 cstring_in(PG_FUNCTION_ARGS)
 {
-   elog(ERROR, "Cannot accept a constant of type %s", "CSTRING");
+   char       *str = PG_GETARG_CSTRING(0);
 
-   PG_RETURN_VOID();           /* keep compiler quiet */
+   PG_RETURN_CSTRING(pstrdup(str));
 }
 
 /*
  * cstring_out     - output routine for pseudo-type CSTRING.
+ *
+ * We allow this mainly so that "SELECT some_output_function(...)" does
+ * what the user will expect.
  */
 Datum
 cstring_out(PG_FUNCTION_ARGS)
 {
-   elog(ERROR, "Cannot display a value of type %s", "CSTRING");
+   char       *str = PG_GETARG_CSTRING(0);
 
-   PG_RETURN_VOID();           /* keep compiler quiet */
+   PG_RETURN_CSTRING(pstrdup(str));
 }
 
 
index a7a387e675290343bc85fb4bd9b75545980e1542..53ea0fa75b7aaad8c6fcc4e71e1ed77ab38a1e59 100644 (file)
@@ -78,7 +78,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.25 2002/08/12 00:36:12 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.26 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,6 +92,7 @@
 #include "catalog/pg_amproc.h"
 #include "catalog/pg_operator.h"
 #include "miscadmin.h"
+#include "utils/datum.h"
 #include "utils/fmgroids.h"
 #include "utils/logtape.h"
 #include "utils/lsyscache.h"
@@ -607,16 +608,14 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
    }
    else
    {
-       int         datalen = state->datumTypeLen;
-       int         tuplelen;
+       Size        datalen;
+       Size        tuplelen;
        char       *newVal;
 
-       if (datalen == -1)      /* variable length type? */
-           datalen = VARSIZE((struct varlena *) DatumGetPointer(val));
+       datalen = datumGetSize(val, false, state->datumTypeLen);
        tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));
-       newVal = (char *) palloc(tuplelen);
-       tuple = (DatumTuple *) newVal;
-       newVal += MAXALIGN(sizeof(DatumTuple));
+       tuple = (DatumTuple *) palloc(tuplelen);
+       newVal = ((char *) tuple) + MAXALIGN(sizeof(DatumTuple));
        memcpy(newVal, DatumGetPointer(val), datalen);
        tuple->val = PointerGetDatum(newVal);
        tuple->isNull = false;
@@ -959,14 +958,7 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward,
    }
    else
    {
-       int         datalen = state->datumTypeLen;
-       char       *newVal;
-
-       if (datalen == -1)      /* variable length type? */
-           datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
-       newVal = (char *) palloc(datalen);
-       memcpy(newVal, DatumGetPointer(tuple->val), datalen);
-       *val = PointerGetDatum(newVal);
+       *val = datumCopy(tuple->val, false, state->datumTypeLen);
        *isNull = false;
    }
 
@@ -1959,10 +1951,9 @@ writetup_datum(Tuplesortstate *state, int tapenum, void *tup)
        tuplen = sizeof(DatumTuple);
    else
    {
-       int         datalen = state->datumTypeLen;
+       Size        datalen;
 
-       if (datalen == -1)      /* variable length type? */
-           datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
+       datalen = datumGetSize(tuple->val, false, state->datumTypeLen);
        tuplen = datalen + MAXALIGN(sizeof(DatumTuple));
    }
 
index 538672954ea3ec71430223f80ae8c63363b397be..562d5a7f96f770ab914c180ea873036797722de8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.63 2002/08/22 00:01:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -196,7 +196,7 @@ describeTypes(const char *pattern, bool verbose)
    if (verbose)
        appendPQExpBuffer(&buf,
                 "  t.typname AS \"%s\",\n"
-                "  CASE WHEN t.typlen = -1\n"
+                "  CASE WHEN t.typlen < 0\n"
                 "    THEN CAST('var' AS pg_catalog.text)\n"
                 "    ELSE CAST(t.typlen AS pg_catalog.text)\n"
                 "  END AS \"%s\",\n",
index 02c5f2615806078ec9f50001cdb6e92ed2d08059..b2bab69b8102fbe87ff2425b46480f1aaa45fd67 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tupmacs.h,v 1.21 2002/06/20 20:29:43 momjian Exp $
+ * $Id: tupmacs.h,v 1.22 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #endif   /* SIZEOF_DATUM == 8 */
 
 /*
- * att_align aligns the given offset as needed for a datum of length attlen
- * and alignment requirement attalign. In practice we don't need the length.
- * The attalign cases are tested in what is hopefully something like their
- * frequency of occurrence.
+ * att_align aligns the given offset as needed for a datum of alignment
+ * requirement attalign.  The cases are tested in what is hopefully something
+ * like their frequency of occurrence.
  */
-#define att_align(cur_offset, attlen, attalign) \
+#define att_align(cur_offset, attalign) \
 ( \
    ((attalign) == 'i') ? INTALIGN(cur_offset) : \
     (((attalign) == 'c') ? ((long)(cur_offset)) : \
 
 /*
  * att_addlength increments the given offset by the length of the attribute.
- * attval is only accessed if we are dealing with a varlena attribute.
+ * attval is only accessed if we are dealing with a variable-length attribute.
  */
 #define att_addlength(cur_offset, attlen, attval) \
 ( \
-   ((attlen) != -1) ? \
+   ((attlen) > 0) ? \
    ( \
        (cur_offset) + (attlen) \
    ) \
-   : \
+   : (((attlen) == -1) ? \
    ( \
        (cur_offset) + VARATT_SIZE(DatumGetPointer(attval)) \
    ) \
+   : \
+   ( \
+       AssertMacro((attlen) == -2), \
+       (cur_offset) + (strlen(DatumGetCString(attval)) + 1) \
+   )) \
 )
 
 /*
index 2eba70c5fd231928197131b36b8b5d230e924514..a45b775dc7eedb3505bdc32428d0bc38be2c23f8 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.151 2002/08/22 00:01:47 tgl Exp $
+ * $Id: catversion.h,v 1.152 2002/08/24 15:00:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200208201
+#define CATALOG_VERSION_NO 200208231
 
 #endif
index dc39ecef79eb4362669fb35bfe4e896db1c55712..e72a9c4c84ec2e2092600b5b0e171568c80bea31 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.128 2002/08/22 00:01:48 tgl Exp $
+ * $Id: pg_type.h,v 1.129 2002/08/24 15:00:46 tgl Exp $
  *
  * NOTES
  *   the genbki.sh script reads this file and generates .bki
@@ -45,7 +45,9 @@ CATALOG(pg_type) BOOTSTRAP
    /*
     * For a fixed-size type, typlen is the number of bytes we use to
     * represent a value of this type, e.g. 4 for an int4.  But for a
-    * variable-length type, typlen is -1.
+    * variable-length type, typlen is negative.  We use -1 to indicate
+    * a "varlena" type (one that has a length word), -2 to indicate a
+    * null-terminated C string.
     */
    int2        typlen;
 
@@ -87,7 +89,7 @@ CATALOG(pg_type) BOOTSTRAP
     * be turned into pseudo-arrays like that. Hence, the way to determine
     * whether a type is a "true" array type is if:
     *
-    * typelem != 0 and typlen < 0.
+    * typelem != 0 and typlen == -1.
     */
    Oid         typelem;
 
@@ -513,11 +515,11 @@ DATA(insert OID = 2211 ( _regtype      PGNSP PGUID -1 f b t \054 0 2206 array_in
  */
 DATA(insert OID = 2249 ( record            PGNSP PGUID  4 t p t \054 0 0 record_in record_out  i p f 0 -1 0 _null_ _null_ ));
 #define RECORDOID      2249
-DATA(insert OID = 2275 ( cstring       PGNSP PGUID  4 t p t \054 0 0 cstring_in cstring_out    i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2275 ( cstring       PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out    c p f 0 -1 0 _null_ _null_ ));
 #define CSTRINGOID     2275
 DATA(insert OID = 2276 ( any           PGNSP PGUID  4 t p t \054 0 0 any_in any_out    i p f 0 -1 0 _null_ _null_ ));
 #define ANYOID         2276
-DATA(insert OID = 2277 ( anyarray      PGNSP PGUID  4 t p t \054 0 0 anyarray_in anyarray_out  i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2277 ( anyarray      PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out  i x f 0 -1 0 _null_ _null_ ));
 #define ANYARRAYOID        2277
 DATA(insert OID = 2278 ( void          PGNSP PGUID  4 t p t \054 0 0 void_in void_out  i p f 0 -1 0 _null_ _null_ ));
 #define VOIDOID            2278
index 3ff32daaeb1ae6d8015074c3560916668bbecc6e..0d1b7ad05ba238ac43821345dfdfcb218d733f3d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.120 2002/06/20 20:29:53 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.121 2002/08/24 15:00:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1138,14 +1138,10 @@ getRowDescriptions(PGconn *conn)
 
        /*
         * Since pqGetInt treats 2-byte integers as unsigned, we need to
-        * coerce the special value "-1" to signed form.  (-1 is sent for
-        * variable-length fields.)  Formerly, libpq effectively did a
-        * sign-extension on the 2-byte value by storing it in a signed
-        * short. Now we only coerce the single value 65535 == -1; values
-        * 32768..65534 are taken as valid field lengths.
+        * coerce the result to signed form.
         */
-       if (typlen == 0xFFFF)
-           typlen = -1;
+       typlen = (int) ((int16) typlen);
+
        result->attDescs[i].name = pqResultStrdup(result,
                                                  conn->workBuffer.data);
        result->attDescs[i].typid = typid;
index 1ce072c57847fd74b55c30c3b6b38f9003c06da2..c6522c35b9ca4a2eb699cdf07a9826bd33fbc184 100644 (file)
@@ -3,7 +3,7 @@
  *           procedural language
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.57 2002/08/20 05:28:23 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.58 2002/08/24 15:00:47 tgl Exp $
  *
  *   This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -362,17 +362,13 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
             */
            if (!fcinfo->isnull && !func->fn_retbyval)
            {
-               int         len;
-               Datum       tmp;
+               Size        len;
+               void       *tmp;
 
-               if (func->fn_rettyplen < 0)
-                   len = VARSIZE(estate.retval);
-               else
-                   len = func->fn_rettyplen;
-
-               tmp = (Datum) SPI_palloc(len);
-               memcpy((void *) tmp, (void *) estate.retval, len);
-               estate.retval = tmp;
+               len = datumGetSize(estate.retval, false, func->fn_rettyplen);
+               tmp = (void *) SPI_palloc(len);
+               memcpy(tmp, DatumGetPointer(estate.retval), len);
+               estate.retval = PointerGetDatum(tmp);
            }
        }
    }
@@ -2682,7 +2678,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
 
            if (var->freeval)
            {
-               pfree((void *) (var->value));
+               pfree(DatumGetPointer(var->value));
                var->freeval = false;
            }
 
@@ -2705,16 +2701,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
            if (!var->datatype->typbyval && !*isNull)
            {
                if (newvalue == value)
-               {
-                   int         len;
-
-                   if (var->datatype->typlen < 0)
-                       len = VARSIZE(newvalue);
-                   else
-                       len = var->datatype->typlen;
-                   var->value = (Datum) palloc(len);
-                   memcpy((void *) (var->value), (void *) newvalue, len);
-               }
+                   var->value = datumCopy(newvalue,
+                                          false,
+                                          var->datatype->typlen);
                else
                    var->value = newvalue;
                var->freeval = true;
index e0890fb01af955acbdb3696fdcfaeda2f42e8696..7f606ec976fd761f3a1f1fda8fa5eab71f803284 100644 (file)
@@ -16,7 +16,7 @@
 SELECT p1.oid, p1.typname
 FROM pg_type as p1
 WHERE p1.typnamespace = 0 OR
-    (p1.typlen <= 0 AND p1.typlen != -1) OR
+    (p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
     (p1.typtype not in ('b', 'c', 'd', 'p')) OR
     NOT p1.typisdefined OR
     (p1.typalign not in ('c', 's', 'i', 'd')) OR
index 0a9701de827943e164b440697a07916292a0e293..7bea3058b4b3cf0cb748506bd58c54ddfb33572c 100644 (file)
@@ -19,7 +19,7 @@
 SELECT p1.oid, p1.typname
 FROM pg_type as p1
 WHERE p1.typnamespace = 0 OR
-    (p1.typlen <= 0 AND p1.typlen != -1) OR
+    (p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
     (p1.typtype not in ('b', 'c', 'd', 'p')) OR
     NOT p1.typisdefined OR
     (p1.typalign not in ('c', 's', 'i', 'd')) OR