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:
parent
cf4d885c67
commit
976246cc7e
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,6 +307,7 @@ nocache_index_getattr(IndexTuple tup,
|
||||
int j;
|
||||
|
||||
for (j = 0; j < attnum; j++)
|
||||
{
|
||||
if (att[j]->attlen <= 0)
|
||||
{
|
||||
slow = true;
|
||||
@ -312,6 +315,7 @@ nocache_index_getattr(IndexTuple tup,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If slow is false, and we got here, we know that we have a tuple
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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,13 +647,20 @@ 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 (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
|
||||
* "struct varlena" and len == -1. NOTE: VARSIZE returns the
|
||||
* 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
|
||||
@ -662,18 +669,25 @@ hashFunc(Datum key, int len, bool byVal)
|
||||
* freeing the detoasted copy; that happens for free when the
|
||||
* per-tuple memory context is reset in ExecHashGetBucket.)
|
||||
*/
|
||||
if (len < 0)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
/* 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);
|
||||
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",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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) \
|
||||
)) \
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user