summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/heap.c158
-rw-r--r--src/backend/catalog/pg_type.c65
-rw-r--r--src/backend/commands/creatinh.c93
-rw-r--r--src/backend/commands/define.c363
-rw-r--r--src/backend/commands/remove.c59
-rw-r--r--src/backend/nodes/copyfuncs.c15
-rw-r--r--src/backend/nodes/equalfuncs.c16
-rw-r--r--src/backend/optimizer/prep/preptlist.c53
-rw-r--r--src/backend/parser/gram.y66
-rw-r--r--src/backend/parser/keywords.c3
-rw-r--r--src/backend/parser/parse_coerce.c32
-rw-r--r--src/backend/parser/parse_expr.c7
-rw-r--r--src/backend/tcop/utility.c17
-rw-r--r--src/backend/utils/adt/format_type.c28
-rw-r--r--src/backend/utils/cache/lsyscache.c63
-rw-r--r--src/backend/utils/cache/relcache.c10
16 files changed, 904 insertions, 144 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 61fc2a451b..2b55700f3a 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.184 2002/03/06 06:09:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.185 2002/03/06 20:34:45 momjian Exp $
*
*
* INTERFACE ROUTINES
@@ -698,10 +698,15 @@ AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid)
"oidin", /* receive procedure */
"oidout", /* send procedure */
NULL, /* array element type - irrelevant */
+ NULL, /* baseType Name -- typically for domiains */
NULL, /* default type value - none */
+ NULL, /* default type binary representation */
true, /* passed by value */
'i', /* default alignment - same as for OID */
- 'p'); /* Not TOASTable */
+ 'p', /* Not TOASTable */
+ -1, /* Type mod length */
+ 0, /* array dimensions for typBaseType */
+ false); /* Type NOT NULL */
}
/* --------------------------------
@@ -1584,6 +1589,10 @@ AddRelationRawConstraints(Relation rel,
int numchecks;
List *listptr;
+ /* Probably shouldn't be null by default */
+ Node *expr = NULL;
+
+
/*
* Get info about existing constraints.
*/
@@ -1614,68 +1623,13 @@ AddRelationRawConstraints(Relation rel,
foreach(listptr, rawColDefaults)
{
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
- Node *expr;
- Oid type_id;
-
- Assert(colDef->raw_default != NULL);
-
- /*
- * Transform raw parsetree to executable expression.
- */
- expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
-
- /*
- * Make sure default expr does not refer to any vars.
- */
- if (contain_var_clause(expr))
- elog(ERROR, "cannot use column references in DEFAULT clause");
-
- /*
- * No subplans or aggregates, either...
- */
- if (contain_subplans(expr))
- elog(ERROR, "cannot use subselects in DEFAULT clause");
- if (contain_agg_clause(expr))
- elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
- /*
- * Check that it will be possible to coerce the expression to the
- * column's type. We store the expression without coercion,
- * however, to avoid premature coercion in cases like
- *
- * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
- *
- * NB: this should match the code in optimizer/prep/preptlist.c that
- * will actually do the coercion, to ensure we don't accept an
- * unusable default expression.
- */
- type_id = exprType(expr);
- if (type_id != InvalidOid)
- {
- Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
- if (type_id != atp->atttypid)
- {
- if (CoerceTargetExpr(NULL, expr, type_id,
- atp->atttypid, atp->atttypmod) == NULL)
- elog(ERROR, "Column \"%s\" is of type %s"
- " but default expression is of type %s"
- "\n\tYou will need to rewrite or cast the expression",
- NameStr(atp->attname),
- format_type_be(atp->atttypid),
- format_type_be(type_id));
- }
- }
+ Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
- /*
- * Might as well try to reduce any constant expressions.
- */
- expr = eval_const_expressions(expr);
-
- /*
- * Must fix opids, in case any operators remain...
- */
- fix_opids(expr);
+ expr = cookDefault(pstate, colDef->raw_default
+ , atp->atttypid, atp->atttypmod
+ , NameStr(atp->attname));
/*
* OK, store it.
@@ -1892,6 +1846,88 @@ SetRelationNumChecks(Relation rel, int numchecks)
heap_close(relrel, RowExclusiveLock);
}
+/*
+ * Take a raw default and convert it to a cooked format ready for
+ * storage.
+ *
+ * Parse state, attypid, attypmod and attname are required for
+ * CoerceTargetExpr() and more importantly transformExpr().
+ */
+Node *
+cookDefault(ParseState *pstate
+ , Node *raw_default
+ , Oid atttypid
+ , int32 atttypmod
+ , char *attname) {
+
+ Oid type_id;
+ Node *expr;
+
+ Assert(raw_default != NULL);
+
+ /*
+ * Transform raw parsetree to executable expression.
+ */
+ expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
+
+ /*
+ * Make sure default expr does not refer to any vars.
+ */
+ if (contain_var_clause(expr))
+ elog(ERROR, "cannot use column references in DEFAULT clause");
+
+ /*
+ * No subplans or aggregates, either...
+ */
+ if (contain_subplans(expr))
+ elog(ERROR, "cannot use subselects in DEFAULT clause");
+ if (contain_agg_clause(expr))
+ elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
+
+ /*
+ * Check that it will be possible to coerce the expression to the
+ * column's type. We store the expression without coercion,
+ * however, to avoid premature coercion in cases like
+ *
+ * CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
+ *
+ * NB: this should match the code in optimizer/prep/preptlist.c that
+ * will actually do the coercion, to ensure we don't accept an
+ * unusable default expression.
+ */
+ type_id = exprType(expr);
+ if (type_id != InvalidOid && atttypid != InvalidOid) {
+ if (type_id != atttypid) {
+
+ /* Try coercing to the base type of the domain if available */
+ if (CoerceTargetExpr(pstate, expr, type_id,
+ getBaseType(atttypid),
+ atttypmod) == NULL) {
+
+ elog(ERROR, "Column \"%s\" is of type %s"
+ " but default expression is of type %s"
+ "\n\tYou will need to rewrite or cast the expression",
+ attname,
+ format_type_be(atttypid),
+ format_type_be(type_id));
+ }
+ }
+ }
+
+ /*
+ * Might as well try to reduce any constant expressions.
+ */
+ expr = eval_const_expressions(expr);
+
+ /*
+ * Must fix opids, in case any operators remain...
+ */
+ fix_opids(expr);
+
+ return(expr);
+}
+
+
static void
RemoveAttrDefaults(Relation rel)
{
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index f14d06e0e2..9991465a61 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.65 2001/10/25 05:49:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.66 2002/03/06 20:34:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -178,8 +178,13 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
values[i++] = CharGetDatum('i'); /* 15 */
values[i++] = CharGetDatum('p'); /* 16 */
+ values[i++] = BoolGetDatum(false); /* 17 */
+ values[i++] = Int32GetDatum(-1); /* 18 */
values[i++] = DirectFunctionCall1(textin,
- CStringGetDatum(typeName)); /* 17 */
+ CStringGetDatum(typeName)); /* 19 */
+ values[i++] = DirectFunctionCall1(textin,
+ CStringGetDatum(typeName)); /* 20 */
+
/*
* create a new type tuple with FormHeapTuple
@@ -264,7 +269,7 @@ TypeShellMake(char *typeName)
Oid
TypeCreate(char *typeName,
Oid assignedTypeOid,
- Oid relationOid, /* only for 'c'atalog typeTypes */
+ Oid relationOid, /* only for 'c'atalog typeTypes */
int16 internalSize,
int16 externalSize,
char typeType,
@@ -274,10 +279,15 @@ TypeCreate(char *typeName,
char *receiveProcedure,
char *sendProcedure,
char *elementTypeName,
- char *defaultTypeValue, /* internal rep */
+ char *baseTypeName,
+ char *defaultTypeValue, /* human readable rep */
+ char *defaultTypeBin, /* cooked rep */
bool passedByValue,
char alignment,
- char storage)
+ char storage,
+ int32 typeMod,
+ int32 typNDims, /* Array dimensions for baseTypeName */
+ bool typeNotNull) /* binary default representation (cooked) */
{
int i,
j;
@@ -285,6 +295,7 @@ TypeCreate(char *typeName,
HeapScanDesc pg_type_scan;
Oid typeObjectId;
Oid elementObjectId = InvalidOid;
+ Oid baseObjectId = InvalidOid;
HeapTuple tup;
char nulls[Natts_pg_type];
char replaces[Natts_pg_type];
@@ -318,6 +329,17 @@ TypeCreate(char *typeName,
}
/*
+ * if this type has an associated baseType, then we check that it
+ * is defined.
+ */
+ if (baseTypeName)
+ {
+ baseObjectId = TypeGet(baseTypeName, &defined);
+ if (!defined)
+ elog(ERROR, "type %s does not exist", baseTypeName);
+ }
+
+ /*
* validate size specifications: either positive (fixed-length) or -1
* (variable-length).
*/
@@ -388,7 +410,7 @@ TypeCreate(char *typeName,
* signature is 0,OIDOID,INT4OID. The output procedures may
* take 2 args (data value, element OID).
*/
- if (OidIsValid(elementObjectId))
+ if (OidIsValid(elementObjectId) || OidIsValid(baseObjectId))
{
int nargs;
@@ -411,6 +433,7 @@ TypeCreate(char *typeName,
PointerGetDatum(argList),
0);
}
+
if (!OidIsValid(procOid))
func_error("TypeCreate", procname, 1, argList, NULL);
}
@@ -429,6 +452,34 @@ TypeCreate(char *typeName,
values[i++] = CharGetDatum(storage); /* 16 */
/*
+ * set the typenotnull value
+ */
+ values[i++] = BoolGetDatum(typeNotNull); /* 17 */
+
+ /*
+ * set the typemod value
+ */
+ values[i++] = Int32GetDatum(typeMod); /* 18 */
+
+ values[i++] = ObjectIdGetDatum(baseObjectId); /* 19 */
+
+ /*
+ * Dimension number for an array base type
+ */
+ values[i++] = Int32GetDatum(typNDims); /* 20 */
+
+ /*
+ * initialize the default binary value for this type. Check for
+ * nulls of course.
+ */
+ if (defaultTypeBin)
+ values[i] = DirectFunctionCall1(textin,
+ CStringGetDatum(defaultTypeBin));
+ else
+ nulls[i] = 'n';
+ i++; /* 21 */
+
+ /*
* initialize the default value for this type.
*/
if (defaultTypeValue)
@@ -436,7 +487,7 @@ TypeCreate(char *typeName,
CStringGetDatum(defaultTypeValue));
else
nulls[i] = 'n';
- i++; /* 17 */
+ i++; /* 22 */
/*
* open pg_type and begin a scan for the type name.
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index 27535429c3..586cee63cc 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.83 2002/03/06 06:09:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.84 2002/03/06 20:34:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,7 +39,7 @@ static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
-
+static List *MergeDomainAttributes(List *schema);
/* ----------------------------------------------------------------
* DefineRelation
@@ -70,6 +70,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
StrNCpy(relname, stmt->relname, NAMEDATALEN);
/*
+ * Merge domain attributes into the known columns before inheritance
+ * applies it's changes otherwise we risk adding double constraints
+ * to a domain thats inherited.
+ */
+ schema = MergeDomainAttributes(schema);
+
+ /*
* Look up inheritance ancestors and generate relation schema,
* including inherited attributes.
*/
@@ -237,6 +244,88 @@ TruncateRelation(char *name)
heap_truncate(name);
}
+
+/*
+ * MergeDomainAttributes
+ * Returns a new schema with the constraints, types, and other
+ * attributes of the domain resolved.
+ *
+ * Defaults are processed at execution time by taking the default of
+ * the type (domain) if it is null. This does not need to be merged
+ * here.
+ */
+static List *
+MergeDomainAttributes(List *schema)
+{
+ List *entry;
+
+ /*
+ * Loop through the table elements supplied. These should
+ * never include inherited domains else they'll be
+ * double (or more) processed.
+ */
+ foreach(entry, schema)
+ {
+ ColumnDef *coldef = lfirst(entry);
+ HeapTuple tuple;
+ Form_pg_type typeTup;
+
+
+ tuple = SearchSysCache(TYPENAME,
+ CStringGetDatum(coldef->typename->name),
+ 0,0,0);
+
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
+ coldef->typename->name);
+
+ typeTup = (Form_pg_type) GETSTRUCT(tuple);
+ if (typeTup->typtype == 'd') {
+ /*
+ * This is a domain, lets force the properties of the domain on to
+ * the new column.
+ */
+
+ /* Enforce the typmod value */
+ coldef->typename->typmod = typeTup->typmod;
+
+ /* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
+ coldef->is_not_null |= typeTup->typnotnull;
+
+ /* Enforce the element type in the event the domain is an array
+ *
+ * BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
+ */
+
+ }
+ ReleaseSysCache(tuple);
+
+//typedef struct TypeName
+//{
+ //NodeTag type;
+ //char *name; /* name of the type */
+ //bool timezone; /* timezone specified? */
+ //bool setof; /* is a set? */
+ //int32 typmod; /* type modifier */
+ //List *arrayBounds; /* array bounds */
+ //char *attrname; /* field name when using %TYPE */
+//} TypeName;
+
+// ColumnDef
+// NodeTag type;
+// char *colname; /* name of column */
+// TypeName *typename; /* type of column */
+// bool is_not_null; /* NOT NULL constraint specified? */
+// Node *raw_default; /* default value (untransformed parse
+// * tree) */
+// char *cooked_default; /* nodeToString representation */
+// List *constraints; /* other constraints on column */
+
+ }
+
+ return schema;
+}
+
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 841fc73c30..cb71340eb2 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.67 2002/03/06 06:09:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.68 2002/03/06 20:34:47 momjian Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -40,6 +40,7 @@
#include "access/heapam.h"
#include "catalog/catname.h"
+#include "catalog/heap.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
@@ -476,6 +477,322 @@ DefineAggregate(char *aggName, List *parameters)
}
/*
+ * DefineDomain
+ * Registers a new domain.
+ */
+void
+DefineDomain(CreateDomainStmt *stmt)
+{
+ int16 internalLength = -1; /* int2 */
+ int16 externalLength = -1; /* int2 */
+ char *inputName = NULL;
+ char *outputName = NULL;
+ char *sendName = NULL;
+ char *receiveName = NULL;
+
+ /*
+ * Domains store the external representation in defaultValue
+ * and the interal Node representation in defaultValueBin
+ */
+ char *defaultValue = NULL;
+ char *defaultValueBin = NULL;
+
+ bool byValue = false;
+ char delimiter = DEFAULT_TYPDELIM;
+ char alignment = 'i'; /* default alignment */
+ char storage = 'p'; /* default TOAST storage method */
+ char typtype;
+ Datum datum;
+ bool typNotNull = false;
+ char *elemName = NULL;
+ int32 typNDims = 0; /* No array dimensions by default */
+
+ bool isnull;
+ Relation pg_type_rel;
+ TupleDesc pg_type_dsc;
+ HeapTuple typeTup;
+ char *typeName = stmt->typename->name;
+
+ List *listptr;
+ List *schema = stmt->constraints;
+
+ /*
+ * Domainnames, unlike typenames don't need to account for the '_'
+ * prefix. So they can be one character longer.
+ */
+ if (strlen(stmt->domainname) > (NAMEDATALEN - 1))
+ elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
+ NAMEDATALEN - 1);
+
+
+ /* Test for existing Domain (or type) of that name */
+ typeTup = SearchSysCache( TYPENAME
+ , PointerGetDatum(stmt->domainname)
+ , 0, 0, 0
+ );
+
+ if (HeapTupleIsValid(typeTup))
+ {
+ elog(ERROR, "CREATE DOMAIN: domain or type %s already exists",
+ stmt->domainname);
+ }
+
+ /*
+ * Get the information about old types
+ */
+ pg_type_rel = heap_openr(TypeRelationName, RowExclusiveLock);
+ pg_type_dsc = RelationGetDescr(pg_type_rel);
+
+
+ /*
+ * When the type is an array for some reason we don't actually receive
+ * the name here. We receive the base types name. Lets set Dims while
+ * were at it.
+ */
+ if (stmt->typename->arrayBounds > 0) {
+ typeName = makeArrayTypeName(stmt->typename->name);
+
+ typNDims = length(stmt->typename->arrayBounds);
+ }
+
+
+ typeTup = SearchSysCache( TYPENAME
+ , PointerGetDatum(typeName)
+ , 0, 0, 0
+ );
+
+ if (!HeapTupleIsValid(typeTup))
+ {
+ elog(ERROR, "CREATE DOMAIN: type %s does not exist",
+ stmt->typename->name);
+ }
+
+
+ /* Check that this is a basetype */
+ typtype = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typtype, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /*
+ * What we really don't want is domains of domains. This could cause all sorts
+ * of neat issues if we allow that.
+ *
+ * With testing, we may determine complex types should be allowed
+ */
+ if (typtype != 'b') {
+ elog(ERROR, "DefineDomain: %s is not a basetype", stmt->typename->name);
+ }
+
+ /* passed by value */
+ byValue = DatumGetBool(heap_getattr(typeTup, Anum_pg_type_typbyval, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* Required Alignment */
+ alignment = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typalign, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* Storage Length */
+ internalLength = DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typlen, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* External Length (unused) */
+ externalLength = DatumGetInt16(heap_getattr(typeTup, Anum_pg_type_typprtlen, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* Array element Delimiter */
+ delimiter = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typdelim, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* Input Function Name */
+ datum = heap_getattr(typeTup, Anum_pg_type_typinput, pg_type_dsc, &isnull);
+ Assert(!isnull);
+
+ inputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ /* Output Function Name */
+ datum = heap_getattr(typeTup, Anum_pg_type_typoutput, pg_type_dsc, &isnull);
+ Assert(!isnull);
+
+ outputName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ /* ReceiveName */
+ datum = heap_getattr(typeTup, Anum_pg_type_typreceive, pg_type_dsc, &isnull);
+ Assert(!isnull);
+
+ receiveName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ /* SendName */
+ datum = heap_getattr(typeTup, Anum_pg_type_typsend, pg_type_dsc, &isnull);
+ Assert(!isnull);
+
+ sendName = DatumGetCString(DirectFunctionCall1(regprocout, datum));
+
+ /* TOAST Strategy */
+ storage = DatumGetChar(heap_getattr(typeTup, Anum_pg_type_typstorage, pg_type_dsc, &isnull));
+ Assert(!isnull);
+
+ /* Inherited default value */
+ datum = heap_getattr(typeTup, Anum_pg_type_typdefault, pg_type_dsc, &isnull);
+ if (!isnull) {
+ defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
+ }
+
+ /*
+ * Pull out the typelem name of the parent OID.
+ *
+ * This is what enables us to make a domain of an array
+ */
+ datum = heap_getattr(typeTup, Anum_pg_type_typelem, pg_type_dsc, &isnull);
+ Assert(!isnull);
+
+ if (DatumGetObjectId(datum) != InvalidOid) {
+ HeapTuple tup;
+
+ tup = SearchSysCache( TYPEOID
+ , datum
+ , 0, 0, 0
+ );
+
+ elemName = NameStr(((Form_pg_type) GETSTRUCT(tup))->typname);
+
+ ReleaseSysCache(tup);
+ }
+
+
+ /*
+ * Run through constraints manually avoids the additional
+ * processing conducted by DefineRelation() and friends.
+ *
+ * Besides, we don't want any constraints to be cooked. We'll
+ * do that when the table is created via MergeDomainAttributes().
+ */
+ foreach(listptr, schema)
+ {
+ bool nullDefined = false;
+ Node *expr;
+ Constraint *colDef = lfirst(listptr);
+
+ /* Used for the statement transformation */
+ ParseState *pstate;
+
+ /*
+ * Create a dummy ParseState and insert the target relation as its
+ * sole rangetable entry. We need a ParseState for transformExpr.
+ */
+ pstate = make_parsestate(NULL);
+
+ switch(colDef->contype) {
+ /*
+ * The inherited default value may be overridden by the user
+ * with the DEFAULT <expr> statement.
+ *
+ * We have to search the entire constraint tree returned as we
+ * don't want to cook or fiddle too much.
+ */
+ case CONSTR_DEFAULT:
+
+ /*
+ * Cook the colDef->raw_expr into an expression to ensure
+ * that it can be done. We store the text version of the
+ * raw value.
+ *
+ * Note: Name is strictly for error message
+ */
+ expr = cookDefault(pstate, colDef->raw_expr
+ , typeTup->t_data->t_oid
+ , stmt->typename->typmod
+ , stmt->typename->name);
+
+ /* Binary default required */
+ defaultValue = deparse_expression(expr,
+ deparse_context_for(stmt->domainname,
+ InvalidOid),
+ false);
+
+ defaultValueBin = nodeToString(expr);
+
+ break;
+
+ /*
+ * Find the NULL constraint.
+ */
+ case CONSTR_NOTNULL:
+ if (nullDefined) {
+ elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ } else {
+ typNotNull = true;
+ nullDefined = true;
+ }
+
+ break;
+
+ case CONSTR_NULL:
+ if (nullDefined) {
+ elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+ } else {
+ typNotNull = false;
+ nullDefined = true;
+ }
+
+ break;
+
+ case CONSTR_UNIQUE:
+ elog(ERROR, "CREATE DOMAIN / UNIQUE indecies not supported");
+ break;
+
+ case CONSTR_PRIMARY:
+ elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indecies not supported");
+ break;
+
+
+ case CONSTR_CHECK:
+
+ elog(ERROR, "defineDomain: CHECK Constraints not supported");
+ break;
+
+ case CONSTR_ATTR_DEFERRABLE:
+ case CONSTR_ATTR_NOT_DEFERRABLE:
+ case CONSTR_ATTR_DEFERRED:
+ case CONSTR_ATTR_IMMEDIATE:
+ elog(ERROR, "defineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
+ break;
+ }
+
+ }
+
+ /*
+ * Have TypeCreate do all the real work.
+ */
+ TypeCreate(stmt->domainname, /* type name */
+ InvalidOid, /* preassigned type oid (not done here) */
+ InvalidOid, /* relation oid (n/a here) */
+ internalLength, /* internal size */
+ externalLength, /* external size */
+ 'd', /* type-type (domain type) */
+ delimiter, /* array element delimiter */
+ inputName, /* input procedure */
+ outputName, /* output procedure */
+ receiveName, /* receive procedure */
+ sendName, /* send procedure */
+ elemName, /* element type name */
+ typeName, /* base type name */
+ defaultValue, /* default type value */
+ defaultValueBin, /* default type value */
+ byValue, /* passed by value */
+ alignment, /* required alignment */
+ storage, /* TOAST strategy */
+ stmt->typename->typmod, /* typeMod value */
+ typNDims, /* Array dimensions for base type */
+ typNotNull); /* Type NOT NULL */
+
+ /*
+ * Now we can clean up.
+ */
+ ReleaseSysCache(typeTup);
+ heap_close(pg_type_rel, NoLock);
+}
+
+
+/*
* DefineType
* Registers a new type.
*/
@@ -490,6 +807,8 @@ DefineType(char *typeName, List *parameters)
char *sendName = NULL;
char *receiveName = NULL;
char *defaultValue = NULL;
+ char *defaultValueBin = NULL;
+ Node *defaultRaw = (Node *) NULL;
bool byValue = false;
char delimiter = DEFAULT_TYPDELIM;
char *shadow_type;
@@ -531,7 +850,7 @@ DefineType(char *typeName, List *parameters)
else if (strcasecmp(defel->defname, "element") == 0)
elemName = defGetString(defel);
else if (strcasecmp(defel->defname, "default") == 0)
- defaultValue = defGetString(defel);
+ defaultRaw = defel->arg;
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true;
else if (strcasecmp(defel->defname, "alignment") == 0)
@@ -591,6 +910,32 @@ DefineType(char *typeName, List *parameters)
if (outputName == NULL)
elog(ERROR, "Define: \"output\" unspecified");
+
+ if (defaultRaw) {
+ Node *expr;
+ ParseState *pstate;
+
+ /*
+ * Create a dummy ParseState and insert the target relation as its
+ * sole rangetable entry. We need a ParseState for transformExpr.
+ */
+ pstate = make_parsestate(NULL);
+
+ expr = cookDefault(pstate, defaultRaw,
+ InvalidOid,
+ -1,
+ typeName);
+
+ /* Binary default required */
+ defaultValue = deparse_expression(expr,
+ deparse_context_for(typeName,
+ InvalidOid),
+ false);
+
+ defaultValueBin = nodeToString(expr);
+ }
+
+
/*
* now have TypeCreate do all the real work.
*/
@@ -606,10 +951,15 @@ DefineType(char *typeName, List *parameters)
receiveName, /* receive procedure */
sendName, /* send procedure */
elemName, /* element type name */
+ NULL, /* base type name (Non-zero for domains) */
defaultValue, /* default type value */
+ defaultValueBin, /* default type value (Binary form) */
byValue, /* passed by value */
alignment, /* required alignment */
- storage); /* TOAST strategy */
+ storage, /* TOAST strategy */
+ -1, /* typMod (Domains only) */
+ 0, /* Array Dimensions of typbasetype */
+ 'f'); /* Type NOT NULL */
/*
* When we create a base type (as opposed to a complex type) we need
@@ -632,10 +982,15 @@ DefineType(char *typeName, List *parameters)
"array_in", /* receive procedure */
"array_out", /* send procedure */
typeName, /* element type name */
+ NULL, /* base type name */
NULL, /* never a default type value */
+ NULL, /* binary default isn't sent either */
false, /* never passed by value */
alignment, /* see above */
- 'x'); /* ARRAY is always toastable */
+ 'x', /* ARRAY is always toastable */
+ -1, /* typMod (Domains only) */
+ 0, /* Array dimensions of typbasetype */
+ 'f'); /* Type NOT NULL */
pfree(shadow_type);
}
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index a0456adeb9..69e6e1b900 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* remove.c
- * POSTGRES remove (function | type | operator ) utilty code.
+ * POSTGRES remove (domain | function | type | operator ) utilty code.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.66 2002/03/06 06:09:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.67 2002/03/06 20:34:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,6 +22,7 @@
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
+#include "parser/parse.h"
#include "parser/parse_agg.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
@@ -276,6 +277,60 @@ RemoveType(char *typeName) /* type name to be removed */
}
/*
+ * RemoveDomain
+ * Removes the domain 'typeName' and all attributes and relations that
+ * use it.
+ */
+void
+RemoveDomain(char *domainName, int behavior) /* domain name to be removed */
+{
+ Relation relation;
+ HeapTuple tup;
+ TupleDesc description;
+ char typtype;
+ bool isnull;
+
+
+ /* Domains are stored as types. Check for permissions on the type */
+ if (!pg_ownercheck(GetUserId(), domainName, TYPENAME))
+ elog(ERROR, "RemoveDomain: type '%s': permission denied",
+ domainName);
+
+
+ relation = heap_openr(TypeRelationName, RowExclusiveLock);
+ description = RelationGetDescr(relation);
+
+ tup = SearchSysCache(TYPENAME,
+ PointerGetDatum(domainName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "RemoveType: type '%s' does not exist", domainName);
+
+
+ /* Check that this is actually a domain */
+ typtype = DatumGetChar(heap_getattr(tup, Anum_pg_type_typtype, description, &isnull));
+ Assert(!isnull);
+
+ if (typtype != 'd') {
+ elog(ERROR, "%s is not a domain", domainName);
+ }
+
+ /* CASCADE unsupported */
+ if (behavior == CASCADE) {
+ elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
+ }
+
+ /* Delete any comments associated with this type */
+ DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
+
+ simple_heap_delete(relation, &tup->t_self);
+
+ ReleaseSysCache(tup);
+
+ heap_close(relation, RowExclusiveLock);
+}
+
+/*
* RemoveFunction
* Deletes a function.
*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d3fe436ac7..07acc5dde6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.165 2002/03/01 22:45:11 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.166 2002/03/06 20:34:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2227,6 +2227,19 @@ _copyLoadStmt(LoadStmt *from)
return newnode;
}
+static CreateDomainStmt *
+_copyCreateDomainStmt(CreateDomainStmt *from)
+{
+ CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
+
+ if (from->domainname)
+ newnode->domainname = pstrdup(from->domainname);
+ if (from->typename)
+ newnode->typename = from->typename;
+
+ return newnode;
+}
+
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 661190dbaa..962471a5a9 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.113 2002/03/06 06:09:49 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.114 2002/03/06 20:34:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1096,6 +1096,17 @@ _equalLoadStmt(LoadStmt *a, LoadStmt *b)
}
static bool
+_equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
+{
+ if (!equalstr(a->domainname, b->domainname))
+ return false;
+ if (!equal(a->typename, b->typename))
+ return false;
+
+ return true;
+}
+
+static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
if (!equalstr(a->dbname, b->dbname))
@@ -2011,6 +2022,9 @@ equal(void *a, void *b)
case T_LoadStmt:
retval = _equalLoadStmt(a, b);
break;
+ case T_CreateDomainStmt:
+ retval = _equalCreateDomainStmt(a, b);
+ break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 4f637f48d1..d8b376ba8c 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -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.46 2001/11/05 17:46:26 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.47 2002/03/06 20:34:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -355,7 +355,6 @@ build_column_default(Relation rel, int attrno)
Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
Oid atttype = att_tup->atttypid;
int32 atttypmod = att_tup->atttypmod;
- bool hasdefault;
Datum typedefault;
int16 typlen;
bool typbyval;
@@ -392,7 +391,7 @@ build_column_default(Relation rel, int attrno)
if (type_id != atttype)
{
expr = CoerceTargetExpr(NULL, expr, type_id,
- atttype, atttypmod);
+ getBaseType(atttype), atttypmod);
/*
* This really shouldn't fail; should have checked the
@@ -430,41 +429,53 @@ build_column_default(Relation rel, int attrno)
* element type is, and the element type's default is irrelevant
* too.
*/
- hasdefault = false;
- typedefault = (Datum) 0;
typlen = sizeof(Oid);
typbyval = true;
+
+ expr = (Node *) makeConst(atttype,
+ typlen,
+ (Datum) 0,
+ true,
+ typbyval,
+ false, /* not a set */
+ false);
}
else
{
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(att_tup))
{
- hasdefault = false;
- typedefault = (Datum) 0;
+
+ expr = (Node *) makeConst(atttype,
+ typlen,
+ (Datum) 0,
+ true,
+ typbyval,
+ false, /* not a set */
+ false);
}
else
#endif /* _DROP_COLUMN_HACK__ */
- hasdefault = get_typdefault(atttype, &typedefault);
-
+ expr = get_typdefault(atttype, atttypmod);
+
+ if (expr == NULL) {
+ expr = (Node *) makeConst(atttype,
+ typlen,
+ (Datum) 0,
+ true,
+ typbyval,
+ false, /* not a set */
+ false);
+ }
get_typlenbyval(atttype, &typlen, &typbyval);
}
- expr = (Node *) makeConst(atttype,
- typlen,
- typedefault,
- !hasdefault,
- typbyval,
- false, /* not a set */
- false);
-
/*
* If the column is a fixed-length type, it may need a length coercion
- * as well as a type coercion. But NULLs don't need that.
+ * as well as a type coercion, as well as direction to the final type.
*/
- if (hasdefault)
- expr = coerce_type_typmod(NULL, expr,
- atttype, atttypmod);
+ expr = coerce_type_typmod(NULL, expr,
+ atttype, atttypmod);
return expr;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a8aba404e7..c1b4665091 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.285 2002/03/06 06:09:53 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.286 2002/03/06 20:34:49 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -135,7 +135,8 @@ static void doNegateFloat(Value *v);
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
- CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
+ CreateUserStmt, CreateDomainStmt, CreatedbStmt, CursorStmt,
+ DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
@@ -289,6 +290,8 @@ static void doNegateFloat(Value *v);
%type <list> constraints_set_namelist
%type <boolean> constraints_set_mode
+%type <boolean> opt_as
+
/*
* If you make any token changes, remember to:
* - use "yacc -d" and update parse.h
@@ -343,7 +346,7 @@ static void doNegateFloat(Value *v);
WITHOUT
/* Keywords (in SQL92 non-reserved words) */
-%token COMMITTED, SERIALIZABLE, TYPE_P
+%token COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P
/* Keywords for Postgres support (not in SQL92 reserved words)
*
@@ -446,6 +449,7 @@ stmt : AlterDatabaseSetStmt
| CopyStmt
| CreateStmt
| CreateAsStmt
+ | CreateDomainStmt
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
@@ -776,7 +780,10 @@ DropSchemaStmt: DROP SCHEMA UserId
n->dbname = $3;
$$ = (Node *)n;
}
+ ;
+
+
/*****************************************************************************
*
@@ -1461,7 +1468,10 @@ ColConstraintElem:
n->name = NULL;
if (exprIsNullConstant($2))
{
- /* DEFAULT NULL should be reported as empty expr */
+ /*
+ * DEFAULT NULL should be reported as empty expr
+ * Required for NOT NULL Domain overrides
+ */
n->raw_expr = NULL;
}
else
@@ -2043,7 +2053,16 @@ def_list: def_elem { $$ = makeList1($1); }
| def_list ',' def_elem { $$ = lappend($1, $3); }
;
-def_elem: ColLabel '=' def_arg
+def_elem: DEFAULT '=' b_expr
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "default";
+ if (exprIsNullConstant($3))
+ $$->arg = (Node *)NULL;
+ else
+ $$->arg = $3;
+ }
+ | ColLabel '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
@@ -2078,6 +2097,15 @@ DropStmt: DROP drop_type name_list
DropStmt *n = makeNode(DropStmt);
n->removeType = $2;
n->names = $3;
+ n->behavior = RESTRICT; /* Restricted by default */
+ $$ = (Node *)n;
+ }
+ | DROP DOMAIN_P name_list drop_behavior
+ {
+ DropStmt *n = makeNode(DropStmt);
+ n->removeType = DROP_DOMAIN_P;
+ n->names = $3;
+ n->behavior = $4;
$$ = (Node *)n;
}
;
@@ -2110,7 +2138,7 @@ TruncateStmt: TRUNCATE opt_table relation_name
* The COMMENT ON statement can take different forms based upon the type of
* the object associated with the comment. The form of the statement is:
*
- * COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
+ * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
* <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
* <funcname> (arg1, arg2, ...) | OPERATOR <op>
* (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
@@ -2196,6 +2224,7 @@ comment_type: DATABASE { $$ = DATABASE; }
| RULE { $$ = RULE; }
| SEQUENCE { $$ = SEQUENCE; }
| TABLE { $$ = TABLE; }
+ | DOMAIN_P { $$ = TYPE_P; }
| TYPE_P { $$ = TYPE_P; }
| VIEW { $$ = VIEW; }
;
@@ -3222,6 +3251,30 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
}
;
+/*****************************************************************************
+ *
+ * Manipulate a domain
+ *
+ *
+ *****************************************************************************/
+
+CreateDomainStmt: CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
+ {
+ CreateDomainStmt *n = makeNode(CreateDomainStmt);
+ n->domainname = $3;
+ n->typename = $5;
+ n->constraints = $6;
+
+ if ($7 != NULL)
+ elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
+ "implemented; clause ignored", $7);
+ $$ = (Node *)n;
+ }
+ ;
+
+opt_as: AS {$$ = TRUE; }
+ | /* EMPTY */ {$$ = FALSE; }
+ ;
/*****************************************************************************
*
@@ -5879,6 +5932,7 @@ unreserved_keyword:
| DEFERRED { $$ = "deferred"; }
| DELETE { $$ = "delete"; }
| DELIMITERS { $$ = "delimiters"; }
+ | DOMAIN_P { $$ = "domain"; }
| DOUBLE { $$ = "double"; }
| DROP { $$ = "drop"; }
| EACH { $$ = "each"; }
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index eaa0f7fa2b..02aff543d0 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.101 2002/03/05 05:33:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.102 2002/03/06 20:34:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -97,6 +97,7 @@ static ScanKeyword ScanKeywords[] = {
{"desc", DESC},
{"distinct", DISTINCT},
{"do", DO},
+ {"domain", DOMAIN_P},
{"double", DOUBLE},
{"drop", DROP},
{"each", EACH},
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index e81edb3efc..8586d5e5cc 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.64 2001/10/25 05:49:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.65 2002/03/06 20:34:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,6 +38,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
{
Node *result;
+
if (targetTypeId == inputTypeId ||
targetTypeId == InvalidOid ||
node == NULL)
@@ -605,3 +606,32 @@ PreferredType(CATEGORY category, Oid type)
}
return result;
} /* PreferredType() */
+
+
+/*
+ * If the targetTypeId is a domain, we really want to coerce
+ * the tuple to the domain type -- not the domain itself
+ */
+Oid
+getBaseType(Oid inType)
+{
+ HeapTuple tup;
+ Form_pg_type typTup;
+
+ tup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(inType),
+ 0, 0, 0);
+
+ typTup = ((Form_pg_type) GETSTRUCT(tup));
+
+ /*
+ * Assume that typbasetype exists and is a base type, where inType
+ * was a domain
+ */
+ if (typTup->typtype == 'd')
+ inType = typTup->typbasetype;
+
+ ReleaseSysCache(tup);
+
+ return inType;
+} \ No newline at end of file
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 339999c0c6..b095fa44b8 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.105 2001/11/12 20:05:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.106 2002/03/06 20:34:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1027,7 +1027,8 @@ parser_typecast_expression(ParseState *pstate,
if (inputType != targetType)
{
expr = CoerceTargetExpr(pstate, expr, inputType,
- targetType, typename->typmod);
+ getBaseType(targetType),
+ typename->typmod);
if (expr == NULL)
elog(ERROR, "Cannot cast type '%s' to '%s'",
format_type_be(inputType),
@@ -1039,7 +1040,7 @@ parser_typecast_expression(ParseState *pstate,
* as well as a type coercion.
*/
expr = coerce_type_typmod(pstate, expr,
- targetType, typename->typmod);
+ getBaseType(targetType), typename->typmod);
return expr;
}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 528b93012c..947bca0553 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.129 2002/03/05 05:33:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.130 2002/03/06 20:34:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -282,6 +282,11 @@ ProcessUtility(Node *parsetree,
/* RemoveType does its own permissions checks */
RemoveType(relname);
break;
+
+ case DROP_DOMAIN_P:
+ /* RemoveDomain does its own permissions checks */
+ RemoveDomain(relname, stmt->behavior);
+ break;
}
/*
@@ -743,6 +748,16 @@ ProcessUtility(Node *parsetree,
break;
/*
+ * ******************************** DOMAIN statements ****
+ *
+ */
+ case T_CreateDomainStmt:
+ set_ps_display(commandTag = "CREATE DOMAIN");
+
+ DefineDomain((CreateDomainStmt *) parsetree);
+ break;
+
+ /*
* ******************************** USER statements ****
*
*/
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index 960d0b2bcf..b825a5b14d 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.24 2002/03/02 21:39:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.25 2002/03/06 20:34:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -126,6 +126,7 @@ format_type_internal(Oid type_oid, int32 typemod,
bool is_array;
char *name;
char *buf;
+ char typtype;
if (type_oid == InvalidOid && allow_invalid)
return pstrdup("-");
@@ -144,6 +145,31 @@ format_type_internal(Oid type_oid, int32 typemod,
array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
+ typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype;
+
+ /*
+ * Domains look alot like arrays, so lets process them first, and return
+ * back to avoid the array and 'standard' formatting procedures that are
+ * use for base types.
+ */
+ if (typtype == 'd') {
+ name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
+
+ /*
+ * Double-quote the name if it's not a standard identifier.
+ * Note this is *necessary* for ruleutils.c's use.
+ */
+ if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
+ || isdigit((unsigned char) name[0]))
+ buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
+ else
+ buf = pstrdup(name);
+
+ ReleaseSysCache(tuple);
+
+ return buf;
+ }
+
if (array_base_type != InvalidOid && typlen < 0)
{
/* Switch our attention to the array element type */
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 706397d28c..3247c0aa8f 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -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.60 2002/03/01 04:09:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.61 2002/03/06 20:34:54 momjian Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@@ -23,6 +23,7 @@
#include "catalog/pg_shadow.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
+#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
@@ -822,16 +823,17 @@ get_typstorage(Oid typid)
* Returns FALSE if there is no default (effectively, default is NULL).
* The result points to palloc'd storage for pass-by-reference types.
*/
-bool
-get_typdefault(Oid typid, Datum *defaultValue)
+Node *
+get_typdefault(Oid typid, int32 atttypmod)
{
HeapTuple typeTuple;
Form_pg_type type;
- Oid typinput,
- typelem;
- Datum textDefaultVal;
+ Oid typinput;
+ Oid typbasetype;
+ char typtype;
+ Datum datum;
bool isNull;
- char *strDefaultVal;
+ Node *expr;
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
@@ -843,38 +845,41 @@ get_typdefault(Oid typid, Datum *defaultValue)
type = (Form_pg_type) GETSTRUCT(typeTuple);
typinput = type->typinput;
- typelem = type->typelem;
+ typbasetype = type->typbasetype;
+ typtype = type->typtype;
/*
- * typdefault is potentially null, so don't try to access it as a
+ * typdefaultbin is potentially null, so don't try to access it as a
* struct field. Must do it the hard way with SysCacheGetAttr.
*/
- textDefaultVal = SysCacheGetAttr(TYPEOID,
- typeTuple,
- Anum_pg_type_typdefault,
- &isNull);
+ datum = SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefaultbin,
+ &isNull);
+ ReleaseSysCache(typeTuple);
if (isNull)
- {
- ReleaseSysCache(typeTuple);
- *defaultValue = (Datum) 0;
- return false;
- }
+ return (Node *) NULL;
- /* Convert text datum to C string */
- strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
- textDefaultVal));
+ /* Convert Datum to a Node */
+ expr = stringToNode(DatumGetCString(
+ DirectFunctionCall1(textout, datum)));
- /* Convert C string to a value of the given type */
- *defaultValue = OidFunctionCall3(typinput,
- CStringGetDatum(strDefaultVal),
- ObjectIdGetDatum(typelem),
- Int32GetDatum(-1));
- pfree(strDefaultVal);
- ReleaseSysCache(typeTuple);
+ /*
+ * Ensure we goto the basetype before the domain type.
+ *
+ * Prevents scenarios like the below from failing:
+ * CREATE DOMAIN dom text DEFAULT random();
+ *
+ */
+ if (typbasetype != InvalidOid) {
+ expr = coerce_type(NULL, expr, typid,
+ typbasetype, atttypmod);
+ }
- return true;
+
+ return expr;
}
/*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 233689c22d..9997b25db1 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.154 2002/03/06 06:10:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.155 2002/03/06 20:34:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -512,8 +512,12 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
(char *) attp,
ATTRIBUTE_TUPLE_SIZE);
- /* Update constraint/default info */
- if (attp->attnotnull)
+
+
+ /*
+ * Update constraint/default info
+ */
+ if (attp->attnotnull)
constr->has_not_null = true;
if (attp->atthasdef)