aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/catalogs.sgml12
-rw-r--r--src/backend/access/common/heaptuple.c43
-rw-r--r--src/backend/access/common/indextuple.c36
-rw-r--r--src/backend/access/common/printtup.c10
-rw-r--r--src/backend/catalog/pg_type.c21
-rw-r--r--src/backend/commands/analyze.c24
-rw-r--r--src/backend/commands/copy.c15
-rw-r--r--src/backend/commands/tablecmds.c6
-rw-r--r--src/backend/executor/nodeHash.c52
-rw-r--r--src/backend/nodes/copyfuncs.c17
-rw-r--r--src/backend/tcop/fastpath.c23
-rw-r--r--src/backend/utils/adt/datum.c56
-rw-r--r--src/backend/utils/adt/format_type.c8
-rw-r--r--src/backend/utils/adt/pseudotypes.c15
-rw-r--r--src/backend/utils/sort/tuplesort.c29
-rw-r--r--src/bin/psql/describe.c4
-rw-r--r--src/include/access/tupmacs.h22
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_type.h12
-rw-r--r--src/interfaces/libpq/fe-exec.c12
-rw-r--r--src/pl/plpgsql/src/pl_exec.c33
-rw-r--r--src/test/regress/expected/type_sanity.out2
-rw-r--r--src/test/regress/sql/type_sanity.sql2
23 files changed, 260 insertions, 198 deletions
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index e62493b5257..58027891c82 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -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">
@@ -3173,7 +3173,13 @@
<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>
@@ -3325,7 +3331,7 @@
<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.
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 19e02dee67e..4aa66879feb 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -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);
}
diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c
index d47c2e2d2f9..a0d2dc8ef7e 100644
--- a/src/backend/access/common/indextuple.c
+++ b/src/backend/access/common/indextuple.c
@@ -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);
}
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 6fbce87be7c..db4187dba44 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -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)
{
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 8482c43ca27..6c6a135a0b9 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -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");
/*
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 5dafb1a42ad..c7dbe44f780 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -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;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e0bbe7560bb..c0b40c6e143 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -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)
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ee2df73f21e..94c687721b0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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;
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index b91c70ab10a..92102486c21 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -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));
}
/* ----------------------------------------------------------------
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 4153bb73af8..49af1f90c8e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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;
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index a402f197d65..23cc25fc6de 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -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.
@@ -71,12 +71,12 @@
/* ----------------
* 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",
diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c
index 7c0dbeeb49c..0a751ff1dff 100644
--- a/src/backend/utils/adt/datum.c
+++ b/src/backend/utils/adt/datum.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -19,15 +19,19 @@
* 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.
*/
@@ -36,17 +40,15 @@
#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);
}
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index e3d78f1f908..2aca3d7fc5f 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -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
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 7e5cd2950d8..cb374e8f93c 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -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));
}
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index a7a387e6752..53ea0fa75b7 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -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));
}
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 538672954ea..562d5a7f96f 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -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",
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 02c5f261580..b2bab69b810 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -93,12 +93,11 @@
#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)) : \
@@ -111,18 +110,23 @@
/*
* 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) \
+ )) \
)
/*
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 2eba70c5fd2..a45b775dc7e 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -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
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index dc39ecef79e..e72a9c4c84e 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -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
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 3ff32daaeb1..0d1b7ad05ba 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -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;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 1ce072c5784..c6522c35b9c 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -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;
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index e0890fb01af..7f606ec976f 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -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
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 0a9701de827..7bea3058b4b 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -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