Commit 976246cc authored by Tom Lane's avatar Tom Lane

The cstring datatype can now be copied, passed around, etc. The typlen

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.
parent cf4d885c
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers 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"> <chapter id="catalogs">
...@@ -3173,7 +3173,13 @@ ...@@ -3173,7 +3173,13 @@
<entry>typlen</entry> <entry>typlen</entry>
<entry><type>int2</type></entry> <entry><type>int2</type></entry>
<entry></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>
<row> <row>
...@@ -3325,7 +3331,7 @@ ...@@ -3325,7 +3331,7 @@
<entry><type>char</type></entry> <entry><type>char</type></entry>
<entry></entry> <entry></entry>
<entry><para> <entry><para>
<structfield>typstorage</structfield> tells for variable-length <structfield>typstorage</structfield> tells for varlena
types (those with <structfield>typlen</structfield> = -1) if types (those with <structfield>typlen</structfield> = -1) if
the type is prepared for toasting and what the default strategy the type is prepared for toasting and what the default strategy
for attributes of this type should be. for attributes of this type should be.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* The old interface functions have been converted to macros * The old interface functions have been converted to macros
...@@ -48,7 +48,7 @@ ComputeDataSize(TupleDesc tupleDesc, ...@@ -48,7 +48,7 @@ ComputeDataSize(TupleDesc tupleDesc,
if (nulls[i] != ' ') if (nulls[i] != ' ')
continue; 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]); data_length = att_addlength(data_length, att[i]->attlen, value[i]);
} }
...@@ -69,7 +69,7 @@ DataFill(char *data, ...@@ -69,7 +69,7 @@ DataFill(char *data,
{ {
bits8 *bitP = 0; bits8 *bitP = 0;
int bitmask = 0; int bitmask = 0;
uint32 data_length; Size data_length;
int i; int i;
int numberOfAttributes = tupleDesc->natts; int numberOfAttributes = tupleDesc->natts;
Form_pg_attribute *att = tupleDesc->attrs; Form_pg_attribute *att = tupleDesc->attrs;
...@@ -105,12 +105,13 @@ DataFill(char *data, ...@@ -105,12 +105,13 @@ DataFill(char *data,
} }
/* XXX we are aligning the pointer itself, not the offset */ /* 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) if (att[i]->attbyval)
{ {
/* pass-by-value */ /* pass-by-value */
store_att_byval(data, value[i], att[i]->attlen); store_att_byval(data, value[i], att[i]->attlen);
data_length = att[i]->attlen;
} }
else if (att[i]->attlen == -1) else if (att[i]->attlen == -1)
{ {
...@@ -123,15 +124,22 @@ DataFill(char *data, ...@@ -123,15 +124,22 @@ DataFill(char *data,
data_length = VARATT_SIZE(DatumGetPointer(value[i])); data_length = VARATT_SIZE(DatumGetPointer(value[i]));
memcpy(data, DatumGetPointer(value[i]), data_length); 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 else
{ {
/* fixed-length pass-by-reference */ /* fixed-length pass-by-reference */
Assert(att[i]->attlen >= 0); Assert(att[i]->attlen > 0);
memcpy(data, DatumGetPointer(value[i]), data_length = att[i]->attlen;
(size_t) (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, ...@@ -235,7 +243,8 @@ nocachegetattr(HeapTuple tuple,
if (att[attnum]->attcacheoff != -1) if (att[attnum]->attcacheoff != -1)
{ {
return fetchatt(att[attnum], return fetchatt(att[attnum],
(char *) tup + tup->t_hoff + att[attnum]->attcacheoff); (char *) tup + tup->t_hoff +
att[attnum]->attcacheoff);
} }
#endif #endif
} }
...@@ -243,9 +252,7 @@ nocachegetattr(HeapTuple tuple, ...@@ -243,9 +252,7 @@ nocachegetattr(HeapTuple tuple,
{ {
/* /*
* there's a null somewhere in the tuple * there's a null somewhere in the tuple
*/ *
/*
* check to see if desired att is null * check to see if desired att is null
*/ */
...@@ -346,11 +353,7 @@ nocachegetattr(HeapTuple tuple, ...@@ -346,11 +353,7 @@ nocachegetattr(HeapTuple tuple,
(HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) && (HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
(HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++) (HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
{ {
/* off = att_align(off, att[j]->attalign);
* Fix me when going to a machine with more than a four-byte
* word!
*/
off = att_align(off, att[j]->attlen, att[j]->attalign);
att[j]->attcacheoff = off; att[j]->attcacheoff = off;
...@@ -391,7 +394,7 @@ nocachegetattr(HeapTuple tuple, ...@@ -391,7 +394,7 @@ nocachegetattr(HeapTuple tuple,
off = att[i]->attcacheoff; off = att[i]->attcacheoff;
else else
{ {
off = att_align(off, att[i]->attlen, att[i]->attalign); off = att_align(off, att[i]->attalign);
if (usecache) if (usecache)
att[i]->attcacheoff = off; att[i]->attcacheoff = off;
...@@ -399,11 +402,11 @@ nocachegetattr(HeapTuple tuple, ...@@ -399,11 +402,11 @@ nocachegetattr(HeapTuple tuple,
off = att_addlength(off, att[i]->attlen, tp + off); off = att_addlength(off, att[i]->attlen, tp + off);
if (usecache && att[i]->attlen == -1) if (usecache && att[i]->attlen <= 0)
usecache = false; 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); return fetchatt(att[attnum], tp + off);
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -64,7 +64,7 @@ index_formtuple(TupleDesc tupleDescriptor,
untoasted_free[i] = false; untoasted_free[i] = false;
/* Do nothing if value is NULL or not of varlena type */ /* Do nothing if value is NULL or not of varlena type */
if (null[i] != ' ' || att->attlen >= 0) if (null[i] != ' ' || att->attlen != -1)
continue; continue;
/* /*
...@@ -243,9 +243,10 @@ nocache_index_getattr(IndexTuple tup, ...@@ -243,9 +243,10 @@ nocache_index_getattr(IndexTuple tup,
#endif #endif
} }
else 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 * check to see if desired att is null
*/ */
...@@ -291,8 +292,9 @@ nocache_index_getattr(IndexTuple tup, ...@@ -291,8 +292,9 @@ nocache_index_getattr(IndexTuple tup,
tp = (char *) tup + data_off; 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 (!slow)
{ {
if (att[attnum]->attcacheoff != -1) if (att[attnum]->attcacheoff != -1)
...@@ -305,6 +307,7 @@ nocache_index_getattr(IndexTuple tup, ...@@ -305,6 +307,7 @@ nocache_index_getattr(IndexTuple tup,
int j; int j;
for (j = 0; j < attnum; j++) for (j = 0; j < attnum; j++)
{
if (att[j]->attlen <= 0) if (att[j]->attlen <= 0)
{ {
slow = true; slow = true;
...@@ -312,6 +315,7 @@ nocache_index_getattr(IndexTuple tup, ...@@ -312,6 +315,7 @@ nocache_index_getattr(IndexTuple tup,
} }
} }
} }
}
/* /*
* If slow is false, and we got here, we know that we have a tuple * If slow is false, and we got here, we know that we have a tuple
...@@ -337,12 +341,7 @@ nocache_index_getattr(IndexTuple tup, ...@@ -337,12 +341,7 @@ nocache_index_getattr(IndexTuple tup,
for (; j <= attnum; j++) for (; j <= attnum; j++)
{ {
/* off = att_align(off, att[j]->attalign);
* Fix me when going to a machine with more than a four-byte
* word!
*/
off = att_align(off, att[j]->attlen, att[j]->attalign);
att[j]->attcacheoff = off; att[j]->attcacheoff = off;
...@@ -377,22 +376,19 @@ nocache_index_getattr(IndexTuple tup, ...@@ -377,22 +376,19 @@ nocache_index_getattr(IndexTuple tup,
off = att[i]->attcacheoff; off = att[i]->attcacheoff;
else else
{ {
off = att_align(off, att[i]->attlen, att[i]->attalign); off = att_align(off, att[i]->attalign);
if (usecache) if (usecache)
att[i]->attcacheoff = off; att[i]->attcacheoff = off;
} }
if (att[i]->attlen == -1) off = att_addlength(off, att[i]->attlen, tp + off);
{
off += VARSIZE(tp + off); if (usecache && att[i]->attlen <= 0)
usecache = false; 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); return fetchatt(att[attnum], tp + off);
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -457,9 +457,15 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
} }
else else
{ {
/* fixed size */ /* fixed size or cstring */
attr = origattr; attr = origattr;
len = typeinfo->attrs[i]->attlen; 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)); pq_sendint(&buf, len, sizeof(int32));
if (typeinfo->attrs[i]->attbyval) if (typeinfo->attrs[i]->attbyval)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -157,14 +157,25 @@ TypeCreate(const char *typeName,
int i; int i;
/* /*
* validate size specifications: either positive (fixed-length) or -1 * We assume that the caller validated the arguments individually,
* (variable-length). * 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", elog(ERROR, "TypeCreate: invalid type internal size %d",
internalSize); 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"); elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -860,6 +860,8 @@ compute_minimal_stats(VacAttrStats *stats,
double total_width = 0; double total_width = 0;
bool is_varlena = (!stats->attr->attbyval && bool is_varlena = (!stats->attr->attbyval &&
stats->attr->attlen == -1); stats->attr->attlen == -1);
bool is_varwidth = (!stats->attr->attbyval &&
stats->attr->attlen < 0);
FmgrInfo f_cmpeq; FmgrInfo f_cmpeq;
typedef struct typedef struct
{ {
...@@ -905,7 +907,7 @@ compute_minimal_stats(VacAttrStats *stats, ...@@ -905,7 +907,7 @@ compute_minimal_stats(VacAttrStats *stats,
nonnull_cnt++; 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 * calculation. Note that if the value is toasted, we use the
* toasted width. We don't bother with this calculation if it's a * toasted width. We don't bother with this calculation if it's a
* fixed-width type. * fixed-width type.
...@@ -928,6 +930,11 @@ compute_minimal_stats(VacAttrStats *stats, ...@@ -928,6 +930,11 @@ compute_minimal_stats(VacAttrStats *stats,
} }
value = PointerGetDatum(PG_DETOAST_DATUM(value)); 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. * See if the value matches anything we're already tracking.
...@@ -984,7 +991,7 @@ compute_minimal_stats(VacAttrStats *stats, ...@@ -984,7 +991,7 @@ compute_minimal_stats(VacAttrStats *stats,
stats->stats_valid = true; stats->stats_valid = true;
/* Do the simple null-frac and width stats */ /* Do the simple null-frac and width stats */
stats->stanullfrac = (double) null_cnt / (double) numrows; stats->stanullfrac = (double) null_cnt / (double) numrows;
if (is_varlena) if (is_varwidth)
stats->stawidth = total_width / (double) nonnull_cnt; stats->stawidth = total_width / (double) nonnull_cnt;
else else
stats->stawidth = stats->attrtype->typlen; stats->stawidth = stats->attrtype->typlen;
...@@ -1157,6 +1164,8 @@ compute_scalar_stats(VacAttrStats *stats, ...@@ -1157,6 +1164,8 @@ compute_scalar_stats(VacAttrStats *stats,
double total_width = 0; double total_width = 0;
bool is_varlena = (!stats->attr->attbyval && bool is_varlena = (!stats->attr->attbyval &&
stats->attr->attlen == -1); stats->attr->attlen == -1);
bool is_varwidth = (!stats->attr->attbyval &&
stats->attr->attlen < 0);
double corr_xysum; double corr_xysum;
RegProcedure cmpFn; RegProcedure cmpFn;
SortFunctionKind cmpFnKind; SortFunctionKind cmpFnKind;
...@@ -1196,7 +1205,7 @@ compute_scalar_stats(VacAttrStats *stats, ...@@ -1196,7 +1205,7 @@ compute_scalar_stats(VacAttrStats *stats,
nonnull_cnt++; 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 * calculation. Note that if the value is toasted, we use the
* toasted width. We don't bother with this calculation if it's a * toasted width. We don't bother with this calculation if it's a
* fixed-width type. * fixed-width type.
...@@ -1219,6 +1228,11 @@ compute_scalar_stats(VacAttrStats *stats, ...@@ -1219,6 +1228,11 @@ compute_scalar_stats(VacAttrStats *stats,
} }
value = PointerGetDatum(PG_DETOAST_DATUM(value)); 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 */ /* Add it to the list to be sorted */
values[values_cnt].value = value; values[values_cnt].value = value;
...@@ -1311,7 +1325,7 @@ compute_scalar_stats(VacAttrStats *stats, ...@@ -1311,7 +1325,7 @@ compute_scalar_stats(VacAttrStats *stats,
stats->stats_valid = true; stats->stats_valid = true;
/* Do the simple null-frac and width stats */ /* Do the simple null-frac and width stats */
stats->stanullfrac = (double) null_cnt / (double) numrows; stats->stanullfrac = (double) null_cnt / (double) numrows;
if (is_varlena) if (is_varwidth)
stats->stawidth = total_width / (double) nonnull_cnt; stats->stawidth = total_width / (double) nonnull_cnt;
else else
stats->stawidth = stats->attrtype->typlen; stats->stawidth = stats->attrtype->typlen;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -567,6 +567,8 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
elog(ERROR, "COPY: couldn't lookup info for type %u", elog(ERROR, "COPY: couldn't lookup info for type %u",
attr[attnum-1]->atttypid); attr[attnum-1]->atttypid);
fmgr_info(out_func_oid, &out_functions[attnum-1]); 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) if (binary)
...@@ -820,9 +822,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, ...@@ -820,9 +822,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
fmgr_info(in_func_oid, &in_functions[i]); fmgr_info(in_func_oid, &in_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid); 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); defexprs[num_defaults] = build_column_default(rel, i + 1);
if (defexprs[num_defaults] != NULL) if (defexprs[num_defaults] != NULL)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -3504,8 +3504,8 @@ needs_toast_table(Relation rel)
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
{ {
data_length = att_align(data_length, att[i]->attlen, att[i]->attalign); data_length = att_align(data_length, att[i]->attalign);
if (att[i]->attlen >= 0) if (att[i]->attlen > 0)
{ {
/* Fixed-length types are never toastable */ /* Fixed-length types are never toastable */
data_length += att[i]->attlen; data_length += att[i]->attlen;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -32,7 +32,7 @@
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
static uint32 hashFunc(Datum key, int len, bool byVal); static uint32 hashFunc(Datum key, int typLen, bool byVal);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecHash * ExecHash
...@@ -632,7 +632,7 @@ ExecScanHashBucket(HashJoinState *hjstate, ...@@ -632,7 +632,7 @@ ExecScanHashBucket(HashJoinState *hjstate,
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static uint32 static uint32
hashFunc(Datum key, int len, bool byVal) hashFunc(Datum key, int typLen, bool byVal)
{ {
unsigned char *k; unsigned char *k;
...@@ -647,13 +647,20 @@ hashFunc(Datum key, int len, bool byVal) ...@@ -647,13 +647,20 @@ hashFunc(Datum key, int len, bool byVal)
* would get the wrong bytes on a big-endian machine. * would get the wrong bytes on a big-endian machine.
*/ */
k = (unsigned char *) &key; k = (unsigned char *) &key;
len = sizeof(Datum); typLen = sizeof(Datum);
} }
else else
{
if (typLen > 0)
{
/* fixed-width pass-by-reference type */
k = (unsigned char *) DatumGetPointer(key);
}
else if (typLen == -1)
{ {
/* /*
* If this is a variable length type, then 'key' points to a * It's a varlena type, so 'key' points to a
* "struct varlena" and len == -1. NOTE: VARSIZE returns the * "struct varlena". NOTE: VARSIZE returns the
* "real" data length plus the sizeof the "vl_len" attribute of * "real" data length plus the sizeof the "vl_len" attribute of
* varlena (the length information). 'key' points to the beginning * varlena (the length information). 'key' points to the beginning
* of the varlena struct, so we have to use "VARDATA" to find the * of the varlena struct, so we have to use "VARDATA" to find the
...@@ -662,18 +669,25 @@ hashFunc(Datum key, int len, bool byVal) ...@@ -662,18 +669,25 @@ hashFunc(Datum key, int len, bool byVal)
* freeing the detoasted copy; that happens for free when the * freeing the detoasted copy; that happens for free when the
* per-tuple memory context is reset in ExecHashGetBucket.) * per-tuple memory context is reset in ExecHashGetBucket.)
*/ */
if (len < 0)
{
struct varlena *vkey = PG_DETOAST_DATUM(key); struct varlena *vkey = PG_DETOAST_DATUM(key);
len = VARSIZE(vkey) - VARHDRSZ; typLen = VARSIZE(vkey) - VARHDRSZ;
k = (unsigned char *) VARDATA(vkey); 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); 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));
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -24,6 +24,7 @@
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "utils/datum.h"
/* /*
...@@ -791,23 +792,17 @@ _copyConst(Const *from) ...@@ -791,23 +792,17 @@ _copyConst(Const *from)
/* /*
* passed by value so just copy the datum. Also, don't try to copy * passed by value so just copy the datum. Also, don't try to copy
* struct when value is null! * struct when value is null!
*
*/ */
newnode->constvalue = from->constvalue; newnode->constvalue = from->constvalue;
} }
else else
{ {
/* /*
* not passed by value. datum contains a pointer. * not passed by value. We need a palloc'd copy.
*/ */
int length = from->constlen; newnode->constvalue = datumCopy(from->constvalue,
from->constbyval,
if (length == -1) /* variable-length type? */ from->constlen);
length = VARSIZE(from->constvalue);
newnode->constvalue = PointerGetDatum(palloc(length));
memcpy(DatumGetPointer(newnode->constvalue),
DatumGetPointer(from->constvalue),
length);
} }
newnode->constisnull = from->constisnull; newnode->constisnull = from->constisnull;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -71,12 +71,12 @@ ...@@ -71,12 +71,12 @@
/* ---------------- /* ----------------
* SendFunctionResult * SendFunctionResult
*
* retlen is 0 if returning NULL, else the typlen according to the catalogs
* ---------------- * ----------------
*/ */
static void static void
SendFunctionResult(Datum retval, /* actual return value */ SendFunctionResult(Datum retval, bool retbyval, int retlen)
bool retbyval,
int retlen) /* the length according to the catalogs */
{ {
StringInfoData buf; StringInfoData buf;
...@@ -93,7 +93,7 @@ SendFunctionResult(Datum retval, /* actual return value */ ...@@ -93,7 +93,7 @@ SendFunctionResult(Datum retval, /* actual return value */
} }
else else
{ /* by-reference ... */ { /* by-reference ... */
if (retlen < 0) if (retlen == -1)
{ /* ... varlena */ { /* ... varlena */
struct varlena *v = (struct varlena *) DatumGetPointer(retval); struct varlena *v = (struct varlena *) DatumGetPointer(retval);
...@@ -177,12 +177,15 @@ fetch_fp_info(Oid func_id, struct fp_info * fip) ...@@ -177,12 +177,15 @@ fetch_fp_info(Oid func_id, struct fp_info * fip)
for (i = 0; i < pp->pronargs; ++i) 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); ReleaseSysCache(func_htp);
...@@ -297,7 +300,7 @@ HandleFunctionRequest(void) ...@@ -297,7 +300,7 @@ HandleFunctionRequest(void)
} }
else else
{ /* by-reference ... */ { /* by-reference ... */
if (fip->arglen[i] < 0) if (fip->arglen[i] == -1)
{ /* ... varlena */ { /* ... varlena */
if (argsize < 0) if (argsize < 0)
elog(ERROR, "HandleFunctionRequest: bogus argsize %d", elog(ERROR, "HandleFunctionRequest: bogus argsize %d",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -19,15 +19,19 @@
* Datum itself (i.e. no pointers involved!). In this case the * Datum itself (i.e. no pointers involved!). In this case the
* length of the type is always greater than zero and not more than * length of the type is always greater than zero and not more than
* "sizeof(Datum)" * "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. * B) if a type is not "byVal" and it has a fixed length (typlen > 0),
* The number of significant bytes are always equal to the length of the * then the "Datum" always contains a pointer to a stream of bytes.
* type. * The number of significant bytes are always equal to the typlen.
* 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". * 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 * This varlena structure has information about the actual length of this
* particular instance of the type and about its value. * 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 * Note that we do not treat "toasted" datums specially; therefore what
* will be copied or compared is the compressed data or toast reference. * will be copied or compared is the compressed data or toast reference.
*/ */
...@@ -36,17 +40,15 @@ ...@@ -36,17 +40,15 @@
#include "utils/datum.h" #include "utils/datum.h"
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* datumGetSize * datumGetSize
* *
* Find the "real" size of a datum, given the datum value, * 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 * This is essentially an out-of-line version of the att_addlength()
* type length, with the exception of variable length types which have * macro in access/tupmacs.h. We do a tad more error checking though.
* 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.
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
Size Size
...@@ -62,19 +64,33 @@ datumGetSize(Datum value, bool typByVal, int typLen) ...@@ -62,19 +64,33 @@ datumGetSize(Datum value, bool typByVal, int typLen)
} }
else 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); struct varlena *s = (struct varlena *) DatumGetPointer(value);
if (!PointerIsValid(s)) if (!PointerIsValid(s))
elog(ERROR, "datumGetSize: Invalid Datum Pointer"); 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 else
{ {
/* Fixed-length pass-by-ref type */ elog(ERROR, "datumGetSize: Invalid typLen %d", typLen);
size = (Size) typLen; size = 0; /* keep compiler quiet */
} }
} }
...@@ -159,7 +175,9 @@ datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen) ...@@ -159,7 +175,9 @@ datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
/* /*
* just compare the two datums. NOTE: just comparing "len" bytes * just compare the two datums. NOTE: just comparing "len" bytes
* will not do the work, because we do not know how these 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); res = (value1 == value2);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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, ...@@ -149,7 +149,7 @@ format_type_internal(Oid type_oid, int32 typemod,
array_base_type = typeform->typelem; array_base_type = typeform->typelem;
if (array_base_type != InvalidOid && if (array_base_type != InvalidOid &&
typeform->typlen < 0 && typeform->typlen == -1 &&
typeform->typtype != 'd') typeform->typtype != 'd')
{ {
/* Switch our attention to the array element type */ /* Switch our attention to the array element type */
...@@ -411,11 +411,11 @@ format_type_internal(Oid type_oid, int32 typemod, ...@@ -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 * 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 * -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. * necessary to look up the type's pg_type tuple here.
* *
* This may appear unrelated to format_type(), but in fact the two routines * This may appear unrelated to format_type(), but in fact the two routines
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -50,24 +50,29 @@ record_out(PG_FUNCTION_ARGS)
/* /*
* cstring_in - input routine for pseudo-type CSTRING. * cstring_in - input routine for pseudo-type CSTRING.
*
* We might as well allow this to support constructs like "foo_in('blah')".
*/ */
Datum Datum
cstring_in(PG_FUNCTION_ARGS) 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. * 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 Datum
cstring_out(PG_FUNCTION_ARGS) 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));
} }
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -92,6 +92,7 @@
#include "catalog/pg_amproc.h" #include "catalog/pg_amproc.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/datum.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/logtape.h" #include "utils/logtape.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
...@@ -607,16 +608,14 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull) ...@@ -607,16 +608,14 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
} }
else else
{ {
int datalen = state->datumTypeLen; Size datalen;
int tuplelen; Size tuplelen;
char *newVal; char *newVal;
if (datalen == -1) /* variable length type? */ datalen = datumGetSize(val, false, state->datumTypeLen);
datalen = VARSIZE((struct varlena *) DatumGetPointer(val));
tuplelen = datalen + MAXALIGN(sizeof(DatumTuple)); tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));
newVal = (char *) palloc(tuplelen); tuple = (DatumTuple *) palloc(tuplelen);
tuple = (DatumTuple *) newVal; newVal = ((char *) tuple) + MAXALIGN(sizeof(DatumTuple));
newVal += MAXALIGN(sizeof(DatumTuple));
memcpy(newVal, DatumGetPointer(val), datalen); memcpy(newVal, DatumGetPointer(val), datalen);
tuple->val = PointerGetDatum(newVal); tuple->val = PointerGetDatum(newVal);
tuple->isNull = false; tuple->isNull = false;
...@@ -959,14 +958,7 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward, ...@@ -959,14 +958,7 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward,
} }
else else
{ {
int datalen = state->datumTypeLen; *val = datumCopy(tuple->val, false, 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);
*isNull = false; *isNull = false;
} }
...@@ -1959,10 +1951,9 @@ writetup_datum(Tuplesortstate *state, int tapenum, void *tup) ...@@ -1959,10 +1951,9 @@ writetup_datum(Tuplesortstate *state, int tapenum, void *tup)
tuplen = sizeof(DatumTuple); tuplen = sizeof(DatumTuple);
else else
{ {
int datalen = state->datumTypeLen; Size datalen;
if (datalen == -1) /* variable length type? */ datalen = datumGetSize(tuple->val, false, state->datumTypeLen);
datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
tuplen = datalen + MAXALIGN(sizeof(DatumTuple)); tuplen = datalen + MAXALIGN(sizeof(DatumTuple));
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright 2000-2002 by PostgreSQL Global Development Group * 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 "postgres_fe.h"
#include "describe.h" #include "describe.h"
...@@ -196,7 +196,7 @@ describeTypes(const char *pattern, bool verbose) ...@@ -196,7 +196,7 @@ describeTypes(const char *pattern, bool verbose)
if (verbose) if (verbose)
appendPQExpBuffer(&buf, appendPQExpBuffer(&buf,
" t.typname AS \"%s\",\n" " 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" " THEN CAST('var' AS pg_catalog.text)\n"
" ELSE CAST(t.typlen AS pg_catalog.text)\n" " ELSE CAST(t.typlen AS pg_catalog.text)\n"
" END AS \"%s\",\n", " END AS \"%s\",\n",
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -93,12 +93,11 @@
#endif /* SIZEOF_DATUM == 8 */ #endif /* SIZEOF_DATUM == 8 */
/* /*
* att_align aligns the given offset as needed for a datum of length attlen * att_align aligns the given offset as needed for a datum of alignment
* and alignment requirement attalign. In practice we don't need the length. * requirement attalign. The cases are tested in what is hopefully something
* The attalign cases are tested in what is hopefully something like their * like their frequency of occurrence.
* frequency of occurrence.
*/ */
#define att_align(cur_offset, attlen, attalign) \ #define att_align(cur_offset, attalign) \
( \ ( \
((attalign) == 'i') ? INTALIGN(cur_offset) : \ ((attalign) == 'i') ? INTALIGN(cur_offset) : \
(((attalign) == 'c') ? ((long)(cur_offset)) : \ (((attalign) == 'c') ? ((long)(cur_offset)) : \
...@@ -111,18 +110,23 @@ ...@@ -111,18 +110,23 @@
/* /*
* att_addlength increments the given offset by the length of the attribute. * 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) \ #define att_addlength(cur_offset, attlen, attval) \
( \ ( \
((attlen) != -1) ? \ ((attlen) > 0) ? \
( \ ( \
(cur_offset) + (attlen) \ (cur_offset) + (attlen) \
) \ ) \
: \ : (((attlen) == -1) ? \
( \ ( \
(cur_offset) + VARATT_SIZE(DatumGetPointer(attval)) \ (cur_offset) + VARATT_SIZE(DatumGetPointer(attval)) \
) \ ) \
: \
( \
AssertMacro((attlen) == -2), \
(cur_offset) + (strlen(DatumGetCString(attval)) + 1) \
)) \
) )
/* /*
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200208201 #define CATALOG_VERSION_NO 200208231
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -45,7 +45,9 @@ CATALOG(pg_type) BOOTSTRAP ...@@ -45,7 +45,9 @@ CATALOG(pg_type) BOOTSTRAP
/* /*
* For a fixed-size type, typlen is the number of bytes we use to * 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 * 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; int2 typlen;
...@@ -87,7 +89,7 @@ CATALOG(pg_type) BOOTSTRAP ...@@ -87,7 +89,7 @@ CATALOG(pg_type) BOOTSTRAP
* be turned into pseudo-arrays like that. Hence, the way to determine * be turned into pseudo-arrays like that. Hence, the way to determine
* whether a type is a "true" array type is if: * whether a type is a "true" array type is if:
* *
* typelem != 0 and typlen < 0. * typelem != 0 and typlen == -1.
*/ */
Oid typelem; Oid typelem;
...@@ -513,11 +515,11 @@ DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in ...@@ -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_ )); 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 #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 #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_ )); 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 #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 #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_ )); 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 #define VOIDOID 2278
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1138,14 +1138,10 @@ getRowDescriptions(PGconn *conn)
/* /*
* Since pqGetInt treats 2-byte integers as unsigned, we need to * Since pqGetInt treats 2-byte integers as unsigned, we need to
* coerce the special value "-1" to signed form. (-1 is sent for * coerce the result to signed form.
* variable-length fields.) Formerly, libpq effectively did a */
* sign-extension on the 2-byte value by storing it in a signed typlen = (int) ((int16) typlen);
* short. Now we only coerce the single value 65535 == -1; values
* 32768..65534 are taken as valid field lengths.
*/
if (typlen == 0xFFFF)
typlen = -1;
result->attDescs[i].name = pqResultStrdup(result, result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data); conn->workBuffer.data);
result->attDescs[i].typid = typid; result->attDescs[i].typid = typid;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -362,17 +362,13 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo) ...@@ -362,17 +362,13 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
*/ */
if (!fcinfo->isnull && !func->fn_retbyval) if (!fcinfo->isnull && !func->fn_retbyval)
{ {
int len; Size len;
Datum tmp; void *tmp;
if (func->fn_rettyplen < 0) len = datumGetSize(estate.retval, false, func->fn_rettyplen);
len = VARSIZE(estate.retval); tmp = (void *) SPI_palloc(len);
else memcpy(tmp, DatumGetPointer(estate.retval), len);
len = func->fn_rettyplen; estate.retval = PointerGetDatum(tmp);
tmp = (Datum) SPI_palloc(len);
memcpy((void *) tmp, (void *) estate.retval, len);
estate.retval = tmp;
} }
} }
} }
...@@ -2682,7 +2678,7 @@ exec_assign_value(PLpgSQL_execstate * estate, ...@@ -2682,7 +2678,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
if (var->freeval) if (var->freeval)
{ {
pfree((void *) (var->value)); pfree(DatumGetPointer(var->value));
var->freeval = false; var->freeval = false;
} }
...@@ -2705,16 +2701,9 @@ exec_assign_value(PLpgSQL_execstate * estate, ...@@ -2705,16 +2701,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
if (!var->datatype->typbyval && !*isNull) if (!var->datatype->typbyval && !*isNull)
{ {
if (newvalue == value) if (newvalue == value)
{ var->value = datumCopy(newvalue,
int len; false,
var->datatype->typlen);
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);
}
else else
var->value = newvalue; var->value = newvalue;
var->freeval = true; var->freeval = true;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
SELECT p1.oid, p1.typname SELECT p1.oid, p1.typname
FROM pg_type as p1 FROM pg_type as p1
WHERE p1.typnamespace = 0 OR 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 (p1.typtype not in ('b', 'c', 'd', 'p')) OR
NOT p1.typisdefined OR NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR (p1.typalign not in ('c', 's', 'i', 'd')) OR
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
SELECT p1.oid, p1.typname SELECT p1.oid, p1.typname
FROM pg_type as p1 FROM pg_type as p1
WHERE p1.typnamespace = 0 OR 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 (p1.typtype not in ('b', 'c', 'd', 'p')) OR
NOT p1.typisdefined OR NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR (p1.typalign not in ('c', 's', 'i', 'd')) OR
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment