? GNUmakefile ? config.log ? config.status ? contrib/spi/.deps ? doc/src/sgml/ref/alter_domain.sgml ? src/Makefile.global ? src/backend/postgres ? src/backend/access/common/.deps ? src/backend/access/gist/.deps ? src/backend/access/hash/.deps ? src/backend/access/heap/.deps ? src/backend/access/index/.deps ? src/backend/access/nbtree/.deps ? src/backend/access/rtree/.deps ? src/backend/access/transam/.deps ? src/backend/bootstrap/.deps ? src/backend/catalog/.deps ? src/backend/catalog/postgres.bki ? src/backend/catalog/postgres.description ? src/backend/commands/.deps ? src/backend/executor/.deps ? src/backend/lib/.deps ? src/backend/libpq/.deps ? src/backend/main/.deps ? src/backend/nodes/.deps ? src/backend/optimizer/geqo/.deps ? src/backend/optimizer/path/.deps ? src/backend/optimizer/plan/.deps ? src/backend/optimizer/prep/.deps ? src/backend/optimizer/util/.deps ? src/backend/parser/.deps ? src/backend/port/.deps ? src/backend/postmaster/.deps ? src/backend/regex/.deps ? src/backend/rewrite/.deps ? src/backend/storage/buffer/.deps ? src/backend/storage/file/.deps ? src/backend/storage/freespace/.deps ? src/backend/storage/ipc/.deps ? src/backend/storage/large_object/.deps ? src/backend/storage/lmgr/.deps ? src/backend/storage/page/.deps ? src/backend/storage/smgr/.deps ? src/backend/tcop/.deps ? src/backend/tcop/.utility.c.swp ? src/backend/utils/.deps ? src/backend/utils/adt/.deps ? src/backend/utils/cache/.deps ? src/backend/utils/error/.deps ? src/backend/utils/fmgr/.deps ? src/backend/utils/hash/.deps ? src/backend/utils/init/.deps ? src/backend/utils/mb/.deps ? src/backend/utils/mb/conversion_procs/conversion_create.sql ? src/backend/utils/mb/conversion_procs/ascii_and_mic/.deps ? src/backend/utils/mb/conversion_procs/ascii_and_mic/libascii_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/cyrillic_and_mic/.deps ? src/backend/utils/mb/conversion_procs/cyrillic_and_mic/libcyrillic_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_cn_and_mic/.deps ? src/backend/utils/mb/conversion_procs/euc_cn_and_mic/libeuc_cn_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/.deps ? src/backend/utils/mb/conversion_procs/euc_jp_and_sjis/libeuc_jp_and_sjis.so.0 ? src/backend/utils/mb/conversion_procs/euc_kr_and_mic/.deps ? src/backend/utils/mb/conversion_procs/euc_kr_and_mic/libeuc_kr_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/euc_tw_and_big5/.deps ? src/backend/utils/mb/conversion_procs/euc_tw_and_big5/libeuc_tw_and_big5.so.0 ? src/backend/utils/mb/conversion_procs/latin2_and_win1250/.deps ? src/backend/utils/mb/conversion_procs/latin2_and_win1250/liblatin2_and_win1250.so.0 ? src/backend/utils/mb/conversion_procs/latin_and_mic/.deps ? src/backend/utils/mb/conversion_procs/latin_and_mic/liblatin_and_mic.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_ascii/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_ascii/libutf8_and_ascii.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_big5/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_big5/libutf8_and_big5.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_cyrillic/libutf8_and_cyrillic.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_cn/libutf8_and_euc_cn.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_jp/libutf8_and_euc_jp.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_kr/libutf8_and_euc_kr.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_euc_tw/libutf8_and_euc_tw.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gb18030/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_gb18030/libutf8_and_gb18030.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_gbk/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_gbk/libutf8_and_gbk.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859/libutf8_and_iso8859.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_iso8859_1/libutf8_and_iso8859_1.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_johab/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_johab/libutf8_and_johab.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_sjis/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_sjis/libutf8_and_sjis.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_tcvn/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_tcvn/libutf8_and_tcvn.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_uhc/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_uhc/libutf8_and_uhc.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1250/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win1250/libutf8_and_win1250.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win1256/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win1256/libutf8_and_win1256.so.0 ? src/backend/utils/mb/conversion_procs/utf8_and_win874/.deps ? src/backend/utils/mb/conversion_procs/utf8_and_win874/libutf8_and_win874.so.0 ? src/backend/utils/misc/.deps ? src/backend/utils/mmgr/.deps ? src/backend/utils/sort/.deps ? src/backend/utils/time/.deps ? src/bin/initdb/initdb ? src/bin/initlocation/initlocation ? src/bin/ipcclean/ipcclean ? src/bin/pg_config/pg_config ? src/bin/pg_controldata/.deps ? src/bin/pg_controldata/pg_controldata ? src/bin/pg_ctl/pg_ctl ? src/bin/pg_dump/.deps ? src/bin/pg_dump/pg_dump ? src/bin/pg_dump/pg_dumpall ? src/bin/pg_dump/pg_restore ? src/bin/pg_encoding/.deps ? src/bin/pg_encoding/pg_encoding ? src/bin/pg_id/.deps ? src/bin/pg_id/pg_id ? src/bin/pg_resetxlog/.deps ? src/bin/pg_resetxlog/pg_resetxlog ? src/bin/psql/.deps ? src/bin/psql/psql ? src/bin/scripts/createlang ? src/include/pg_config.h ? src/include/stamp-h ? src/include/commands/typecmds.h ? src/interfaces/ecpg/lib/.deps ? src/interfaces/ecpg/lib/libecpg.so.3 ? src/interfaces/ecpg/preproc/.deps ? src/interfaces/ecpg/preproc/ecpg ? src/interfaces/libpq/.deps ? src/interfaces/libpq/libpq.so.2 ? src/pl/plpgsql/src/.deps ? src/pl/plpgsql/src/libplpgsql.so.1 ? src/test/regress/.deps ? src/test/regress/log ? src/test/regress/pg_regress ? src/test/regress/results ? src/test/regress/tmp_check ? src/test/regress/expected/constraints.out ? src/test/regress/expected/copy.out ? src/test/regress/expected/create_function_1.out ? src/test/regress/expected/create_function_2.out ? src/test/regress/expected/misc.out ? src/test/regress/sql/constraints.sql ? src/test/regress/sql/copy.sql ? src/test/regress/sql/create_function_1.sql ? src/test/regress/sql/create_function_2.sql ? src/test/regress/sql/misc.sql Index: doc/src/sgml/reference.sgml =================================================================== RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/reference.sgml,v retrieving revision 1.38 diff -c -r1.38 reference.sgml *** doc/src/sgml/reference.sgml 2002/09/08 02:33:08 1.38 --- doc/src/sgml/reference.sgml 2002/11/28 16:12:05 *************** *** 47,52 **** --- 47,53 ---- &abort; &alterDatabase; + &alterDomain; &alterGroup; &alterTable; &alterTrigger; Index: doc/src/sgml/ref/allfiles.sgml =================================================================== RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/ref/allfiles.sgml,v retrieving revision 1.49 diff -c -r1.49 allfiles.sgml *** doc/src/sgml/ref/allfiles.sgml 2002/09/07 16:49:50 1.49 --- doc/src/sgml/ref/allfiles.sgml 2002/11/28 16:12:05 *************** *** 38,43 **** --- 38,44 ---- + Index: src/backend/catalog/dependency.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/catalog/dependency.c,v retrieving revision 1.12 diff -c -r1.12 dependency.c *** src/backend/catalog/dependency.c 2002/09/22 00:37:09 1.12 --- src/backend/catalog/dependency.c 2002/11/28 16:12:05 *************** *** 36,41 **** --- 36,42 ---- #include "commands/proclang.h" #include "commands/schemacmds.h" #include "commands/trigger.h" + #include "commands/typecmds.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "optimizer/clauses.h" Index: src/backend/catalog/pg_constraint.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/catalog/pg_constraint.c,v retrieving revision 1.8 diff -c -r1.8 pg_constraint.c *** src/backend/catalog/pg_constraint.c 2002/11/15 02:50:05 1.8 --- src/backend/catalog/pg_constraint.c 2002/11/28 16:12:05 *************** *** 199,204 **** --- 199,205 ---- domobject.classId = RelOid_pg_type; domobject.objectId = domainId; + domobject.objectSubId = 0; recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO); } *************** *** 496,510 **** HeapTuple typTup; ScanKeyData typKey[1]; SysScanDesc typScan; typRel = heap_openr(TypeRelationName, RowExclusiveLock); ! ScanKeyEntryInitialize(&typKey[0], 0x0, ! Anum_pg_constraint_contypid, F_OIDEQ, ObjectIdGetDatum(con->contypid)); typScan = systable_beginscan(typRel, TypeOidIndex, true, ! SnapshotNow, 1, typKey); typTup = systable_getnext(typScan); --- 497,512 ---- HeapTuple typTup; ScanKeyData typKey[1]; SysScanDesc typScan; + int nkeys = 0; typRel = heap_openr(TypeRelationName, RowExclusiveLock); ! ScanKeyEntryInitialize(&typKey[nkeys++], 0x0, ! ObjectIdAttributeNumber, F_OIDEQ, ObjectIdGetDatum(con->contypid)); typScan = systable_beginscan(typRel, TypeOidIndex, true, ! SnapshotNow, nkeys, typKey); typTup = systable_getnext(typScan); *************** *** 516,521 **** --- 518,528 ---- /* Keep lock on domain type until end of xact */ heap_close(typRel, NoLock); + } + else + { + elog(ERROR, "RemoveConstraintById: Constraint %u is not a known type", + conId); } /* Fry the constraint itself */ Index: src/backend/catalog/pg_type.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/catalog/pg_type.c,v retrieving revision 1.82 diff -c -r1.82 pg_type.c *** src/backend/catalog/pg_type.c 2002/09/04 20:31:14 1.82 --- src/backend/catalog/pg_type.c 2002/11/28 16:12:05 *************** *** 139,145 **** Oid elementType, Oid baseType, const char *defaultTypeValue, /* human readable rep */ ! const char *defaultTypeBin, /* cooked rep */ bool passedByValue, char alignment, char storage, --- 139,145 ---- Oid elementType, Oid baseType, const char *defaultTypeValue, /* human readable rep */ ! char *defaultTypeBin, /* cooked rep */ bool passedByValue, char alignment, char storage, *************** *** 291,377 **** */ if (!IsBootstrapProcessingMode()) { ! ObjectAddress myself, ! referenced; ! myself.classId = RelOid_pg_type; ! myself.objectId = typeObjectId; ! myself.objectSubId = 0; ! ! /* dependency on namespace */ ! /* skip for relation rowtype, since we have indirect dependency */ ! if (!OidIsValid(relationOid)) ! { ! referenced.classId = get_system_catalog_relid(NamespaceRelationName); ! referenced.objectId = typeNamespace; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! } ! ! /* Normal dependencies on the I/O functions */ ! referenced.classId = RelOid_pg_proc; ! referenced.objectId = inputProcedure; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! referenced.classId = RelOid_pg_proc; ! referenced.objectId = outputProcedure; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! /* ! * If the type is a rowtype for a relation, mark it as internally ! * dependent on the relation, *unless* it is a stand-alone ! * composite type relation. For the latter case, we have to ! * reverse the dependency. ! * ! * In the former case, this allows the type to be auto-dropped when ! * the relation is, and not otherwise. And in the latter, of ! * course we get the opposite effect. ! */ ! if (OidIsValid(relationOid)) ! { ! referenced.classId = RelOid_pg_class; ! referenced.objectId = relationOid; ! referenced.objectSubId = 0; ! ! if (relationKind != RELKIND_COMPOSITE_TYPE) ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); ! else ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); ! } ! /* ! * If the type is an array type, mark it auto-dependent on the ! * base type. (This is a compromise between the typical case ! * where the array type is automatically generated and the case ! * where it is manually created: we'd prefer INTERNAL for the ! * former case and NORMAL for the latter.) ! */ ! if (OidIsValid(elementType)) ! { ! referenced.classId = RelOid_pg_type; ! referenced.objectId = elementType; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); ! } ! ! /* Normal dependency from a domain to its base type. */ ! if (OidIsValid(baseType)) ! { ! referenced.classId = RelOid_pg_type; ! referenced.objectId = baseType; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! } } /* ! * finish up */ ! heap_close(pg_type_desc, RowExclusiveLock); ! return typeObjectId; } /* --- 291,415 ---- */ if (!IsBootstrapProcessingMode()) { ! GenerateTypeDependencies(typeNamespace, ! typeObjectId, ! relationOid, ! relationKind, ! inputProcedure, ! outputProcedure, ! elementType, ! baseType, ! defaultTypeBin, ! false); ! } ! /* ! * finish up ! */ ! heap_close(pg_type_desc, RowExclusiveLock); ! return typeObjectId; ! } ! ! void ! GenerateTypeDependencies(Oid typeNamespace, ! Oid typeObjectId, ! Oid relationOid, /* only for 'c'atalog typeType */ ! char relationKind, ! Oid inputProcedure, ! Oid outputProcedure, ! Oid elementType, ! Oid baseType, ! char *defaultTypeBin, /* cooked rep */ ! bool rebuild) ! { ! ObjectAddress myself, ! referenced; ! ! /* ! * If true, we need to remove all current dependencies that the type ! * holds, and rebuild them from scratch. This allows us to easily ! * implement alter type, and alter domain statements. ! */ ! if (rebuild) ! deleteDependencyRecordsFor(RelOid_pg_type, ! typeObjectId); ! ! myself.classId = RelOid_pg_type; ! myself.objectId = typeObjectId; ! myself.objectSubId = 0; ! ! /* dependency on namespace */ ! /* skip for relation rowtype, since we have indirect dependency */ ! if (!OidIsValid(relationOid)) ! { ! referenced.classId = get_system_catalog_relid(NamespaceRelationName); ! referenced.objectId = typeNamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } ! /* Normal dependencies on the I/O functions */ ! referenced.classId = RelOid_pg_proc; ! referenced.objectId = inputProcedure; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! ! referenced.classId = RelOid_pg_proc; ! referenced.objectId = outputProcedure; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! /* ! * If the type is a rowtype for a relation, mark it as internally ! * dependent on the relation, *unless* it is a stand-alone ! * composite type relation. For the latter case, we have to ! * reverse the dependency. ! * ! * In the former case, this allows the type to be auto-dropped when ! * the relation is, and not otherwise. And in the latter, of ! * course we get the opposite effect. ! */ ! if (OidIsValid(relationOid)) ! { ! referenced.classId = RelOid_pg_class; ! referenced.objectId = relationOid; ! referenced.objectSubId = 0; ! ! if (relationKind != RELKIND_COMPOSITE_TYPE) ! recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); ! else ! recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL); } /* ! * If the type is an array type, mark it auto-dependent on the ! * base type. (This is a compromise between the typical case ! * where the array type is automatically generated and the case ! * where it is manually created: we'd prefer INTERNAL for the ! * former case and NORMAL for the latter.) */ ! if (OidIsValid(elementType)) ! { ! referenced.classId = RelOid_pg_type; ! referenced.objectId = elementType; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); ! } ! /* Normal dependency from a domain to its base type. */ ! if (OidIsValid(baseType)) ! { ! referenced.classId = RelOid_pg_type; ! referenced.objectId = baseType; ! referenced.objectSubId = 0; ! recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); ! } ! ! /* Dependency on the default expression */ ! if (defaultTypeBin) ! recordDependencyOnExpr(&myself, stringToNode(defaultTypeBin), ! NIL, DEPENDENCY_NORMAL); } /* Index: src/backend/commands/cluster.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/cluster.c,v retrieving revision 1.97 diff -c -r1.97 cluster.c *** src/backend/commands/cluster.c 2002/11/23 18:26:45 1.97 --- src/backend/commands/cluster.c 2002/11/28 16:12:05 *************** *** 667,673 **** tableOid = RangeVarGetRelid(stmt->relation, false); if (!check_cluster_ownership(tableOid)) elog(ERROR, "CLUSTER: You do not own relation %s", ! stmt->relation->relname); tuple = SearchSysCache(RELOID, ObjectIdGetDatum(tableOid), --- 667,673 ---- tableOid = RangeVarGetRelid(stmt->relation, false); if (!check_cluster_ownership(tableOid)) elog(ERROR, "CLUSTER: You do not own relation %s", ! stmt->relation->relname); tuple = SearchSysCache(RELOID, ObjectIdGetDatum(tableOid), *************** *** 706,712 **** } if (indexOid == InvalidOid) elog(ERROR, "CLUSTER: No previously clustered index found on table %s", ! stmt->relation->relname); RelationClose(rel); ReleaseSysCache(ituple); ReleaseSysCache(idxtuple); --- 706,712 ---- } if (indexOid == InvalidOid) elog(ERROR, "CLUSTER: No previously clustered index found on table %s", ! stmt->relation->relname); RelationClose(rel); ReleaseSysCache(ituple); ReleaseSysCache(idxtuple); *************** *** 721,727 **** /* XXX Maybe the namespace should be reported as well */ if (!OidIsValid(indexOid)) elog(ERROR, "CLUSTER: cannot find index \"%s\" for table \"%s\"", ! stmt->indexname, stmt->relation->relname); rvtc.tableOid = tableOid; rvtc.indexOid = indexOid; rvtc.isPrevious = false; --- 721,727 ---- /* XXX Maybe the namespace should be reported as well */ if (!OidIsValid(indexOid)) elog(ERROR, "CLUSTER: cannot find index \"%s\" for table \"%s\"", ! stmt->indexname, stmt->relation->relname); rvtc.tableOid = tableOid; rvtc.indexOid = indexOid; rvtc.isPrevious = false; *************** *** 819,825 **** List *rvs = NIL; /* ! * Get all indexes that have indisclustered set. System * relations or nailed-in relations cannot ever have * indisclustered set, because CLUSTER will refuse to * set it when called with one of them as argument. --- 819,825 ---- List *rvs = NIL; /* ! * Get all indexes that have indisclustered set. System * relations or nailed-in relations cannot ever have * indisclustered set, because CLUSTER will refuse to * set it when called with one of them as argument. Index: src/backend/commands/typecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/typecmds.c,v retrieving revision 1.17 diff -c -r1.17 typecmds.c *** src/backend/commands/typecmds.c 2002/11/15 02:50:06 1.17 --- src/backend/commands/typecmds.c 2002/11/28 16:12:06 *************** *** 32,45 **** --- 32,49 ---- #include "postgres.h" #include "access/heapam.h" + #include "access/genam.h" #include "catalog/catname.h" #include "catalog/dependency.h" #include "catalog/heap.h" + #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_constraint.h" #include "catalog/pg_type.h" #include "commands/defrem.h" #include "commands/tablecmds.h" + #include "commands/typecmds.h" + #include "executor/executor.h" #include "miscadmin.h" #include "nodes/nodes.h" #include "optimizer/clauses.h" *************** *** 48,53 **** --- 52,58 ---- #include "parser/parse_coerce.h" #include "parser/parse_expr.h" #include "parser/parse_func.h" + #include "parser/parse_relation.h" #include "parser/parse_type.h" #include "utils/acl.h" #include "utils/builtins.h" *************** *** 55,62 **** #include "utils/lsyscache.h" #include "utils/syscache.h" - static Oid findTypeIOFunction(List *procname, Oid typeOid, bool isOutput); /* * DefineType --- 60,80 ---- #include "utils/lsyscache.h" #include "utils/syscache.h" static Oid findTypeIOFunction(List *procname, Oid typeOid, bool isOutput); + static List *get_rels_with_domain(Oid domainOid); + static void domainPermissionCheck(HeapTuple tup, TypeName *typename); + static void domainCheckForUnsupportedConstraints(Node *newConstraint); + static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, + Oid baseTypeOid, + int typMod, Constraint *constr, + int *counter, char *domainName); + + typedef struct + { + Oid relOid; + int natts; + int *atts; + } relToCheck; /* * DefineType *************** *** 501,512 **** Constraint *colDef; ParseState *pstate; ! /* Prior to processing, confirm that it is not a foreign key constraint */ ! if (nodeTag(newConstraint) == T_FkConstraint) ! elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported"); colDef = (Constraint *) newConstraint; - switch (colDef->contype) { /* --- 519,532 ---- Constraint *colDef; ParseState *pstate; ! /* ! * Check for constraint types which are not supported by ! * domains. Throws an error if it finds one. ! */ ! domainCheckForUnsupportedConstraints(newConstraint); + /* Assume its a CHECK, DEFAULT, NULL or NOT NULL constraint */ colDef = (Constraint *) newConstraint; switch (colDef->contype) { /* *************** *** 559,584 **** typNotNull = false; nullDefined = true; break; - - case CONSTR_UNIQUE: - elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported"); - break; - - case CONSTR_PRIMARY: - elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported"); - break; ! /* Check constraints are handled after domain creation */ case CONSTR_CHECK: 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; default: elog(ERROR, "DefineDomain: unrecognized constraint node type"); break; --- 579,596 ---- typNotNull = false; nullDefined = true; break; ! /* ! * Check constraints are handled after domain creation, as they require ! * the Oid of the domain ! */ case CONSTR_CHECK: break; + /* + * If we reach this, then domainCheckForUnsupportedConstraints() + * doesn't have a complete list of unsupported domain constraints + */ default: elog(ERROR, "DefineDomain: unrecognized constraint node type"); break; *************** *** 616,758 **** foreach(listptr, schema) { Constraint *constr = lfirst(listptr); - ParseState *pstate; switch (constr->contype) { case CONSTR_CHECK: { ! Node *expr; ! char *ccsrc; ! char *ccbin; ! ConstraintTestValue *domVal; ! ! /* ! * Assign or validate constraint name ! */ ! if (constr->name) ! { ! if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN, ! domainoid, ! domainNamespace, ! constr->name)) ! elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"", ! constr->name, ! domainName); ! } ! else ! constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN, ! domainoid, ! domainNamespace, ! &counter); ! ! /* ! * Convert the A_EXPR in raw_expr into an ! * EXPR ! */ ! pstate = make_parsestate(NULL); ! ! /* ! * We want to have the domain VALUE node type filled in so ! * that proper casting can occur. ! */ ! domVal = makeNode(ConstraintTestValue); ! domVal->typeId = basetypeoid; ! domVal->typeMod = stmt->typename->typmod; ! ! expr = transformExpr(pstate, constr->raw_expr, domVal); ! ! /* ! * Domains don't allow var clauses ! */ ! if (contain_var_clause(expr)) ! elog(ERROR, "cannot use column references in domain CHECK clause"); ! ! /* ! * Make sure it yields a boolean result. ! */ ! expr = coerce_to_boolean(expr, "CHECK"); ! ! /* ! * Make sure no outside relations are ! * referred to. ! */ ! if (length(pstate->p_rtable) != 0) ! elog(ERROR, "Relations cannot be referenced in domain CHECK constraint"); ! ! /* ! * No subplans or aggregates, either... ! */ ! if (contain_subplans(expr)) ! elog(ERROR, "cannot use subselect in CHECK constraint expression"); ! if (contain_agg_clause(expr)) ! elog(ERROR, "cannot use aggregate function in CHECK constraint expression"); ! ! /* ! * Might as well try to reduce any constant expressions. ! */ ! expr = eval_const_expressions(expr); ! ! /* ! * Must fix opids in operator clauses. ! */ ! fix_opids(expr); ! ! ccbin = nodeToString(expr); ! ! /* ! * Deparse it. Since VARNOs aren't allowed in domain ! * constraints, relation context isn't required as anything ! * other than a shell. ! */ ! ccsrc = deparse_expression(expr, ! deparse_context_for(domainName, ! InvalidOid), ! false, false); ! ! /* Write the constraint */ ! CreateConstraintEntry(constr->name, /* Constraint Name */ ! domainNamespace, /* namespace */ ! CONSTRAINT_CHECK, /* Constraint Type */ ! false, /* Is Deferrable */ ! false, /* Is Deferred */ ! InvalidOid, /* not a relation constraint */ ! NULL, ! 0, ! domainoid, /* domain constraint */ ! InvalidOid, /* Foreign key fields */ ! NULL, ! 0, ! ' ', ! ' ', ! ' ', ! InvalidOid, ! expr, /* Tree form check constraint */ ! ccbin, /* Binary form check constraint */ ! ccsrc); /* Source form check constraint */ } break; default: break; } } /* - * Add any dependencies needed for the default expression. - */ - if (defaultExpr) - { - ObjectAddress domobject; - - domobject.classId = RelOid_pg_type; - domobject.objectId = domainoid; - domobject.objectSubId = 0; - - recordDependencyOnExpr(&domobject, defaultExpr, NIL, - DEPENDENCY_NORMAL); - } - - /* * Now we can clean up. */ ReleaseSysCache(typeTup); --- 628,654 ---- foreach(listptr, schema) { Constraint *constr = lfirst(listptr); switch (constr->contype) { case CONSTR_CHECK: { ! char *junk; ! ! /* Returns the cooked constraint which is not needed during creation */ ! junk = domainAddConstraint(domainoid, domainNamespace, ! basetypeoid, stmt->typename->typmod, ! constr, &counter, domainName); } break; + + /* Errors for other constraints are taken care of prior to domain creation */ default: break; } } /* * Now we can clean up. */ ReleaseSysCache(typeTup); *************** *** 931,937 **** if (OidIsValid(procOid)) { /* Found, but must complain and fix the pg_proc entry */ ! elog(NOTICE, "TypeCreate: changing argument type of function %s from OPAQUE to CSTRING", NameListToString(procname)); SetFunctionArgType(procOid, 0, CSTRINGOID); /* --- 827,834 ---- if (OidIsValid(procOid)) { /* Found, but must complain and fix the pg_proc entry */ ! elog(NOTICE, "TypeCreate: changing argument type of function %s " ! "from OPAQUE to CSTRING", NameListToString(procname)); SetFunctionArgType(procOid, 0, CSTRINGOID); /* *************** *** 991,994 **** --- 888,1666 ---- * finally create the relation... */ return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE); + } + + /* + * AlterDomainDefault + * + * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements. + */ + void + AlterDomainDefault(List *names, Node *defaultRaw) + { + TypeName *typename; + Oid domainoid; + HeapTuple tup; + ParseState *pstate; + Relation rel; + char *defaultValue; + Node *defaultExpr = NULL; /* NULL if no default specified */ + Datum new_record[Natts_pg_type]; + char new_record_nulls[Natts_pg_type]; + char new_record_repl[Natts_pg_type]; + HeapTuple newtuple; + Form_pg_type typTup; + + /* Make a TypeName so we can use standard type lookup machinery */ + typename = makeNode(TypeName); + typename->names = names; + typename->typmod = -1; + typename->arrayBounds = NIL; + + /* Lock the domain in the type table */ + rel = heap_openr(TypeRelationName, RowExclusiveLock); + + /* Use LookupTypeName here so that shell types can be removed. */ + domainoid = LookupTypeName(typename); + if (!OidIsValid(domainoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(typename)); + + tup = SearchSysCacheCopy(TYPEOID, + ObjectIdGetDatum(domainoid), + 0, 0, 0); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "AlterDomain: type \"%s\" does not exist", + TypeNameToString(typename)); + + /* Doesn't return if user isn't allowed to alter the domain */ + domainPermissionCheck(tup, typename); + + /* Setup new tuple */ + MemSet(new_record, (Datum) 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); + + /* Useful later */ + typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Store the new default, if null then skip this step */ + if (defaultRaw) + { + /* Create a dummy ParseState for transformExpr */ + pstate = make_parsestate(NULL); + /* + * Cook the colDef->raw_expr into an expression. Note: + * Name is strictly for error message + */ + defaultExpr = cookDefault(pstate, defaultRaw, + typTup->typbasetype, + typTup->typtypmod, + NameStr(typTup->typname)); + + /* + * Expression must be stored as a nodeToString result, but + * we also require a valid textual representation (mainly + * to make life easier for pg_dump). + */ + defaultValue = deparse_expression(defaultExpr, + deparse_context_for(NameStr(typTup->typname), + InvalidOid), + false, false); + /* + * Form an updated tuple with the new default and write it back. + */ + new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin, + CStringGetDatum( + nodeToString(defaultExpr))); + + new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r'; + new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin, + CStringGetDatum(defaultValue)); + new_record_repl[Anum_pg_type_typdefault - 1] = 'r'; + } + else /* Default is NULL, drop it */ + { + new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n'; + new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r'; + new_record_nulls[Anum_pg_type_typdefault - 1] = 'n'; + new_record_repl[Anum_pg_type_typdefault - 1] = 'r'; + } + + newtuple = heap_modifytuple(tup, rel, + new_record, new_record_nulls, new_record_repl); + + simple_heap_update(rel, &tup->t_self, newtuple); + + CatalogUpdateIndexes(rel, newtuple); + + /* Rebuild dependencies */ + GenerateTypeDependencies(typTup->typnamespace, + domainoid, + typTup->typrelid, + InvalidOid, + typTup->typinput, + typTup->typoutput, + typTup->typelem, + typTup->typbasetype, + nodeToString(defaultExpr), + true); /* Rebuild is true */ + + /* Clean up */ + heap_close(rel, NoLock); + heap_freetuple(newtuple); + }; + + /* + * AlterDomainNotNull + * + * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements. + */ + void + AlterDomainNotNull(List *names, bool notNull) + { + TypeName *typename; + Oid domainoid; + HeapTuple tup; + Relation rel; + Datum new_record[Natts_pg_type]; + char new_record_nulls[Natts_pg_type]; + char new_record_repl[Natts_pg_type]; + HeapTuple newtuple; + Form_pg_type typTup; + + /* Make a TypeName so we can use standard type lookup machinery */ + typename = makeNode(TypeName); + typename->names = names; + typename->typmod = -1; + typename->arrayBounds = NIL; + + /* Lock the type table */ + rel = heap_openr(TypeRelationName, RowExclusiveLock); + + /* Use LookupTypeName here so that shell types can be removed. */ + domainoid = LookupTypeName(typename); + if (!OidIsValid(domainoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(typename)); + + tup = SearchSysCacheCopy(TYPEOID, + ObjectIdGetDatum(domainoid), + 0, 0, 0); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "AlterDomain: type \"%s\" does not exist", + TypeNameToString(typename)); + + /* Doesn't return if user isn't allowed to alter the domain */ + domainPermissionCheck(tup, typename); + + typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Is the domain already set to the destination constraint? */ + if (typTup->typnotnull == notNull) + elog(ERROR, "AlterDomain: %s is already set to %s", + TypeNameToString(typename), + notNull ? "NOT NULL" : "NULL"); + + /* Adding a NOT NULL constraint requires checking current domains */ + if (notNull) + { + List *rels; + List *rt; + + /* Fetch relation list with attributes based on this domain */ + rels = get_rels_with_domain(domainoid); + + foreach (rt, rels) + { + Relation typrel; + HeapTuple tuple; + HeapScanDesc scan; + TupleDesc tupdesc; + relToCheck *rtc = (relToCheck *) lfirst(rt); + + /* Lock relation */ + typrel = heap_open(rtc->relOid, ExclusiveLock); + + tupdesc = RelationGetDescr(typrel); + + /* Fetch tuples sequentially */ + scan = heap_beginscan(typrel, SnapshotNow, 0, NULL); + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + int i; + + /* Test attributes */ + for (i = 0; i < rtc->natts; i++) + { + Datum d; + bool isNull; + + d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull); + + if (isNull) + elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" " + "contains NULL values", + RelationGetRelationName(typrel), + NameStr(*attnumAttName(typrel, rtc->atts[i]))); + } + } + + heap_endscan(scan); + + /* Release lock */ + heap_close(typrel, NoLock); + } + } + + + /* Setup new tuple */ + MemSet(new_record, (Datum) 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); + + new_record[Anum_pg_type_typnotnull - 1] = BoolGetDatum(notNull); + new_record_repl[Anum_pg_type_typnotnull - 1] = 'r'; + + /* Build the new tuple */ + newtuple = heap_modifytuple(tup, rel, + new_record, new_record_nulls, new_record_repl); + + simple_heap_update(rel, &tup->t_self, newtuple); + + CatalogUpdateIndexes(rel, newtuple); + + /* Clean up */ + heap_close(rel, NoLock); + heap_freetuple(newtuple); + } + + /* + * AlterDomainDropConstraint + * + * Implements the ALTER DOMAIN DROP CONSTRAINT statement + */ + void + AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior) + { + TypeName *typename; + Oid domainoid; + HeapTuple tup; + Relation rel; + Form_pg_type typTup; + Relation conrel; + SysScanDesc conscan; + ScanKeyData key[1]; + HeapTuple contup; + + /* Make a TypeName so we can use standard type lookup machinery */ + typename = makeNode(TypeName); + typename->names = names; + typename->typmod = -1; + typename->arrayBounds = NIL; + + /* Lock the type table */ + rel = heap_openr(TypeRelationName, RowExclusiveLock); + + /* Use LookupTypeName here so that shell types can be removed. */ + domainoid = LookupTypeName(typename); + if (!OidIsValid(domainoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(typename)); + + tup = SearchSysCacheCopy(TYPEOID, + ObjectIdGetDatum(domainoid), + 0, 0, 0); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "AlterDomain: type \"%s\" does not exist", + TypeNameToString(typename)); + + /* Doesn't return if user isn't allowed to alter the domain */ + domainPermissionCheck(tup, typename); + + /* Grab an appropriate lock on the pg_constraint relation */ + conrel = heap_openr(ConstraintRelationName, RowExclusiveLock); + + /* Use the index to scan only constraints of the target relation */ + ScanKeyEntryInitialize(&key[0], 0x0, + Anum_pg_constraint_contypid, F_OIDEQ, + ObjectIdGetDatum(HeapTupleGetOid(tup))); + + conscan = systable_beginscan(conrel, ConstraintTypidIndex, true, + SnapshotNow, 1, key); + + typTup = (Form_pg_type) GETSTRUCT(tup); + + /* + * Scan over the result set, removing any matching entries. + */ + while ((contup = systable_getnext(conscan)) != NULL) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup); + + if (strcmp(NameStr(con->conname), constrName) == 0) + { + ObjectAddress conobj; + + conobj.classId = RelationGetRelid(conrel); + conobj.objectId = HeapTupleGetOid(contup); + conobj.objectSubId = 0; + + performDeletion(&conobj, behavior); + } + } + /* Clean up after the scan */ + systable_endscan(conscan); + heap_close(conrel, RowExclusiveLock); + + heap_close(rel, NoLock); + }; + + /* + * AlterDomainAddConstraint + * + * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement. + */ + void + AlterDomainAddConstraint(List *names, Node *newConstraint) + { + TypeName *typename; + Oid domainoid; + HeapTuple tup; + Relation rel; + List *rels; + List *rt; + Form_pg_type typTup; + char *ccbin; + Node *expr; + int counter = 0; + Constraint *constr; + + /* Make a TypeName so we can use standard type lookup machinery */ + typename = makeNode(TypeName); + typename->names = names; + typename->typmod = -1; + typename->arrayBounds = NIL; + + /* Lock the type table */ + rel = heap_openr(TypeRelationName, RowExclusiveLock); + + /* Use LookupTypeName here so that shell types can be removed. */ + domainoid = LookupTypeName(typename); + if (!OidIsValid(domainoid)) + elog(ERROR, "Type \"%s\" does not exist", + TypeNameToString(typename)); + + tup = SearchSysCacheCopy(TYPEOID, + ObjectIdGetDatum(domainoid), + 0, 0, 0); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "AlterDomain: type \"%s\" does not exist", + TypeNameToString(typename)); + + + /* Doesn't return if user isn't allowed to alter the domain */ + domainPermissionCheck(tup, typename); + + typTup = (Form_pg_type) GETSTRUCT(tup); + + + /* + * Check for constraint types which are not supported by + * domains. Throws an error if it finds one. + */ + domainCheckForUnsupportedConstraints(newConstraint); + + /* Assume its a CHECK, DEFAULT, NULL or NOT NULL constraint */ + constr = (Constraint *) newConstraint; + switch (constr->contype) + { + case CONSTR_DEFAULT: + elog(ERROR, "Use ALTER DOMAIN .. SET DEFAULT instead"); + break; + + case CONSTR_NOTNULL: + case CONSTR_NULL: + elog(ERROR, "Use ALTER DOMAIN .. [ SET | DROP ] NOT NULL instead"); + break; + + /* + * Check constraints are handled after domain creation, as they require + * the Oid of the domain + */ + case CONSTR_CHECK: + { + /* Returns the cooked constraint which is not needed during creation */ + ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace, + typTup->typbasetype, typTup->typtypmod, + constr, &counter, NameStr(typTup->typname)); + } + break; + + /* + * If we reach this, then domainCheckForUnsupportedConstraints() + * doesn't have a complete list of unsupported domain constraints + */ + default: + elog(ERROR, "DefineDomain: unrecognized constraint node type"); + break; + } + + /* + * Since all other constraint types throw errors, this must be + * a check constraint, and ccbin must be set. + * + * Test all values stored in the attributes based on the domain + * the constraint is being added to. + */ + expr = stringToNode(ccbin); + rels = get_rels_with_domain(domainoid); + foreach (rt, rels) + { + Relation typrel; + HeapTuple tuple; + HeapScanDesc scan; + TupleDesc tupdesc; + ExprContext *econtext; + TupleTableSlot *slot; + relToCheck *rtc = (relToCheck *) lfirst(rt); + + /* Lock relation */ + typrel = heap_open(rtc->relOid, ExclusiveLock); + + /* Test attributes */ + tupdesc = RelationGetDescr(typrel); + + /* Make tuple slot to hold tuples */ + slot = MakeTupleTableSlot(); + ExecSetSlotDescriptor(slot, RelationGetDescr(typrel), false); + + /* Make an expression context for ExecQual */ + econtext = MakeExprContext(slot, CurrentMemoryContext); + + /* Scan through table */ + scan = heap_beginscan(typrel, SnapshotNow, 0, NULL); + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + int i; + + ExecStoreTuple(tuple, slot, InvalidBuffer, false); + + /* Loop through each attribute of the tuple with a domain */ + for (i = 0; i < rtc->natts; i++) + { + Datum d; + bool isNull; + Datum conResult; + ExprDoneCond isDone; + + d = heap_getattr(tuple, rtc->atts[i], tupdesc, &isNull); + + if (isNull) + elog(ERROR, "ALTER DOMAIN: Relation \"%s\" Attribute \"%s\" " + "contains NULL values", + RelationGetRelationName(typrel), + NameStr(*attnumAttName(typrel, rtc->atts[i]))); + + econtext->domainValue_datum = d; + econtext->domainValue_isNull = isNull; + + conResult = ExecEvalExpr(expr, econtext, &isNull, &isDone); + + if (!DatumGetBool(conResult)) + elog(ERROR, "AlterDomainAddConstraint: Domain %s constraint %s failed", + NameStr(typTup->typname), constr->name); + } + + ResetExprContext(econtext); + } + + heap_endscan(scan); + + FreeExprContext(econtext); + pfree(slot); + + /* Hold type lock */ + heap_close(typrel, NoLock); + } + + /* Clean up */ + heap_close(rel, NoLock); + } + + /* + * get_rels_with_domain + * + * Fetch all relations / attributes which are using the domain + * while maintaining a RowExclusiveLock on the pg_attribute + * entries. + * + * Generally used for retrieving a list of tests when adding + * new constraints to a domain. + */ + List * + get_rels_with_domain(Oid domainOid) + { + Relation classRel; + HeapTuple classTup; + Relation attRel; + HeapScanDesc classScan; + List *rels = NIL; + + /* + * We need to lock the domain rows for the length of the transaction, + * but once all of the tables and the appropriate attributes are + * found we can relese the relation lock. + */ + classRel = relation_openr(RelationRelationName, ExclusiveLock); + attRel = relation_openr(AttributeRelationName, RowExclusiveLock); + + classScan = heap_beginscan(classRel, SnapshotNow, 0, NULL); + + /* Scan through pg_class for tables */ + while ((classTup = heap_getnext(classScan, ForwardScanDirection)) != NULL) + { + bool addToList = true; + int nkeys = 0; + HeapTuple attTup; + HeapScanDesc attScan; + ScanKeyData attKey[2]; + Form_pg_class pg_class; + + /* Get our pg_class struct */ + pg_class = (Form_pg_class) GETSTRUCT(classTup); + + /* Fetch attributes from pg_attribute for the relation of the type domainOid */ + ScanKeyEntryInitialize(&attKey[nkeys++], 0, Anum_pg_attribute_attrelid, + F_OIDEQ, ObjectIdGetDatum(HeapTupleGetOid(classTup))); + + ScanKeyEntryInitialize(&attKey[nkeys++], 0, Anum_pg_attribute_atttypid, + F_OIDEQ, ObjectIdGetDatum(domainOid)); + + /* Setup to scan pg_attribute */ + attScan = heap_beginscan(attRel, SnapshotNow, nkeys, attKey); + + /* Scan through pg_attribute for attributes based on the domain */ + while ((attTup = heap_getnext(attScan, ForwardScanDirection)) != NULL) + { + relToCheck *rtc; + + /* Make the list entries for the relation */ + if (addToList) + { + addToList = false; + + rtc = (relToCheck *)palloc(sizeof(relToCheck)); + rtc->atts = (int *)palloc(sizeof(int) * pg_class->relnatts); + rtc->relOid = HeapTupleGetOid(classTup); + rtc->natts = 0; + rels = lcons((void *)rtc, rels); + } + + /* Now add the attribute */ + rtc->atts[rtc->natts++] = ((Form_pg_attribute) GETSTRUCT(attTup))->attnum; + } + + heap_endscan(attScan); + } + + heap_endscan(classScan); + + /* Release pg_class, hold pg_attribute for further processing */ + relation_close(classRel, ExclusiveLock); + relation_close(attRel, NoLock); + + return rels; + } + + /* + * domainPermissionCheck + * + * Throw an error if the current user doesn't have permission to modify + * the domain in an ALTER DOMAIN statement, or if the type isn't actually + * a domain. + */ + void + domainPermissionCheck(HeapTuple tup, TypeName *typename) + { + Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Permission check: must own type or its namespace */ + if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()) && + !pg_namespace_ownercheck(typTup->typnamespace, + GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, TypeNameToString(typename)); + + /* Check that this is actually a domain */ + if (typTup->typtype != 'd') + elog(ERROR, "%s is not a domain", + TypeNameToString(typename)); + } + + + /* + * + */ + char * + domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, + int typMod, Constraint *constr, int *counter, char *domainName) + { + Node *expr; + char *ccsrc; + char *ccbin; + ParseState *pstate; + ConstraintTestValue *domVal; + + /* + * Assign or validate constraint name + */ + if (constr->name) + { + if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN, + domainOid, + domainNamespace, + constr->name)) + elog(ERROR, "constraint \"%s\" already exists for domain \"%s\"", + constr->name, + domainName); + } + else + constr->name = GenerateConstraintName(CONSTRAINT_DOMAIN, + domainOid, + domainNamespace, + counter); + + /* + * Convert the A_EXPR in raw_expr into an + * EXPR + */ + pstate = make_parsestate(NULL); + + /* + * We want to have the domain VALUE node type filled in so + * that proper casting can occur. + */ + domVal = makeNode(ConstraintTestValue); + domVal->typeId = baseTypeOid; + domVal->typeMod = typMod; + + expr = transformExpr(pstate, constr->raw_expr, domVal); + + /* + * Domains don't allow var clauses + */ + if (contain_var_clause(expr)) + elog(ERROR, "cannot use column references in domain CHECK clause"); + + /* + * Make sure it yields a boolean result. + */ + expr = coerce_to_boolean(expr, "CHECK"); + + /* + * Make sure no outside relations are + * referred to. + */ + if (length(pstate->p_rtable) != 0) + elog(ERROR, "Relations cannot be referenced in domain CHECK constraint"); + + /* + * No subplans or aggregates, either... + */ + if (contain_subplans(expr)) + elog(ERROR, "cannot use subselect in CHECK constraint expression"); + if (contain_agg_clause(expr)) + elog(ERROR, "cannot use aggregate function in CHECK constraint expression"); + + /* + * Might as well try to reduce any constant expressions. + */ + expr = eval_const_expressions(expr); + + /* + * Must fix opids in operator clauses. + */ + fix_opids(expr); + + ccbin = nodeToString(expr); + + /* + * Deparse it. Since VARNOs aren't allowed in domain + * constraints, relation context isn't required as anything + * other than a shell. + */ + ccsrc = deparse_expression(expr, + deparse_context_for(domainName, + InvalidOid), + false, false); + + /* Write the constraint */ + CreateConstraintEntry(constr->name, /* Constraint Name */ + domainNamespace, /* namespace */ + CONSTRAINT_CHECK, /* Constraint Type */ + false, /* Is Deferrable */ + false, /* Is Deferred */ + InvalidOid, /* not a relation constraint */ + NULL, + 0, + domainOid, /* domain constraint */ + InvalidOid, /* Foreign key fields */ + NULL, + 0, + ' ', + ' ', + ' ', + InvalidOid, + expr, /* Tree form check constraint */ + ccbin, /* Binary form check constraint */ + ccsrc); /* Source form check constraint */ + + /* + * Return the constraint so the calling routine can perform any additional + * required tests. + */ + return ccbin; + } + + /* + * domainCheckForUnsupportedConstraints + * + * Throws an error on constraints that are unsupported by the + * domains. + */ + void + domainCheckForUnsupportedConstraints(Node *newConstraint) + { + Constraint *colDef; + + if (nodeTag(newConstraint) == T_FkConstraint) + elog(ERROR, "CREATE DOMAIN / FOREIGN KEY constraints not supported"); + + colDef = (Constraint *) newConstraint; + + switch (colDef->contype) + { + case CONSTR_UNIQUE: + elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported"); + break; + + case CONSTR_PRIMARY: + elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes 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; + + default: + break; + } } Index: src/backend/executor/execQual.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/execQual.c,v retrieving revision 1.110 diff -c -r1.110 execQual.c *** src/backend/executor/execQual.c 2002/11/25 21:29:35 1.110 --- src/backend/executor/execQual.c 2002/11/28 16:12:06 *************** *** 1570,1577 **** conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone); if (!DatumGetBool(conResult)) ! elog(ERROR, "Domain %s constraint %s failed", ! constraint->name, constraint->domname); } break; default: --- 1570,1577 ---- conResult = ExecEvalExpr(constraint->check_expr, econtext, isNull, isDone); if (!DatumGetBool(conResult)) ! elog(ERROR, "ExecEvalConstraintTest: Domain %s constraint %s failed", ! constraint->domname, constraint->name); } break; default: Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/copyfuncs.c,v retrieving revision 1.223 diff -c -r1.223 copyfuncs.c *** src/backend/nodes/copyfuncs.c 2002/11/25 21:29:36 1.223 --- src/backend/nodes/copyfuncs.c 2002/11/28 16:12:06 *************** *** 1815,1820 **** --- 1815,1834 ---- return newnode; } + static AlterDomainStmt * + _copyAlterDomainStmt(AlterDomainStmt *from) + { + AlterDomainStmt *newnode = makeNode(AlterDomainStmt); + + COPY_SCALAR_FIELD(subtype); + COPY_NODE_FIELD(typename); + COPY_STRING_FIELD(name); + COPY_NODE_FIELD(def); + COPY_SCALAR_FIELD(behavior); + + return newnode; + } + static GrantStmt * _copyGrantStmt(GrantStmt *from) { *************** *** 2832,2837 **** --- 2846,2854 ---- break; case T_AlterTableStmt: retval = _copyAlterTableStmt(from); + break; + case T_AlterDomainStmt: + retval = _copyAlterDomainStmt(from); break; case T_GrantStmt: retval = _copyGrantStmt(from); Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/nodes/equalfuncs.c,v retrieving revision 1.169 diff -c -r1.169 equalfuncs.c *** src/backend/nodes/equalfuncs.c 2002/11/25 21:29:36 1.169 --- src/backend/nodes/equalfuncs.c 2002/11/28 16:12:06 *************** *** 667,672 **** --- 667,684 ---- } static bool + _equalAlterDomainStmt(AlterDomainStmt *a, AlterDomainStmt *b) + { + COMPARE_SCALAR_FIELD(subtype); + COMPARE_NODE_FIELD(typename); + COMPARE_STRING_FIELD(name); + COMPARE_NODE_FIELD(def); + COMPARE_SCALAR_FIELD(behavior); + + return true; + } + + static bool _equalGrantStmt(GrantStmt *a, GrantStmt *b) { COMPARE_SCALAR_FIELD(is_grant); *************** *** 1794,1799 **** --- 1806,1814 ---- break; case T_AlterTableStmt: retval = _equalAlterTableStmt(a, b); + break; + case T_AlterDomainStmt: + retval = _equalAlterDomainStmt(a, b); break; case T_GrantStmt: retval = _equalGrantStmt(a, b); Index: src/backend/parser/gram.y =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.383 diff -c -r2.383 gram.y *** src/backend/parser/gram.y 2002/11/25 21:29:40 2.383 --- src/backend/parser/gram.y 2002/11/28 16:12:06 *************** *** 128,134 **** } %type stmt schema_stmt ! AlterDatabaseSetStmt AlterGroupStmt AlterTableStmt AlterUserStmt AlterUserSetStmt AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt --- 128,134 ---- } %type stmt schema_stmt ! AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt AlterTableStmt AlterUserStmt AlterUserSetStmt AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt *************** *** 479,484 **** --- 479,485 ---- stmt : AlterDatabaseSetStmt + | AlterDomainStmt | AlterGroupStmt | AlterTableStmt | AlterUserStmt *************** *** 3728,3733 **** --- 3729,3781 ---- $$ = (Node *)n; } ; + + AlterDomainStmt: + /* ALTER DOMAIN {SET DEFAULT |DROP DEFAULT} */ + ALTER DOMAIN_P any_name alter_column_default + { + AlterDomainStmt *n = makeNode(AlterDomainStmt); + n->subtype = 'T'; + n->typename = $3; + n->def = $4; + $$ = (Node *)n; + } + /* ALTER DOMAIN DROP NOT NULL */ + | ALTER DOMAIN_P any_name DROP NOT NULL_P + { + AlterDomainStmt *n = makeNode(AlterDomainStmt); + n->subtype = 'N'; + n->typename = $3; + $$ = (Node *)n; + } + /* ALTER DOMAIN SET NOT NULL */ + | ALTER DOMAIN_P any_name SET NOT NULL_P + { + AlterDomainStmt *n = makeNode(AlterDomainStmt); + n->subtype = 'O'; + n->typename = $3; + $$ = (Node *)n; + } + /* ALTER DOMAIN ADD CONSTRAINT ... */ + | ALTER DOMAIN_P any_name ADD TableConstraint + { + AlterDomainStmt *n = makeNode(AlterDomainStmt); + n->subtype = 'C'; + n->typename = $3; + n->def = $5; + $$ = (Node *)n; + } + /* ALTER DOMAIN DROP CONSTRAINT [RESTRICT|CASCADE] */ + | ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior + { + AlterDomainStmt *n = makeNode(AlterDomainStmt); + n->subtype = 'X'; + n->typename = $3; + n->name = $6; + n->behavior = $7; + $$ = (Node *)n; + } + ; opt_as: AS {} | /* EMPTY */ {} Index: src/backend/parser/parse_expr.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/parse_expr.c,v retrieving revision 1.131 diff -c -r1.131 parse_expr.c *** src/backend/parser/parse_expr.c 2002/11/26 03:01:58 1.131 --- src/backend/parser/parse_expr.c 2002/11/28 16:12:07 *************** *** 627,632 **** --- 627,640 ---- case T_DomainConstraintValue: { + /* + * If domVal is NULL, we are not translating an expression that + * can use it + */ + if (domVal == NULL) + elog(ERROR, "VALUE is not allowed in expression for node %d", + nodeTag(expr)); + result = (Node *) copyObject(domVal); break; Index: src/backend/tcop/postgres.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/tcop/postgres.c,v retrieving revision 1.310 diff -c -r1.310 postgres.c *** src/backend/tcop/postgres.c 2002/11/19 17:21:40 1.310 --- src/backend/tcop/postgres.c 2002/11/28 16:12:07 *************** *** 2319,2324 **** --- 2319,2328 ---- tag = "ALTER TABLE"; break; + case T_AlterDomainStmt: + tag = "ALTER DOMAIN"; + break; + case T_GrantStmt: { GrantStmt *stmt = (GrantStmt *) parsetree; Index: src/backend/tcop/utility.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.182 diff -c -r1.182 utility.c *** src/backend/tcop/utility.c 2002/11/15 03:09:38 1.182 --- src/backend/tcop/utility.c 2002/11/28 16:12:08 *************** *** 36,41 **** --- 36,42 ---- #include "commands/sequence.h" #include "commands/tablecmds.h" #include "commands/trigger.h" + #include "commands/typecmds.h" #include "commands/user.h" #include "commands/vacuum.h" #include "commands/view.h" *************** *** 555,560 **** --- 556,604 ---- break; default: /* oops */ elog(ERROR, "T_AlterTableStmt: unknown subtype"); + break; + } + } + break; + + case T_AlterDomainStmt: + { + AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree; + + /* + * Some or all of these functions are recursive to cover + * inherited things, so permission checks are done there. + */ + switch (stmt->subtype) + { + case 'T': /* ALTER COLUMN DEFAULT */ + + /* + * Recursively alter column default for table and, + * if requested, for descendants + */ + AlterDomainDefault(stmt->typename, + stmt->def); + break; + case 'N': /* ALTER COLUMN DROP NOT NULL */ + AlterDomainNotNull(stmt->typename, + false); + break; + case 'O': /* ALTER COLUMN SET NOT NULL */ + AlterDomainNotNull(stmt->typename, + true); + break; + case 'C': /* ADD CONSTRAINT */ + AlterDomainAddConstraint(stmt->typename, + stmt->def); + break; + case 'X': /* DROP CONSTRAINT */ + AlterDomainDropConstraint(stmt->typename, + stmt->name, + stmt->behavior); + break; + default: /* oops */ + elog(ERROR, "T_AlterDomainStmt: unknown subtype"); break; } } Index: src/include/catalog/pg_type.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/catalog/pg_type.h,v retrieving revision 1.134 diff -c -r1.134 pg_type.h *** src/include/catalog/pg_type.h 2002/09/24 21:26:44 1.134 --- src/include/catalog/pg_type.h 2002/11/28 16:12:09 *************** *** 550,562 **** Oid elementType, Oid baseType, const char *defaultTypeValue, ! const char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull); extern void TypeRename(const char *oldTypeName, Oid typeNamespace, --- 550,574 ---- Oid elementType, Oid baseType, const char *defaultTypeValue, ! char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull); + + extern void + GenerateTypeDependencies(Oid typeNamespace, + Oid typeObjectId, + Oid relationOid, /* only for 'c'atalog typeType */ + char relationKind, + Oid inputProcedure, + Oid outputProcedure, + Oid elementType, + Oid baseType, + char *defaultTypeBin, /* cooked rep */ + bool rebuild); extern void TypeRename(const char *oldTypeName, Oid typeNamespace, Index: src/include/commands/defrem.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/commands/defrem.h,v retrieving revision 1.46 diff -c -r1.46 defrem.h *** src/include/commands/defrem.h 2002/09/21 18:39:26 1.46 --- src/include/commands/defrem.h 2002/11/28 16:12:09 *************** *** 52,65 **** extern void DefineAggregate(List *names, List *parameters); extern void RemoveAggregate(RemoveAggrStmt *stmt); - /* commands/typecmds.c */ - extern void DefineType(List *names, List *parameters); - extern void RemoveType(List *names, DropBehavior behavior); - extern void RemoveTypeById(Oid typeOid); - extern void DefineDomain(CreateDomainStmt *stmt); - extern void RemoveDomain(List *names, DropBehavior behavior); - extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist); - /* commands/opclasscmds.c */ extern void DefineOpClass(CreateOpClassStmt *stmt); extern void RemoveOpClass(RemoveOpClassStmt *stmt); --- 52,57 ---- Index: src/include/nodes/nodes.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/nodes.h,v retrieving revision 1.124 diff -c -r1.124 nodes.h *** src/include/nodes/nodes.h 2002/11/24 21:52:14 1.124 --- src/include/nodes/nodes.h 2002/11/28 16:12:09 *************** *** 147,152 **** --- 147,153 ---- T_UpdateStmt, T_SelectStmt, T_AlterTableStmt, + T_AlterDomainStmt, T_SetOperationStmt, T_GrantStmt, T_ClosePortalStmt, Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/parsenodes.h,v retrieving revision 1.218 diff -c -r1.218 parsenodes.h *** src/include/nodes/parsenodes.h 2002/11/25 03:36:50 1.218 --- src/include/nodes/parsenodes.h 2002/11/28 16:12:10 *************** *** 828,833 **** --- 828,860 ---- } AlterTableStmt; /* ---------------------- + * Alter Domain + * + * The fields are used in different ways by the different variants of + * this command. Subtypes should match AlterTable subtypes + * ---------------------- + */ + typedef struct AlterDomainStmt + { + NodeTag type; + char subtype; /*------------ + * T = alter column default + * N = alter column drop not null + * O = alter column set not null + * C = add constraint + * X = drop constraint + * U = change owner + *------------ + */ + List *typename; /* table to work on */ + char *name; /* column or constraint name to act on, or + * new owner */ + Node *def; /* definition of default or constraint */ + DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ + } AlterDomainStmt; + + + /* ---------------------- * Grant|Revoke Statement * ---------------------- */ Index: src/test/regress/resultmap =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/resultmap,v retrieving revision 1.60 diff -c -r1.60 resultmap *** src/test/regress/resultmap 2002/11/21 04:40:26 1.60 --- src/test/regress/resultmap 2002/11/28 16:12:11 *************** *** 14,21 **** float8/alpha.*-dec-osf.*:cc=float8-fp-exception float8/i.86-pc-cygwin=float8-small-is-zero geometry/.*-darwin=geometry-positive-zeros ! geometry/i.86-.*-freebsd4.[0-5]=geometry-positive-zeros ! geometry/alpha.*-freebsd4.[0-5]=geometry-positive-zeros geometry/i.86-.*-openbsd=geometry-positive-zeros geometry/sparc-.*-openbsd=geometry-positive-zeros geometry/.*-netbsd1.[0-5]=geometry-positive-zeros --- 14,21 ---- float8/alpha.*-dec-osf.*:cc=float8-fp-exception float8/i.86-pc-cygwin=float8-small-is-zero geometry/.*-darwin=geometry-positive-zeros ! geometry/i.86-.*-freebsd4.[0-7]=geometry-positive-zeros ! geometry/alpha.*-freebsd4.[0-7]=geometry-positive-zeros geometry/i.86-.*-openbsd=geometry-positive-zeros geometry/sparc-.*-openbsd=geometry-positive-zeros geometry/.*-netbsd1.[0-5]=geometry-positive-zeros Index: src/test/regress/expected/domain.out =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/expected/domain.out,v retrieving revision 1.13 diff -c -r1.13 domain.out *** src/test/regress/expected/domain.out 2002/11/15 02:50:21 1.13 --- src/test/regress/expected/domain.out 2002/11/28 16:12:11 *************** *** 115,121 **** ERROR: Domain dnotnull does not allow NULL values INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good insert into nulltest values ('a', 'b', 'c', 'd', NULL); ! ERROR: Domain $1 constraint dcheck failed insert into nulltest values ('a', 'b', 'c', 'd', 'a'); ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest" INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd'); --- 115,121 ---- ERROR: Domain dnotnull does not allow NULL values INSERT INTO nulltest values ('a', 'b', 'c', 'd', 'c'); -- Good insert into nulltest values ('a', 'b', 'c', 'd', NULL); ! ERROR: ExecEvalConstraintTest: Domain dcheck constraint $1 failed insert into nulltest values ('a', 'b', 'c', 'd', 'a'); ERROR: ExecInsert: rejected due to CHECK constraint "nulltest_col5" on "nulltest" INSERT INTO nulltest values (NULL, 'b', 'c', 'd', 'd'); *************** *** 127,133 **** INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good -- Test copy COPY nulltest FROM stdin; --fail ! ERROR: copy: line 1, Domain $1 constraint dcheck failed lost synchronization with server, resetting connection SET autocommit TO 'on'; -- Last row is bad --- 127,133 ---- INSERT INTO nulltest values ('a', 'b', 'c', NULL, 'd'); -- Good -- Test copy COPY nulltest FROM stdin; --fail ! ERROR: copy: line 1, ExecEvalConstraintTest: Domain dcheck constraint $1 failed lost synchronization with server, resetting connection SET autocommit TO 'on'; -- Last row is bad *************** *** 158,163 **** --- 158,164 ---- drop table nulltest; drop domain dnotnull restrict; drop domain dnull restrict; + drop domain dcheck restrict; create domain ddef1 int4 DEFAULT 3; create domain ddef2 oid DEFAULT '12'; -- Type mixing, function returns int8 *************** *** 191,197 **** (4 rows) drop sequence ddef4_seq; ! drop table defaulttest; drop domain ddef1 restrict; drop domain ddef2 restrict; drop domain ddef3 restrict; --- 192,271 ---- (4 rows) drop sequence ddef4_seq; ! drop table defaulttest cascade; ! -- Test ALTER DOMAIN .. NOT NULL ! create domain dnotnulltest integer; ! create table domnotnull ! ( col1 dnotnulltest ! , col2 dnotnulltest ! ); ! insert into domnotnull default values; ! alter domain dnotnulltest set not null; -- fails ! ERROR: ALTER DOMAIN: Relation "domnotnull" Attribute "col1" contains NULL values ! update domnotnull set col1 = 5; ! alter domain dnotnulltest set not null; -- fails ! ERROR: ALTER DOMAIN: Relation "domnotnull" Attribute "col2" contains NULL values ! update domnotnull set col2 = 6; ! alter domain dnotnulltest set not null; ! alter domain dnotnulltest set not null; -- fails ! ERROR: AlterDomain: dnotnulltest is already set to NOT NULL ! update domnotnull set col1 = null; -- fails ! ERROR: Domain dnotnulltest does not allow NULL values ! alter domain dnotnulltest drop not null; ! alter domain dnotnulltest drop not null; -- fails ! ERROR: AlterDomain: dnotnulltest is already set to NULL ! update domnotnull set col1 = null; ! drop domain dnotnulltest cascade; ! NOTICE: Drop cascades to table domnotnull column col2 ! NOTICE: Drop cascades to table domnotnull column col1 ! -- Test ALTER DOMAIN .. DEFAULT .. ! create table domdeftest (col1 ddef1); ! insert into domdeftest default values; ! select * from domdeftest; ! col1 ! ------ ! 3 ! (1 row) ! ! alter domain ddef1 set default '42'; ! insert into domdeftest default values; ! select * from domdeftest; ! col1 ! ------ ! 3 ! 42 ! (2 rows) ! ! alter domain ddef1 drop default; ! insert into domdeftest default values; ! select * from domdeftest; ! col1 ! ------ ! 3 ! 42 ! ! (3 rows) ! ! drop table domdeftest; ! -- Test ALTER DOMAIN .. CONSTRAINT .. ! create domain con as integer; ! create table domcontest (col1 con); ! insert into domcontest values (1); ! insert into domcontest values (2); ! alter domain con add constraint t check (VALUE < 1); -- fails ! ERROR: AlterDomainAddConstraint: Domain con constraint t failed ! alter domain con add constraint t check (VALUE < 34); ! alter domain con add check (VALUE > 0); ! insert into domcontest values (-5); -- fails ! ERROR: ExecEvalConstraintTest: Domain con constraint $1 failed ! insert into domcontest values (42); -- fails ! ERROR: ExecEvalConstraintTest: Domain con constraint t failed ! insert into domcontest values (5); ! alter domain con drop constraint t; ! insert into domcontest values (-5); --fails ! ERROR: ExecEvalConstraintTest: Domain con constraint $1 failed ! insert into domcontest values (42); ! -- cleanup drop domain ddef1 restrict; drop domain ddef2 restrict; drop domain ddef3 restrict; Index: src/test/regress/sql/domain.sql =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/sql/domain.sql,v retrieving revision 1.10 diff -c -r1.10 domain.sql *** src/test/regress/sql/domain.sql 2002/11/15 02:50:21 1.10 --- src/test/regress/sql/domain.sql 2002/11/28 16:12:11 *************** *** 127,132 **** --- 127,133 ---- drop table nulltest; drop domain dnotnull restrict; drop domain dnull restrict; + drop domain dcheck restrict; create domain ddef1 int4 DEFAULT 3; *************** *** 159,165 **** select * from defaulttest; drop sequence ddef4_seq; ! drop table defaulttest; drop domain ddef1 restrict; drop domain ddef2 restrict; drop domain ddef3 restrict; --- 160,230 ---- select * from defaulttest; drop sequence ddef4_seq; ! drop table defaulttest cascade; ! ! -- Test ALTER DOMAIN .. NOT NULL ! create domain dnotnulltest integer; ! create table domnotnull ! ( col1 dnotnulltest ! , col2 dnotnulltest ! ); ! ! insert into domnotnull default values; ! alter domain dnotnulltest set not null; -- fails ! ! update domnotnull set col1 = 5; ! alter domain dnotnulltest set not null; -- fails ! ! update domnotnull set col2 = 6; ! ! alter domain dnotnulltest set not null; ! alter domain dnotnulltest set not null; -- fails ! ! update domnotnull set col1 = null; -- fails ! ! alter domain dnotnulltest drop not null; ! alter domain dnotnulltest drop not null; -- fails ! ! update domnotnull set col1 = null; ! ! drop domain dnotnulltest cascade; ! ! -- Test ALTER DOMAIN .. DEFAULT .. ! create table domdeftest (col1 ddef1); ! ! insert into domdeftest default values; ! select * from domdeftest; ! ! alter domain ddef1 set default '42'; ! insert into domdeftest default values; ! select * from domdeftest; ! ! alter domain ddef1 drop default; ! insert into domdeftest default values; ! select * from domdeftest; ! ! drop table domdeftest; ! ! -- Test ALTER DOMAIN .. CONSTRAINT .. ! create domain con as integer; ! create table domcontest (col1 con); ! ! insert into domcontest values (1); ! insert into domcontest values (2); ! alter domain con add constraint t check (VALUE < 1); -- fails ! ! alter domain con add constraint t check (VALUE < 34); ! alter domain con add check (VALUE > 0); ! ! insert into domcontest values (-5); -- fails ! insert into domcontest values (42); -- fails ! insert into domcontest values (5); ! ! alter domain con drop constraint t; ! insert into domcontest values (-5); --fails ! insert into domcontest values (42); ! ! -- cleanup drop domain ddef1 restrict; drop domain ddef2 restrict; drop domain ddef3 restrict;