OSDN Git Service

The cstring datatype can now be copied, passed around, etc. The typlen
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 24 Aug 2002 15:00:47 +0000 (15:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 e62493b..5802789 100644 (file)
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.53 2002/08/13 17:22:08 petere Exp $
+ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.54 2002/08/24 15:00:45 tgl Exp $
  -->
 
 <chapter id="catalogs">
       <entry>typlen</entry>
       <entry><type>int2</type></entry>
       <entry></entry>
-      <entry>Length of the storage representation of the type, -1 if variable length</entry>
+      <entry>
+       For a fixed-size type, <structfield>typlen</structfield> is the number
+       of bytes in the internal representation of the type.  But for a
+       variable-length type, <structfield>typlen</structfield> is negative.
+       -1 indicates a <quote>varlena</> type (one that has a length word),
+       -2 indicates a null-terminated C string.
+      </entry>
      </row>
 
      <row>
       <entry><type>char</type></entry>
       <entry></entry>
       <entry><para>
-       <structfield>typstorage</structfield> tells for variable-length
+       <structfield>typstorage</structfield> tells for varlena
        types (those with <structfield>typlen</structfield> = -1) if
        the type is prepared for toasting and what the default strategy
        for attributes of this type should be.
index 19e02de..4aa6687 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 d47c2e2..a0d2dc8 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 6fbce87..db4187d 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 8482c43..6c6a135 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 5dafb1a..c7dbe44 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 e0bbe75..c0b40c6 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 ee2df73..94c6877 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 b91c70a..9210248 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 4153bb7..49af1f9 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 a402f19..23cc25f 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 7c0dbee..0a751ff 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 e3d78f1..2aca3d7 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 7e5cd29..cb374e8 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 a7a387e..53ea0fa 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 5386729..562d5a7 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 02c5f26..b2bab69 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 2eba70c..a45b775 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 dc39ece..e72a9c4 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 3ff32da..0d1b7ad 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 1ce072c..c6522c3 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 e0890fb..7f606ec 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 0a9701d..7bea305 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