Fix handling of pg_type.typdefault per bug report from Dave Blasby.
If there's anyone out there who's actually using datatype-defined default values, this will be an incompatible change in behavior ... but the old behavior was so broken that I doubt anyone was using it.
This commit is contained in:
parent
f2b604ecf4
commit
6c91eef7b7
@ -1,6 +1,6 @@
|
||||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.22 2001/08/26 16:55:58 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.23 2001/09/06 02:07:41 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="catalogs">
|
||||
@ -243,7 +243,9 @@
|
||||
<entry></entry>
|
||||
<entry>
|
||||
The initial value of the transition state. This is a text
|
||||
field which will be cast to the type of aggtranstype.
|
||||
field containing the initial value in its external string
|
||||
representation. If the field is NULL, the transition state
|
||||
value starts out NULL.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
@ -2071,7 +2073,11 @@
|
||||
<entry>typdefault</entry>
|
||||
<entry><type>text</type></entry>
|
||||
<entry></entry>
|
||||
<entry>???</entry>
|
||||
<entry><para>
|
||||
<structfield>typdefault</structfield> is NULL for types without a
|
||||
default value. If it's not NULL, it contains the external string
|
||||
representation of the type's default value.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.175 2001/08/25 18:52:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.176 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -657,7 +657,6 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||
static void
|
||||
AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid)
|
||||
{
|
||||
|
||||
/*
|
||||
* The sizes are set to oid size because it makes implementing sets
|
||||
* MUCH easier, and no one (we hope) uses these fields to figure out
|
||||
@ -666,24 +665,22 @@ AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid)
|
||||
* actually get is the oid of a tuple in the pg_proc catalog, so the
|
||||
* size of the "set" is the size of an oid. Similarly, byval being
|
||||
* true makes sets much easier, and it isn't used by anything else.
|
||||
*
|
||||
* XXX Note the assumption that OIDs are the same size as int4s.
|
||||
*/
|
||||
TypeCreate(typeName, /* type name */
|
||||
new_type_oid, /* preassigned oid for type */
|
||||
new_rel_oid, /* relation oid */
|
||||
sizeof(Oid), /* internal size */
|
||||
sizeof(Oid), /* external size */
|
||||
-1, /* external size */
|
||||
'c', /* type-type (catalog) */
|
||||
',', /* default array delimiter */
|
||||
"int4in", /* input procedure */
|
||||
"int4out", /* output procedure */
|
||||
"int4in", /* receive procedure */
|
||||
"int4out", /* send procedure */
|
||||
"oidin", /* input procedure */
|
||||
"oidout", /* output procedure */
|
||||
"oidin", /* receive procedure */
|
||||
"oidout", /* send procedure */
|
||||
NULL, /* array element type - irrelevant */
|
||||
"-", /* default type value */
|
||||
NULL, /* default type value - none */
|
||||
true, /* passed by value */
|
||||
'i', /* default alignment */
|
||||
'i', /* default alignment - same as for OID */
|
||||
'p'); /* Not TOASTable */
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.62 2001/08/10 15:49:39 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.63 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -51,7 +51,7 @@ TypeGetWithOpenRelation(Relation pg_type_desc,
|
||||
/*
|
||||
* initialize the scan key and begin a scan of pg_type
|
||||
*/
|
||||
ScanKeyEntryInitialize(typeKey,
|
||||
ScanKeyEntryInitialize(&typeKey[0],
|
||||
0,
|
||||
Anum_pg_type_typname,
|
||||
F_NAMEEQ,
|
||||
@ -318,10 +318,18 @@ TypeCreate(char *typeName,
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX comment me
|
||||
* validate size specifications: either positive (fixed-length) or
|
||||
* -1 (variable-length).
|
||||
*/
|
||||
if (externalSize == 0)
|
||||
externalSize = -1; /* variable length */
|
||||
if (! (internalSize > 0 || internalSize == -1))
|
||||
elog(ERROR, "TypeCreate: invalid type internal size %d",
|
||||
internalSize);
|
||||
if (! (externalSize > 0 || externalSize == -1))
|
||||
elog(ERROR, "TypeCreate: invalid type external size %d",
|
||||
externalSize);
|
||||
|
||||
if (internalSize != -1 && storage != 'p')
|
||||
elog(ERROR, "TypeCreate: fixed size types must have storage PLAIN");
|
||||
|
||||
/*
|
||||
* initialize arrays needed by FormHeapTuple
|
||||
@ -330,20 +338,9 @@ TypeCreate(char *typeName,
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
replaces[i] = 'r';
|
||||
values[i] = (Datum) NULL; /* redundant, but nice */
|
||||
values[i] = (Datum) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* Do this so that user-defined types have size -1 instead of zero if
|
||||
* they are variable-length - this is so that everything else in the
|
||||
* backend works.
|
||||
*/
|
||||
|
||||
if (internalSize == 0)
|
||||
internalSize = -1;
|
||||
|
||||
/*
|
||||
* initialize the *values information
|
||||
*/
|
||||
@ -435,15 +432,19 @@ TypeCreate(char *typeName,
|
||||
/*
|
||||
* initialize the default value for this type.
|
||||
*/
|
||||
values[i] = DirectFunctionCall1(textin, /* 17 */
|
||||
CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
|
||||
if (defaultTypeValue)
|
||||
values[i] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(defaultTypeValue));
|
||||
else
|
||||
nulls[i] = 'n';
|
||||
i++; /* 17 */
|
||||
|
||||
/*
|
||||
* open pg_type and begin a scan for the type name.
|
||||
*/
|
||||
pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock);
|
||||
|
||||
ScanKeyEntryInitialize(typeKey,
|
||||
ScanKeyEntryInitialize(&typeKey[0],
|
||||
0,
|
||||
Anum_pg_type_typname,
|
||||
F_NAMEEQ,
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.58 2001/08/03 20:47:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.59 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@ -535,20 +535,20 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
void
|
||||
DefineType(char *typeName, List *parameters)
|
||||
{
|
||||
int16 internalLength = 0; /* int2 */
|
||||
int16 externalLength = 0; /* int2 */
|
||||
int16 internalLength = -1; /* int2 */
|
||||
int16 externalLength = -1; /* int2 */
|
||||
char *elemName = NULL;
|
||||
char *inputName = NULL;
|
||||
char *outputName = NULL;
|
||||
char *sendName = NULL;
|
||||
char *receiveName = NULL;
|
||||
char *defaultValue = NULL; /* Datum */
|
||||
char *defaultValue = NULL;
|
||||
bool byValue = false;
|
||||
char delimiter = DEFAULT_TYPDELIM;
|
||||
char *shadow_type;
|
||||
List *pl;
|
||||
char alignment = 'i'; /* default alignment */
|
||||
char storage = 'p'; /* default storage in TOAST */
|
||||
char storage = 'p'; /* default TOAST storage method */
|
||||
|
||||
/*
|
||||
* Type names must be one character shorter than other names, allowing
|
||||
@ -556,10 +556,8 @@ DefineType(char *typeName, List *parameters)
|
||||
* "_".
|
||||
*/
|
||||
if (strlen(typeName) > (NAMEDATALEN - 2))
|
||||
{
|
||||
elog(ERROR, "DefineType: type names must be %d characters or less",
|
||||
NAMEDATALEN - 2);
|
||||
}
|
||||
|
||||
foreach(pl, parameters)
|
||||
{
|
||||
@ -645,9 +643,6 @@ DefineType(char *typeName, List *parameters)
|
||||
if (outputName == NULL)
|
||||
elog(ERROR, "Define: \"output\" unspecified");
|
||||
|
||||
if (internalLength != -1 && storage != 'p')
|
||||
elog(ERROR, "Define: fixed size types must have storage PLAIN");
|
||||
|
||||
/*
|
||||
* now have TypeCreate do all the real work.
|
||||
*/
|
||||
@ -674,6 +669,9 @@ DefineType(char *typeName, List *parameters)
|
||||
*/
|
||||
shadow_type = makeArrayTypeName(typeName);
|
||||
|
||||
/* alignment must be 'i' or 'd' for arrays */
|
||||
alignment = (alignment == 'd') ? 'd' : 'i';
|
||||
|
||||
TypeCreate(shadow_type, /* type name */
|
||||
InvalidOid, /* preassigned type oid (not done here) */
|
||||
InvalidOid, /* relation oid (n/a here) */
|
||||
@ -688,7 +686,7 @@ DefineType(char *typeName, List *parameters)
|
||||
typeName, /* element type name */
|
||||
NULL, /* never a default type value */
|
||||
false, /* never passed by value */
|
||||
alignment, /* NB: must be 'i' or 'd' for arrays... */
|
||||
alignment, /* see above */
|
||||
'x'); /* ARRAY is always toastable */
|
||||
|
||||
pfree(shadow_type);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.42 2001/03/22 03:59:38 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.43 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -192,45 +192,54 @@ expand_targetlist(List *tlist, int command_type,
|
||||
{
|
||||
case CMD_INSERT:
|
||||
{
|
||||
Datum typedefault = get_typdefault(atttype);
|
||||
int typlen;
|
||||
Const *temp_const;
|
||||
bool hasdefault;
|
||||
Datum typedefault;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
Const *def_const;
|
||||
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
if (COLUMN_IS_DROPPED(att_tup))
|
||||
typedefault = PointerGetDatum(NULL);
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
|
||||
if (typedefault == PointerGetDatum(NULL))
|
||||
typlen = 0;
|
||||
if (att_tup->attisset)
|
||||
{
|
||||
/*
|
||||
* Set attributes are represented as OIDs no
|
||||
* matter what the set element type is, and
|
||||
* the element type's default is irrelevant too.
|
||||
*/
|
||||
hasdefault = false;
|
||||
typedefault = (Datum) 0;
|
||||
typlen = sizeof(Oid);
|
||||
typbyval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Since this is an append or replace, the
|
||||
* size of any set attribute is the size of
|
||||
* the OID used to represent it.
|
||||
*/
|
||||
if (att_tup->attisset)
|
||||
typlen = get_typlen(OIDOID);
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
if (COLUMN_IS_DROPPED(att_tup))
|
||||
{
|
||||
hasdefault = false;
|
||||
typedefault = (Datum) 0;
|
||||
}
|
||||
else
|
||||
typlen = get_typlen(atttype);
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
hasdefault = get_typdefault(atttype,
|
||||
&typedefault);
|
||||
|
||||
get_typlenbyval(atttype, &typlen, &typbyval);
|
||||
}
|
||||
|
||||
temp_const = makeConst(atttype,
|
||||
typlen,
|
||||
typedefault,
|
||||
(typedefault == PointerGetDatum(NULL)),
|
||||
false,
|
||||
false, /* not a set */
|
||||
false);
|
||||
def_const = makeConst(atttype,
|
||||
typlen,
|
||||
typedefault,
|
||||
!hasdefault,
|
||||
typbyval,
|
||||
false, /* not a set */
|
||||
false);
|
||||
|
||||
new_tle = makeTargetEntry(makeResdom(attrno,
|
||||
atttype,
|
||||
-1,
|
||||
pstrdup(attrname),
|
||||
false),
|
||||
(Node *) temp_const);
|
||||
(Node *) def_const);
|
||||
break;
|
||||
}
|
||||
case CMD_UPDATE:
|
||||
|
92
src/backend/utils/cache/lsyscache.c
vendored
92
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.57 2001/08/21 16:36:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.58 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@ -750,23 +750,20 @@ get_typstorage(Oid typid)
|
||||
/*
|
||||
* get_typdefault
|
||||
*
|
||||
* Given a type OID, return the typdefault field associated with that
|
||||
* type, or Datum(NULL) if there is no typdefault. (This implies
|
||||
* that pass-by-value types can't have a default value that has
|
||||
* a representation of zero. Not worth fixing now.)
|
||||
* The result points to palloc'd storage for non-pass-by-value types.
|
||||
* Given a type OID, return the type's default value, if any.
|
||||
* Returns FALSE if there is no default (effectively, default is NULL).
|
||||
* The result points to palloc'd storage for pass-by-reference types.
|
||||
*/
|
||||
Datum
|
||||
get_typdefault(Oid typid)
|
||||
bool
|
||||
get_typdefault(Oid typid, Datum *defaultValue)
|
||||
{
|
||||
HeapTuple typeTuple;
|
||||
Form_pg_type type;
|
||||
struct varlena *typDefault;
|
||||
Oid typinput,
|
||||
typelem;
|
||||
Datum textDefaultVal;
|
||||
bool isNull;
|
||||
int32 dataSize;
|
||||
int32 typLen;
|
||||
bool typByVal;
|
||||
Datum returnValue;
|
||||
char *strDefaultVal;
|
||||
|
||||
typeTuple = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typid),
|
||||
@ -777,66 +774,39 @@ get_typdefault(Oid typid)
|
||||
|
||||
type = (Form_pg_type) GETSTRUCT(typeTuple);
|
||||
|
||||
typinput = type->typinput;
|
||||
typelem = type->typelem;
|
||||
|
||||
/*
|
||||
* First, see if there is a non-null typdefault field (usually there
|
||||
* isn't)
|
||||
* typdefault is potentially null, so don't try to access it as a struct
|
||||
* field. Must do it the hard way with SysCacheGetAttr.
|
||||
*/
|
||||
typDefault = (struct varlena *)
|
||||
DatumGetPointer(SysCacheGetAttr(TYPEOID,
|
||||
typeTuple,
|
||||
Anum_pg_type_typdefault,
|
||||
&isNull));
|
||||
textDefaultVal = SysCacheGetAttr(TYPEOID,
|
||||
typeTuple,
|
||||
Anum_pg_type_typdefault,
|
||||
&isNull);
|
||||
|
||||
if (isNull)
|
||||
{
|
||||
ReleaseSysCache(typeTuple);
|
||||
return PointerGetDatum(NULL);
|
||||
*defaultValue = (Datum) 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, extract/copy the value.
|
||||
*/
|
||||
dataSize = VARSIZE(typDefault) - VARHDRSZ;
|
||||
typLen = type->typlen;
|
||||
typByVal = type->typbyval;
|
||||
/* Convert text datum to C string */
|
||||
strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
|
||||
textDefaultVal));
|
||||
|
||||
if (typByVal)
|
||||
{
|
||||
if (dataSize == typLen)
|
||||
returnValue = fetch_att(VARDATA(typDefault), typByVal, typLen);
|
||||
else
|
||||
returnValue = PointerGetDatum(NULL);
|
||||
}
|
||||
else if (typLen < 0)
|
||||
{
|
||||
/* variable-size type */
|
||||
if (dataSize < 0)
|
||||
returnValue = PointerGetDatum(NULL);
|
||||
else
|
||||
{
|
||||
returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
|
||||
memcpy((char *) DatumGetPointer(returnValue),
|
||||
(char *) typDefault,
|
||||
(int) VARSIZE(typDefault));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fixed-size pass-by-ref type */
|
||||
if (dataSize != typLen)
|
||||
returnValue = PointerGetDatum(NULL);
|
||||
else
|
||||
{
|
||||
returnValue = PointerGetDatum(palloc(dataSize));
|
||||
memcpy((char *) DatumGetPointer(returnValue),
|
||||
VARDATA(typDefault),
|
||||
(int) dataSize);
|
||||
}
|
||||
}
|
||||
/* Convert C string to a value of the given type */
|
||||
*defaultValue = OidFunctionCall3(typinput,
|
||||
CStringGetDatum(strDefaultVal),
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(-1));
|
||||
|
||||
pfree(strDefaultVal);
|
||||
ReleaseSysCache(typeTuple);
|
||||
|
||||
return returnValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -22,7 +22,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.227 2001/08/27 20:33:07 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.228 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1400,7 +1400,10 @@ getTypes(int *numTypes)
|
||||
tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
|
||||
tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
|
||||
tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
|
||||
tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
|
||||
if (PQgetisnull(res, i, i_typdefault))
|
||||
tinfo[i].typdefault = NULL;
|
||||
else
|
||||
tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
|
||||
tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
|
||||
tinfo[i].typalign = strdup(PQgetvalue(res, i, i_typalign));
|
||||
tinfo[i].typstorage = strdup(PQgetvalue(res, i, i_typstorage));
|
||||
@ -3167,8 +3170,10 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
|
||||
"CREATE TYPE %s "
|
||||
"( internallength = %s, externallength = %s,",
|
||||
fmtId(tinfo[i].typname, force_quotes),
|
||||
tinfo[i].typlen,
|
||||
tinfo[i].typprtlen);
|
||||
(strcmp(tinfo[i].typlen, "-1") == 0) ?
|
||||
"variable" : tinfo[i].typlen,
|
||||
(strcmp(tinfo[i].typprtlen, "-1") == 0) ?
|
||||
"variable" : tinfo[i].typprtlen);
|
||||
/* cannot combine these because fmtId uses static result area */
|
||||
appendPQExpBuffer(q, " input = %s,",
|
||||
fmtId(tinfo[i].typinput, force_quotes));
|
||||
@ -3176,9 +3181,14 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
|
||||
fmtId(tinfo[i].typoutput, force_quotes));
|
||||
appendPQExpBuffer(q, " send = %s,",
|
||||
fmtId(tinfo[i].typsend, force_quotes));
|
||||
appendPQExpBuffer(q, " receive = %s, default = ",
|
||||
appendPQExpBuffer(q, " receive = %s",
|
||||
fmtId(tinfo[i].typreceive, force_quotes));
|
||||
formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
|
||||
|
||||
if (tinfo[i].typdefault != NULL)
|
||||
{
|
||||
appendPQExpBuffer(q, ", default = ");
|
||||
formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
|
||||
}
|
||||
|
||||
if (tinfo[i].isArray)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_type.h,v 1.110 2001/08/25 18:52:43 tgl Exp $
|
||||
* $Id: pg_type.h,v 1.111 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -42,11 +42,16 @@ CATALOG(pg_type) BOOTSTRAP
|
||||
int4 typowner;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
int2 typlen;
|
||||
/*
|
||||
* typprtlen was once intended to be the length of the external
|
||||
* representation of a datatype, with the same interpretation as for
|
||||
* typlen. But it's currently unused.
|
||||
*/
|
||||
int2 typprtlen;
|
||||
|
||||
/*
|
||||
@ -66,8 +71,14 @@ CATALOG(pg_type) BOOTSTRAP
|
||||
* anyway?)
|
||||
*/
|
||||
char typtype;
|
||||
|
||||
/*
|
||||
* If typisdefined is false, the entry is only a placeholder (forward
|
||||
* reference). We know the type name, but not yet anything else about it.
|
||||
*/
|
||||
bool typisdefined;
|
||||
char typdelim;
|
||||
|
||||
char typdelim; /* delimiter for arrays of this type */
|
||||
Oid typrelid; /* 0 if not a class type */
|
||||
|
||||
/*
|
||||
@ -82,6 +93,10 @@ CATALOG(pg_type) BOOTSTRAP
|
||||
* typelem != 0 and typlen < 0.
|
||||
*/
|
||||
Oid typelem;
|
||||
|
||||
/*
|
||||
* I/O conversion procedures for the datatype.
|
||||
*/
|
||||
regproc typinput;
|
||||
regproc typoutput;
|
||||
regproc typreceive;
|
||||
@ -123,6 +138,12 @@ CATALOG(pg_type) BOOTSTRAP
|
||||
*/
|
||||
char typstorage;
|
||||
|
||||
/*
|
||||
* typdefault is NULL if the type has no associated default value.
|
||||
* If it's not NULL, it contains the external representation of the
|
||||
* type's default value --- this default is used whenever no per-column
|
||||
* default is specified for a column of the datatype.
|
||||
*/
|
||||
text typdefault; /* VARIABLE LENGTH FIELD */
|
||||
} FormData_pg_type;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: lsyscache.h,v 1.35 2001/08/21 16:36:06 tgl Exp $
|
||||
* $Id: lsyscache.h,v 1.36 2001/09/06 02:07:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -42,7 +42,7 @@ extern int16 get_typlen(Oid typid);
|
||||
extern bool get_typbyval(Oid typid);
|
||||
extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
|
||||
extern char get_typstorage(Oid typid);
|
||||
extern Datum get_typdefault(Oid typid);
|
||||
extern bool get_typdefault(Oid typid, Datum *defaultValue);
|
||||
extern int32 get_typavgwidth(Oid typid, int32 typmod);
|
||||
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
|
||||
extern bool get_attstatsslot(HeapTuple statstuple,
|
||||
|
@ -13,3 +13,28 @@ CREATE TYPE city_budget (
|
||||
output = int44out,
|
||||
element = int4
|
||||
);
|
||||
-- Test type-related default values (broken in releases before PG 7.2)
|
||||
CREATE TYPE int42 (
|
||||
internallength = 4,
|
||||
input = int4in,
|
||||
output = int4out,
|
||||
alignment = int4,
|
||||
default = 42,
|
||||
passedbyvalue
|
||||
);
|
||||
CREATE TYPE text_w_default (
|
||||
internallength = variable,
|
||||
input = textin,
|
||||
output = textout,
|
||||
alignment = int4,
|
||||
default = 'zippo'
|
||||
);
|
||||
CREATE TABLE default_test (f1 text_w_default, f2 int42);
|
||||
INSERT INTO default_test DEFAULT VALUES;
|
||||
SELECT * FROM default_test;
|
||||
f1 | f2
|
||||
-------+----
|
||||
zippo | 42
|
||||
(1 row)
|
||||
|
||||
DROP TABLE default_test;
|
||||
|
@ -16,3 +16,29 @@ CREATE TYPE city_budget (
|
||||
element = int4
|
||||
);
|
||||
|
||||
-- Test type-related default values (broken in releases before PG 7.2)
|
||||
|
||||
CREATE TYPE int42 (
|
||||
internallength = 4,
|
||||
input = int4in,
|
||||
output = int4out,
|
||||
alignment = int4,
|
||||
default = 42,
|
||||
passedbyvalue
|
||||
);
|
||||
|
||||
CREATE TYPE text_w_default (
|
||||
internallength = variable,
|
||||
input = textin,
|
||||
output = textout,
|
||||
alignment = int4,
|
||||
default = 'zippo'
|
||||
);
|
||||
|
||||
CREATE TABLE default_test (f1 text_w_default, f2 int42);
|
||||
|
||||
INSERT INTO default_test DEFAULT VALUES;
|
||||
|
||||
SELECT * FROM default_test;
|
||||
|
||||
DROP TABLE default_test;
|
||||
|
Loading…
Reference in New Issue
Block a user