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.
This commit is contained in:
Tom Lane 2002-08-24 15:00:47 +00:00
parent cf4d885c67
commit 976246cc7e
23 changed files with 260 additions and 198 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.53 2002/08/13 17:22:08 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.54 2002/08/24 15:00:45 tgl Exp $
-->
<chapter id="catalogs">
@ -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.

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.78 2002/07/20 05:16:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.79 2002/08/24 15:00:45 tgl Exp $
*
* NOTES
* The old interface functions have been converted to macros
@ -48,7 +48,7 @@ ComputeDataSize(TupleDesc tupleDesc,
if (nulls[i] != ' ')
continue;
data_length = att_align(data_length, att[i]->attlen, att[i]->attalign);
data_length = att_align(data_length, att[i]->attalign);
data_length = att_addlength(data_length, att[i]->attlen, value[i]);
}
@ -69,7 +69,7 @@ DataFill(char *data,
{
bits8 *bitP = 0;
int bitmask = 0;
uint32 data_length;
Size data_length;
int i;
int numberOfAttributes = tupleDesc->natts;
Form_pg_attribute *att = tupleDesc->attrs;
@ -105,12 +105,13 @@ DataFill(char *data,
}
/* XXX we are aligning the pointer itself, not the offset */
data = (char *) att_align((long) data, att[i]->attlen, att[i]->attalign);
data = (char *) att_align((long) data, att[i]->attalign);
if (att[i]->attbyval)
{
/* pass-by-value */
store_att_byval(data, value[i], att[i]->attlen);
data_length = att[i]->attlen;
}
else if (att[i]->attlen == -1)
{
@ -123,15 +124,22 @@ DataFill(char *data,
data_length = VARATT_SIZE(DatumGetPointer(value[i]));
memcpy(data, DatumGetPointer(value[i]), data_length);
}
else if (att[i]->attlen == -2)
{
/* cstring */
*infomask |= HEAP_HASVARLENA;
data_length = strlen(DatumGetCString(value[i])) + 1;
memcpy(data, DatumGetPointer(value[i]), data_length);
}
else
{
/* fixed-length pass-by-reference */
Assert(att[i]->attlen >= 0);
memcpy(data, DatumGetPointer(value[i]),
(size_t) (att[i]->attlen));
Assert(att[i]->attlen > 0);
data_length = att[i]->attlen;
memcpy(data, DatumGetPointer(value[i]), data_length);
}
data = (char *) att_addlength((long) data, att[i]->attlen, value[i]);
data += data_length;
}
}
@ -235,7 +243,8 @@ nocachegetattr(HeapTuple tuple,
if (att[attnum]->attcacheoff != -1)
{
return fetchatt(att[attnum],
(char *) tup + tup->t_hoff + att[attnum]->attcacheoff);
(char *) tup + tup->t_hoff +
att[attnum]->attcacheoff);
}
#endif
}
@ -243,9 +252,7 @@ nocachegetattr(HeapTuple tuple,
{
/*
* there's a null somewhere in the tuple
*/
/*
*
* check to see if desired att is null
*/
@ -346,11 +353,7 @@ nocachegetattr(HeapTuple tuple,
(HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
(HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
{
/*
* Fix me when going to a machine with more than a four-byte
* word!
*/
off = att_align(off, att[j]->attlen, att[j]->attalign);
off = att_align(off, att[j]->attalign);
att[j]->attcacheoff = off;
@ -391,7 +394,7 @@ nocachegetattr(HeapTuple tuple,
off = att[i]->attcacheoff;
else
{
off = att_align(off, att[i]->attlen, att[i]->attalign);
off = att_align(off, att[i]->attalign);
if (usecache)
att[i]->attcacheoff = off;
@ -399,11 +402,11 @@ nocachegetattr(HeapTuple tuple,
off = att_addlength(off, att[i]->attlen, tp + off);
if (usecache && att[i]->attlen == -1)
if (usecache && att[i]->attlen <= 0)
usecache = false;
}
off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
off = att_align(off, att[attnum]->attalign);
return fetchatt(att[attnum], tp + off);
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.57 2002/06/20 20:29:24 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.58 2002/08/24 15:00:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -64,7 +64,7 @@ index_formtuple(TupleDesc tupleDescriptor,
untoasted_free[i] = false;
/* Do nothing if value is NULL or not of varlena type */
if (null[i] != ' ' || att->attlen >= 0)
if (null[i] != ' ' || att->attlen != -1)
continue;
/*
@ -243,9 +243,10 @@ nocache_index_getattr(IndexTuple tup,
#endif
}
else
{ /* there's a null somewhere in the tuple */
{
/*
* there's a null somewhere in the tuple
*
* check to see if desired att is null
*/
@ -291,8 +292,9 @@ nocache_index_getattr(IndexTuple tup,
tp = (char *) tup + data_off;
/* now check for any non-fixed length attrs before our attribute */
/*
* now check for any non-fixed length attrs before our attribute
*/
if (!slow)
{
if (att[attnum]->attcacheoff != -1)
@ -305,11 +307,13 @@ nocache_index_getattr(IndexTuple tup,
int j;
for (j = 0; j < attnum; j++)
{
if (att[j]->attlen <= 0)
{
slow = true;
break;
}
}
}
}
@ -337,12 +341,7 @@ nocache_index_getattr(IndexTuple tup,
for (; j <= attnum; j++)
{
/*
* Fix me when going to a machine with more than a four-byte
* word!
*/
off = att_align(off, att[j]->attlen, att[j]->attalign);
off = att_align(off, att[j]->attalign);
att[j]->attcacheoff = off;
@ -377,22 +376,19 @@ nocache_index_getattr(IndexTuple tup,
off = att[i]->attcacheoff;
else
{
off = att_align(off, att[i]->attlen, att[i]->attalign);
off = att_align(off, att[i]->attalign);
if (usecache)
att[i]->attcacheoff = off;
}
if (att[i]->attlen == -1)
{
off += VARSIZE(tp + off);
off = att_addlength(off, att[i]->attlen, tp + off);
if (usecache && att[i]->attlen <= 0)
usecache = false;
}
else
off += att[i]->attlen;
}
off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
off = att_align(off, att[attnum]->attalign);
return fetchatt(att[attnum], tp + off);
}

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.63 2002/08/22 00:01:41 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -457,9 +457,15 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
}
else
{
/* fixed size */
/* fixed size or cstring */
attr = origattr;
len = typeinfo->attrs[i]->attlen;
if (len <= 0)
{
/* it's a cstring */
Assert(len == -2 && !typeinfo->attrs[i]->attbyval);
len = strlen(DatumGetCString(attr)) + 1;
}
pq_sendint(&buf, len, sizeof(int32));
if (typeinfo->attrs[i]->attbyval)
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.78 2002/08/15 16:36:01 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.79 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -157,14 +157,25 @@ TypeCreate(const char *typeName,
int i;
/*
* validate size specifications: either positive (fixed-length) or -1
* (variable-length).
* We assume that the caller validated the arguments individually,
* but did not check for bad combinations.
*
* Validate size specifications: either positive (fixed-length) or -1
* (varlena) or -2 (cstring). Pass-by-value types must have a fixed
* length not more than sizeof(Datum).
*/
if (!(internalSize > 0 || internalSize == -1))
if (!(internalSize > 0 ||
internalSize == -1 ||
internalSize == -2))
elog(ERROR, "TypeCreate: invalid type internal size %d",
internalSize);
if (passedByValue &&
(internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
elog(ERROR, "TypeCreate: invalid type internal size %d",
internalSize);
if (internalSize != -1 && storage != 'p')
/* Only varlena types can be toasted */
if (storage != 'p' && internalSize != -1)
elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.42 2002/08/11 00:08:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.43 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -860,6 +860,8 @@ compute_minimal_stats(VacAttrStats *stats,
double total_width = 0;
bool is_varlena = (!stats->attr->attbyval &&
stats->attr->attlen == -1);
bool is_varwidth = (!stats->attr->attbyval &&
stats->attr->attlen < 0);
FmgrInfo f_cmpeq;
typedef struct
{
@ -905,7 +907,7 @@ compute_minimal_stats(VacAttrStats *stats,
nonnull_cnt++;
/*
* If it's a varlena field, add up widths for average width
* If it's a variable-width field, add up widths for average width
* calculation. Note that if the value is toasted, we use the
* toasted width. We don't bother with this calculation if it's a
* fixed-width type.
@ -928,6 +930,11 @@ compute_minimal_stats(VacAttrStats *stats,
}
value = PointerGetDatum(PG_DETOAST_DATUM(value));
}
else if (is_varwidth)
{
/* must be cstring */
total_width += strlen(DatumGetCString(value)) + 1;
}
/*
* See if the value matches anything we're already tracking.
@ -984,7 +991,7 @@ compute_minimal_stats(VacAttrStats *stats,
stats->stats_valid = true;
/* Do the simple null-frac and width stats */
stats->stanullfrac = (double) null_cnt / (double) numrows;
if (is_varlena)
if (is_varwidth)
stats->stawidth = total_width / (double) nonnull_cnt;
else
stats->stawidth = stats->attrtype->typlen;
@ -1157,6 +1164,8 @@ compute_scalar_stats(VacAttrStats *stats,
double total_width = 0;
bool is_varlena = (!stats->attr->attbyval &&
stats->attr->attlen == -1);
bool is_varwidth = (!stats->attr->attbyval &&
stats->attr->attlen < 0);
double corr_xysum;
RegProcedure cmpFn;
SortFunctionKind cmpFnKind;
@ -1196,7 +1205,7 @@ compute_scalar_stats(VacAttrStats *stats,
nonnull_cnt++;
/*
* If it's a varlena field, add up widths for average width
* If it's a variable-width field, add up widths for average width
* calculation. Note that if the value is toasted, we use the
* toasted width. We don't bother with this calculation if it's a
* fixed-width type.
@ -1219,6 +1228,11 @@ compute_scalar_stats(VacAttrStats *stats,
}
value = PointerGetDatum(PG_DETOAST_DATUM(value));
}
else if (is_varwidth)
{
/* must be cstring */
total_width += strlen(DatumGetCString(value)) + 1;
}
/* Add it to the list to be sorted */
values[values_cnt].value = value;
@ -1311,7 +1325,7 @@ compute_scalar_stats(VacAttrStats *stats,
stats->stats_valid = true;
/* Do the simple null-frac and width stats */
stats->stanullfrac = (double) null_cnt / (double) numrows;
if (is_varlena)
if (is_varwidth)
stats->stawidth = total_width / (double) nonnull_cnt;
else
stats->stawidth = stats->attrtype->typlen;

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.166 2002/08/22 00:01:42 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.167 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -567,6 +567,8 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
elog(ERROR, "COPY: couldn't lookup info for type %u",
attr[attnum-1]->atttypid);
fmgr_info(out_func_oid, &out_functions[attnum-1]);
if (binary && attr[attnum-1]->attlen == -2)
elog(ERROR, "COPY BINARY: cstring not supported");
}
if (binary)
@ -820,9 +822,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
fmgr_info(in_func_oid, &in_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid);
/* if column not specified, use default value if one exists */
if (!intMember(i + 1, attnumlist))
if (intMember(i + 1, attnumlist))
{
/* attribute is to be copied */
if (binary && attr[i]->attlen == -2)
elog(ERROR, "COPY BINARY: cstring not supported");
}
else
{
/* attribute is NOT to be copied */
/* use default value if one exists */
defexprs[num_defaults] = build_column_default(rel, i + 1);
if (defexprs[num_defaults] != NULL)
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.32 2002/08/22 14:23:36 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.33 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -3504,8 +3504,8 @@ needs_toast_table(Relation rel)
for (i = 0; i < tupdesc->natts; i++)
{
data_length = att_align(data_length, att[i]->attlen, att[i]->attalign);
if (att[i]->attlen >= 0)
data_length = att_align(data_length, att[i]->attalign);
if (att[i]->attlen > 0)
{
/* Fixed-length types are never toastable */
data_length += att[i]->attlen;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: nodeHash.c,v 1.63 2002/06/20 20:29:28 momjian Exp $
* $Id: nodeHash.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -32,7 +32,7 @@
#include "utils/lsyscache.h"
static uint32 hashFunc(Datum key, int len, bool byVal);
static uint32 hashFunc(Datum key, int typLen, bool byVal);
/* ----------------------------------------------------------------
* ExecHash
@ -632,7 +632,7 @@ ExecScanHashBucket(HashJoinState *hjstate,
* ----------------------------------------------------------------
*/
static uint32
hashFunc(Datum key, int len, bool byVal)
hashFunc(Datum key, int typLen, bool byVal)
{
unsigned char *k;
@ -647,33 +647,47 @@ hashFunc(Datum key, int len, bool byVal)
* would get the wrong bytes on a big-endian machine.
*/
k = (unsigned char *) &key;
len = sizeof(Datum);
typLen = sizeof(Datum);
}
else
{
/*
* If this is a variable length type, then 'key' points to a
* "struct varlena" and len == -1. NOTE: VARSIZE returns the
* "real" data length plus the sizeof the "vl_len" attribute of
* varlena (the length information). 'key' points to the beginning
* of the varlena struct, so we have to use "VARDATA" to find the
* beginning of the "real" data. Also, we have to be careful to
* detoast the datum if it's toasted. (We don't worry about
* freeing the detoasted copy; that happens for free when the
* per-tuple memory context is reset in ExecHashGetBucket.)
*/
if (len < 0)
if (typLen > 0)
{
/* fixed-width pass-by-reference type */
k = (unsigned char *) DatumGetPointer(key);
}
else if (typLen == -1)
{
/*
* It's a varlena type, so 'key' points to a
* "struct varlena". NOTE: VARSIZE returns the
* "real" data length plus the sizeof the "vl_len" attribute of
* varlena (the length information). 'key' points to the beginning
* of the varlena struct, so we have to use "VARDATA" to find the
* beginning of the "real" data. Also, we have to be careful to
* detoast the datum if it's toasted. (We don't worry about
* freeing the detoasted copy; that happens for free when the
* per-tuple memory context is reset in ExecHashGetBucket.)
*/
struct varlena *vkey = PG_DETOAST_DATUM(key);
len = VARSIZE(vkey) - VARHDRSZ;
typLen = VARSIZE(vkey) - VARHDRSZ;
k = (unsigned char *) VARDATA(vkey);
}
else
else if (typLen == -2)
{
/* It's a null-terminated C string */
typLen = strlen(DatumGetCString(key)) + 1;
k = (unsigned char *) DatumGetPointer(key);
}
else
{
elog(ERROR, "hashFunc: Invalid typLen %d", typLen);
k = NULL; /* keep compiler quiet */
}
}
return DatumGetUInt32(hash_any(k, len));
return DatumGetUInt32(hash_any(k, typLen));
}
/* ----------------------------------------------------------------

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.204 2002/08/19 15:08:46 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.205 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -24,6 +24,7 @@
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "utils/datum.h"
/*
@ -791,23 +792,17 @@ _copyConst(Const *from)
/*
* passed by value so just copy the datum. Also, don't try to copy
* struct when value is null!
*
*/
newnode->constvalue = from->constvalue;
}
else
{
/*
* not passed by value. datum contains a pointer.
* not passed by value. We need a palloc'd copy.
*/
int length = from->constlen;
if (length == -1) /* variable-length type? */
length = VARSIZE(from->constvalue);
newnode->constvalue = PointerGetDatum(palloc(length));
memcpy(DatumGetPointer(newnode->constvalue),
DatumGetPointer(from->constvalue),
length);
newnode->constvalue = datumCopy(from->constvalue,
from->constbyval,
from->constlen);
}
newnode->constisnull = from->constisnull;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.53 2002/06/20 20:29:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.54 2002/08/24 15:00:46 tgl Exp $
*
* NOTES
* This cruft is the server side of PQfn.
@ -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",

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.23 2002/06/20 20:29:37 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.24 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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)
{
/* Assume it is a varlena datatype */
/* Fixed-length pass-by-ref type */
size = (Size) typLen;
}
else if (typLen == -1)
{
/* 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);
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.31 2002/08/04 06:44:47 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.32 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -149,7 +149,7 @@ format_type_internal(Oid type_oid, int32 typemod,
array_base_type = typeform->typelem;
if (array_base_type != InvalidOid &&
typeform->typlen < 0 &&
typeform->typlen == -1 &&
typeform->typtype != 'd')
{
/* Switch our attention to the array element type */
@ -411,11 +411,11 @@ format_type_internal(Oid type_oid, int32 typemod,
/*
* type_maximum_size --- determine maximum width of a varlena column
* type_maximum_size --- determine maximum width of a variable-width column
*
* If the max width is indeterminate, return -1. In particular, we return
* -1 for any type not known to this routine. We assume the caller has
* already determined that the type is a varlena type, so it's not
* already determined that the type is a variable-width type, so it's not
* necessary to look up the type's pg_type tuple here.
*
* This may appear unrelated to format_type(), but in fact the two routines

View File

@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.1 2002/08/22 00:01:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.2 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -50,24 +50,29 @@ record_out(PG_FUNCTION_ARGS)
/*
* cstring_in - input routine for pseudo-type CSTRING.
*
* We might as well allow this to support constructs like "foo_in('blah')".
*/
Datum
cstring_in(PG_FUNCTION_ARGS)
{
elog(ERROR, "Cannot accept a constant of type %s", "CSTRING");
char *str = PG_GETARG_CSTRING(0);
PG_RETURN_VOID(); /* keep compiler quiet */
PG_RETURN_CSTRING(pstrdup(str));
}
/*
* cstring_out - output routine for pseudo-type CSTRING.
*
* We allow this mainly so that "SELECT some_output_function(...)" does
* what the user will expect.
*/
Datum
cstring_out(PG_FUNCTION_ARGS)
{
elog(ERROR, "Cannot display a value of type %s", "CSTRING");
char *str = PG_GETARG_CSTRING(0);
PG_RETURN_VOID(); /* keep compiler quiet */
PG_RETURN_CSTRING(pstrdup(str));
}

View File

@ -78,7 +78,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.25 2002/08/12 00:36:12 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.26 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -92,6 +92,7 @@
#include "catalog/pg_amproc.h"
#include "catalog/pg_operator.h"
#include "miscadmin.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/logtape.h"
#include "utils/lsyscache.h"
@ -607,16 +608,14 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
}
else
{
int datalen = state->datumTypeLen;
int tuplelen;
Size datalen;
Size tuplelen;
char *newVal;
if (datalen == -1) /* variable length type? */
datalen = VARSIZE((struct varlena *) DatumGetPointer(val));
datalen = datumGetSize(val, false, state->datumTypeLen);
tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));
newVal = (char *) palloc(tuplelen);
tuple = (DatumTuple *) newVal;
newVal += MAXALIGN(sizeof(DatumTuple));
tuple = (DatumTuple *) palloc(tuplelen);
newVal = ((char *) tuple) + MAXALIGN(sizeof(DatumTuple));
memcpy(newVal, DatumGetPointer(val), datalen);
tuple->val = PointerGetDatum(newVal);
tuple->isNull = false;
@ -959,14 +958,7 @@ tuplesort_getdatum(Tuplesortstate *state, bool forward,
}
else
{
int datalen = state->datumTypeLen;
char *newVal;
if (datalen == -1) /* variable length type? */
datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
newVal = (char *) palloc(datalen);
memcpy(newVal, DatumGetPointer(tuple->val), datalen);
*val = PointerGetDatum(newVal);
*val = datumCopy(tuple->val, false, state->datumTypeLen);
*isNull = false;
}
@ -1959,10 +1951,9 @@ writetup_datum(Tuplesortstate *state, int tapenum, void *tup)
tuplen = sizeof(DatumTuple);
else
{
int datalen = state->datumTypeLen;
Size datalen;
if (datalen == -1) /* variable length type? */
datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
datalen = datumGetSize(tuple->val, false, state->datumTypeLen);
tuplen = datalen + MAXALIGN(sizeof(DatumTuple));
}

View File

@ -3,7 +3,7 @@
*
* Copyright 2000-2002 by PostgreSQL Global Development Group
*
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.63 2002/08/22 00:01:47 tgl Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.64 2002/08/24 15:00:46 tgl Exp $
*/
#include "postgres_fe.h"
#include "describe.h"
@ -196,7 +196,7 @@ describeTypes(const char *pattern, bool verbose)
if (verbose)
appendPQExpBuffer(&buf,
" t.typname AS \"%s\",\n"
" CASE WHEN t.typlen = -1\n"
" CASE WHEN t.typlen < 0\n"
" THEN CAST('var' AS pg_catalog.text)\n"
" ELSE CAST(t.typlen AS pg_catalog.text)\n"
" END AS \"%s\",\n",

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: tupmacs.h,v 1.21 2002/06/20 20:29:43 momjian Exp $
* $Id: tupmacs.h,v 1.22 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -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) \
)) \
)
/*

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.151 2002/08/22 00:01:47 tgl Exp $
* $Id: catversion.h,v 1.152 2002/08/24 15:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200208201
#define CATALOG_VERSION_NO 200208231
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_type.h,v 1.128 2002/08/22 00:01:48 tgl Exp $
* $Id: pg_type.h,v 1.129 2002/08/24 15:00:46 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -45,7 +45,9 @@ CATALOG(pg_type) BOOTSTRAP
/*
* For a fixed-size type, typlen is the number of bytes we use to
* represent a value of this type, e.g. 4 for an int4. But for a
* variable-length type, typlen is -1.
* variable-length type, typlen is negative. We use -1 to indicate
* a "varlena" type (one that has a length word), -2 to indicate a
* null-terminated C string.
*/
int2 typlen;
@ -87,7 +89,7 @@ CATALOG(pg_type) BOOTSTRAP
* be turned into pseudo-arrays like that. Hence, the way to determine
* whether a type is a "true" array type is if:
*
* typelem != 0 and typlen < 0.
* typelem != 0 and typlen == -1.
*/
Oid typelem;
@ -513,11 +515,11 @@ DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in
*/
DATA(insert OID = 2249 ( record PGNSP PGUID 4 t p t \054 0 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
#define RECORDOID 2249
DATA(insert OID = 2275 ( cstring PGNSP PGUID 4 t p t \054 0 0 cstring_in cstring_out i p f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out c p f 0 -1 0 _null_ _null_ ));
#define CSTRINGOID 2275
DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p t \054 0 0 any_in any_out i p f 0 -1 0 _null_ _null_ ));
#define ANYOID 2276
DATA(insert OID = 2277 ( anyarray PGNSP PGUID 4 t p t \054 0 0 anyarray_in anyarray_out i p f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out i x f 0 -1 0 _null_ _null_ ));
#define ANYARRAYOID 2277
DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p t \054 0 0 void_in void_out i p f 0 -1 0 _null_ _null_ ));
#define VOIDOID 2278

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.120 2002/06/20 20:29:53 momjian Exp $
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.121 2002/08/24 15:00:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1138,14 +1138,10 @@ getRowDescriptions(PGconn *conn)
/*
* Since pqGetInt treats 2-byte integers as unsigned, we need to
* coerce the special value "-1" to signed form. (-1 is sent for
* variable-length fields.) Formerly, libpq effectively did a
* sign-extension on the 2-byte value by storing it in a signed
* short. Now we only coerce the single value 65535 == -1; values
* 32768..65534 are taken as valid field lengths.
* coerce the result to signed form.
*/
if (typlen == 0xFFFF)
typlen = -1;
typlen = (int) ((int16) typlen);
result->attDescs[i].name = pqResultStrdup(result,
conn->workBuffer.data);
result->attDescs[i].typid = typid;

View File

@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.57 2002/08/20 05:28:23 momjian Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.58 2002/08/24 15:00:47 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -362,17 +362,13 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
*/
if (!fcinfo->isnull && !func->fn_retbyval)
{
int len;
Datum tmp;
Size len;
void *tmp;
if (func->fn_rettyplen < 0)
len = VARSIZE(estate.retval);
else
len = func->fn_rettyplen;
tmp = (Datum) SPI_palloc(len);
memcpy((void *) tmp, (void *) estate.retval, len);
estate.retval = tmp;
len = datumGetSize(estate.retval, false, func->fn_rettyplen);
tmp = (void *) SPI_palloc(len);
memcpy(tmp, DatumGetPointer(estate.retval), len);
estate.retval = PointerGetDatum(tmp);
}
}
}
@ -2682,7 +2678,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
if (var->freeval)
{
pfree((void *) (var->value));
pfree(DatumGetPointer(var->value));
var->freeval = false;
}
@ -2705,16 +2701,9 @@ exec_assign_value(PLpgSQL_execstate * estate,
if (!var->datatype->typbyval && !*isNull)
{
if (newvalue == value)
{
int len;
if (var->datatype->typlen < 0)
len = VARSIZE(newvalue);
else
len = var->datatype->typlen;
var->value = (Datum) palloc(len);
memcpy((void *) (var->value), (void *) newvalue, len);
}
var->value = datumCopy(newvalue,
false,
var->datatype->typlen);
else
var->value = newvalue;
var->freeval = true;

View File

@ -16,7 +16,7 @@
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1) OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR

View File

@ -19,7 +19,7 @@
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1) OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR