Commit d3788c33 authored by Bruce Momjian's avatar Bruce Momjian

Add DOMAIN support. Includes manual pages and regression tests, from

Rod Taylor.
parent 525b1939
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.33 2002/03/07 16:35:32 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.34 2002/03/19 02:18:10 momjian Exp $
-->
<chapter id="catalogs">
......@@ -2510,6 +2510,53 @@
</para></entry>
</row>
<row>
<entry>typbasetype</entry>
<entry><type>oid</type></entry>
<entry></entry>
<entry><para>
<structfield>typbasetype</structfield> is the type that this one is based
on. Normally references the domains parent type, and is 0 otherwise.
</para></entry>
</row>
<row>
<entry>typnotnull</entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry><para>
<structfield>typnotnull</structfield> represents a NOT NULL
constraint on a type. Used for domains only.
</para></entry>
</row>
<row>
<entry>typmod</entry>
<entry><type>integer</type></entry>
<entry></entry>
<entry><para>
<structfield>typmod</structfield> records type-specific data
supplied at table creation time (for example, the maximum
length of a <type>varchar</type> column). It is passed to
type-specific input and output functions as the third
argument. The value will generally be -1 for types that do not
need typmod. This data is copied to
<structfield>pg_attribute.atttypmod</structfield> on creation
of a table using a domain as it's field type.
</para></entry>
</row>
<row>
<entry>typdefaultbin</entry>
<entry><type>text</type></entry>
<entry></entry>
<entry><para>
<structfield>typdefaultbin</structfield> is NULL for types without a
default value. If it's not NULL, it contains the internal string
representation of the default expression node.
</para></entry>
</row>
<row>
<entry>typdefault</entry>
<entry><type>text</type></entry>
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.35 2002/03/07 16:35:32 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.36 2002/03/19 02:18:12 momjian Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
......@@ -52,6 +52,7 @@ Complete list of usable sgml source files in this directory.
<!entity createAggregate system "create_aggregate.sgml">
<!entity createConstraint system "create_constraint.sgml">
<!entity createDatabase system "create_database.sgml">
<!entity createDomain system "create_domain.sgml">
<!entity createFunction system "create_function.sgml">
<!entity createGroup system "create_group.sgml">
<!entity createIndex system "create_index.sgml">
......@@ -69,6 +70,7 @@ Complete list of usable sgml source files in this directory.
<!entity delete system "delete.sgml">
<!entity dropAggregate system "drop_aggregate.sgml">
<!entity dropDatabase system "drop_database.sgml">
<!entity dropDomain system "drop_domain.sgml">
<!entity dropFunction system "drop_function.sgml">
<!entity dropGroup system "drop_group.sgml">
<!entity dropIndex system "drop_index.sgml">
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.14 2002/03/07 16:35:33 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.15 2002/03/19 02:18:12 momjian Exp $
PostgreSQL documentation
-->
......@@ -25,7 +25,7 @@ PostgreSQL documentation
<synopsis>
COMMENT ON
[
[ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
[ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
......@@ -33,7 +33,7 @@ COMMENT ON
TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
] IS <replaceable class="PARAMETER">'text'</replaceable>
</synopsis>
<refsect2 id="R2-SQL-COMMENT-1">
<refsect2info>
<date>1999-10-25</date>
......@@ -64,7 +64,7 @@ COMMENT ON
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-COMMENT-2">
<refsect2info>
<date>1998-09-08</date>
......@@ -99,7 +99,7 @@ COMMENT
</title>
<para>
<command>COMMENT</command> stores a comment about a database object.
Comments can be
Comments can be
easily retrieved with <command>psql</command>'s
<command>\dd</command>, <command>\d+</command>, or <command>\l+</command>
commands. Other user interfaces to retrieve comments can be built atop
......@@ -141,6 +141,7 @@ COMMENT ON mytable IS 'This is my table.';
<programlisting>
COMMENT ON DATABASE my_database IS 'Development Database';
COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
COMMENT ON RULE my_rule IS 'Logs UPDATES of employee records';
COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
......@@ -155,12 +156,12 @@ COMMENT ON TRIGGER my_trigger ON my_table IS 'Used for R.I.';
</programlisting>
</para>
</refsect1>
<refsect1 id="R1-SQL-COMMENT-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-COMMENT-4">
<refsect2info>
<date>1998-09-08</date>
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_domain.sgml,v 1.3 2002/03/19 02:18:13 momjian Exp $
PostgreSQL documentation
-->
<refentry id="SQL-CREATEDOMAIN">
<refmeta>
<refentrytitle id="sql-createdomian-title">
CREATE DOMAIN
</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
CREATE DOMAIN
</refname>
<refpurpose>
define a new domain
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2002-02-24</date>
</refsynopsisdivinfo>
<synopsis>
CREATE DOMAIN <replaceable class="parameter">domainname</replaceable> <replaceable class="parameter">data_type</replaceable> [ DEFAULT <replaceable>default_expr</> ] [ <replaceable class="PARAMETER">column_constraint</replaceable> [, ... ] ]
[ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
{ NOT NULL | NULL <!-- | UNIQUE | PRIMARY KEY |
CHECK (<replaceable class="PARAMETER">expression</replaceable>) |
REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> ) ] [ MATCH FULL | MATCH PARTIAL ]
[ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] --> }
<!-- [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] -->
</synopsis>
<refsect2 id="R2-SQL-CREATEDOMAIN-1">
<refsect2info>
<date>2002-02-24</date>
</refsect2info>
<title>
Parameters
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">domainname</replaceable></term>
<listitem>
<para>
The name of a domain to be created.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">data_type</replaceable></term>
<listitem>
<para>
The data type of the domain. This may include array specifiers.
Refer to the <citetitle>User's Guide</citetitle> for further
information about data types and arrays.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DEFAULT
<replaceable>default_expr</replaceable></literal></term>
<listitem>
<para>
The <literal>DEFAULT</> clause assigns a default data value for
the column whose column definition it appears within. The value
is any variable-free expression (subselects and cross-references
to other columns in the current table are not allowed). The
data type of the default expression must match the data type of the
domain.
</para>
<para>
The default expression will be used in any insert operation that
does not specify a value for the domain. If there is no default
for a domain, then the default is NULL.
</para>
<note>
<para>
The default of a column will be tested before that of the domain.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable></literal></term>
<listitem>
<para>
An optional name for a domain. If not specified,
the system generates a name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NOT NULL</></term>
<listitem>
<para>
The column is not allowed to contain NULL values. This is
equivalent to the column constraint <literal>CHECK (<replaceable
class="PARAMETER">column</replaceable> NOT NULL)</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NULL</></term>
<listitem>
<para>
The column is allowed to contain NULL values. This is the default.
</para>
<para>
This clause is only available for compatibility with
non-standard SQL databases. Its use is discouraged in new
applications.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-CREATEDOMAIN-2">
<refsect2info>
<date>2002-02-24</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>
CREATE DOMAIN
</computeroutput></term>
<listitem>
<para>
Message returned if the domain is successfully created.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-CREATEDOMAIN-1">
<refsect1info>
<date>2002-02-24</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>CREATE DOMAIN</command> allows the user to register a new user data
domain with PostgreSQL for use in the current data base. The
user who defines a domain becomes its owner.
<replaceable class="parameter">domainname</replaceable> is
the name of the new type and must be unique within the
types and domains defined for this database.
</para>
<para>
Domains are useful for abstracting common fields between tables into
a single location for maintenance. An email address column may be used
in several tables, all with the same properties. Define a domain and
use that rather than setting up each tables constraints individually.
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
This example creates the <type>country_code</type> data type and then uses the
type in a table definition:
<programlisting>
CREATE DOMAIN country_code char(2) NOT NULL;
CREATE TABLE countrylist (id INT4, country country_code);
</programlisting>
</para>
</refsect1>
<refsect1 id="SQL-CREATEDOMAIN-compatibility">
<title>Compatibility</title>
<para>
This <command>CREATE DOMAIN</command> command is a
<productname>PostgreSQL</productname> extension. CHECK and FOREIGN KEY
constraints are currently unsupported.
</para>
</refsect1>
<refsect1 id="SQL-CREATEDOMAIN-see-also">
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-dropdomain"></member>
<member><citetitle>PostgreSQL Programmer's Guide</citetitle></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_domain.sgml,v 1.3 2002/03/19 02:18:13 momjian Exp $
PostgreSQL documentation
-->
<refentry id="SQL-DROPDOMAIN">
<refmeta>
<refentrytitle id="SQL-DROPDOMAIN-TITLE">
DROP DOMAIN
</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
DROP DOMAIN
</refname>
<refpurpose>
remove a user-defined domain
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>1999-07-20</date>
</refsynopsisdivinfo>
<synopsis>
DROP DOMAIN <replaceable class="PARAMETER">domainname</replaceable> [, ...]
</synopsis>
<refsect2 id="R2-SQL-DROPDOMAIN-1">
<refsect2info>
<date>2002-02-24</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">domainname</replaceable></term>
<listitem>
<para>
The name of an existing domain.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-DROPDOMAIN-2">
<refsect2info>
<date>2002-02-24</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>
DROP
</computeroutput></term>
<listitem>
<para>
The message returned if the command is successful.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><computeroutput>
ERROR: RemoveDomain: type '<replaceable class="parameter">domainname</replaceable>' does not exist
</computeroutput></term>
<listitem>
<para>
This message occurs if the specified domain (or type) is not found.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-DROPDOMAIN-1">
<refsect1info>
<date>2002-02-24</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>DROP DOMAIN</command> will remove a user domain from the
system catalogs.
</para>
<para>
Only the owner of a domain can remove it.
</para>
</refsect1>
<refsect1 id="SQL-DROPDOMAIN-notes">
<title>Notes</title>
<itemizedlist>
<listitem>
<para>
It is the user's responsibility to remove any operators,
functions, aggregates, access methods, and tables that
use a deleted domain.
</para>
</listitem>
</itemizedlist>
</refsect1>
<refsect1 id="SQL-DROPDOMAIN-examples">
<title>Examples</title>
<para>
To remove the <type>box</type> domain:
<programlisting>
DROP DOMAIN box RESTRICT;
</programlisting>
</para>
</refsect1>
<refsect1 id="SQL-DROPDOMAIN-compatibility">
<title>Compatibility</title>
<para>
A <command>DROP DOMAIN</command> statement exists in SQL99. As with
most other <quote>drop</quote> commands, <command>DROP
DOMAIN</command> in SQL99 requires a <quote>drop behavior</quote>
clause to select between dropping all dependent objects or refusing
to drop if dependent objects exist:
<synopsis>
DROP DOMAIN <replaceable>name</replaceable> { CASCADE | RESTRICT }
</synopsis>
<productname>PostgreSQL</productname> enforces the existance of
RESTRICT or CASCADE but ignores their enforcement against the
system tables.
</para>
</refsect1>
<refsect1 id="SQL-DROPDOMAIN-see-also">
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createdomain"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!-- reference.sgml
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.23 2002/03/07 16:35:32 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.24 2002/03/19 02:18:11 momjian Exp $
PostgreSQL Reference Manual
-->
......@@ -61,6 +61,7 @@ PostgreSQL Reference Manual
&createAggregate;
&createConstraint;
&createDatabase;
&createDomain;
&createFunction;
&createGroup;
&createIndex;
......@@ -78,6 +79,7 @@ PostgreSQL Reference Manual
&delete;
&dropAggregate;
&dropDatabase;
&dropDomain;
&dropFunction;
&dropGroup;
&dropIndex;
......@@ -115,7 +117,7 @@ PostgreSQL Reference Manual
&unlisten;
&update;
&vacuum;
</reference>
<!--
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.186 2002/03/07 16:35:33 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.187 2002/03/19 02:18:14 momjian Exp $
*
*
* INTERFACE ROUTINES
......@@ -49,6 +49,7 @@
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
......@@ -698,10 +699,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 domains */
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 +1590,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 +1624,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 +1847,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)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.67 2002/03/07 16:35:33 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.68 2002/03/19 02:18:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -176,10 +176,16 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
values[i++] = CharGetDatum('i'); /* 15 */
values[i++] = CharGetDatum('p'); /* 16 */
values[i++] = CharGetDatum('i'); /* 15 */
values[i++] = CharGetDatum('p'); /* 16 */
values[i++] = BoolGetDatum(false); /* 17 */
values[i++] = Int32GetDatum(-1); /* 18 */
values[i++] = ObjectIdGetDatum(InvalidOid); /* 19 */
values[i++] = Int32GetDatum(0); /* 20 */
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(typeName)); /* 17 */
CStringGetDatum(typeName)); /* 21 */
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(typeName)); /* 22 */
/*
* create a new type tuple with FormHeapTuple
......@@ -264,7 +270,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 +280,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 +296,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];
......@@ -317,6 +329,17 @@ TypeCreate(char *typeName,
elog(ERROR, "type %s does not exist", elementTypeName);
}
/*
* 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 +411,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 +434,7 @@ TypeCreate(char *typeName,
PointerGetDatum(argList),
0);
}
if (!OidIsValid(procOid))
func_error("TypeCreate", procname, 1, argList, NULL);
}
......@@ -428,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.
*/
......@@ -436,7 +488,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.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.85 2002/03/07 16:35:34 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.86 2002/03/19 02:18:15 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
......@@ -69,6 +69,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
*/
StrNCpy(relname, stmt->relname, NAMEDATALEN);
/*
* Inherit domain attributes into the known columns before table 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,66 @@ TruncateRelation(char *name)
heap_truncate(name);
}
/*
* MergeDomainAttributes
* Returns a new table schema with the constraints, types, and other
* attributes of the domain resolved for fields using the domain as
* their type.
*
* Defaults are pulled out by the table attribute as required, similar to
* how all types defaults are processed.
*/
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);
}
return schema;
}
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
......
This diff is collapsed.
/*-------------------------------------------------------------------------
*
* 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.68 2002/03/07 16:35:34 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.69 2002/03/19 02:18:16 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"
......@@ -275,6 +276,60 @@ RemoveType(char *typeName) /* type name to be removed */
heap_close(relation, RowExclusiveLock);
}
/*
* 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.
......
......@@ -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.169 2002/03/12 00:51:37 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.170 2002/03/19 02:18:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2231,6 +2231,20 @@ _copyLoadStmt(LoadStmt *from)
return newnode;
}
static CreateDomainStmt *
_copyCreateDomainStmt(CreateDomainStmt *from)
{
CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
if (from->domainname)
newnode->domainname = pstrdup(from->domainname);
Node_Copy(from, newnode, typename);
Node_Copy(from, newnode, constraints);
return newnode;
}
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
......@@ -3031,6 +3045,9 @@ copyObject(void *from)
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
case T_CreateDomainStmt:
retval = _copyCreateDomainStmt(from);
break;
default:
elog(ERROR, "copyObject: don't know how to copy node type %d",
......
......@@ -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.117 2002/03/12 00:51:37 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.118 2002/03/19 02:18:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1093,6 +1093,19 @@ _equalLoadStmt(LoadStmt *a, LoadStmt *b)
return true;
}
static bool
_equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
{
if (!equalstr(a->domainname, b->domainname))
return false;
if (!equal(a->typename, b->typename))
return false;
if (!equal(a->constraints, b->constraints))
return false;
return true;
}
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
......@@ -2021,6 +2034,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;
......
......@@ -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.48 2002/03/07 16:35:35 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.49 2002/03/19 02:18:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -355,8 +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;
Node *expr;
......@@ -392,7 +390,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 +428,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;
}
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.291 2002/03/10 06:02:23 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.292 2002/03/19 02:18:18 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -98,7 +98,6 @@ static void doNegateFloat(Value *v);
%}
%union
{
int ival;
......@@ -134,9 +133,10 @@ static void doNegateFloat(Value *v);
AlterDatabaseSetStmt, AlterGroupStmt, AlterSchemaStmt, AlterTableStmt,
AlterUserStmt, AlterUserSetStmt, AnalyzeStmt,
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CopyStmt, CreateAsStmt, CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
CreateUserStmt, CreatedbStmt, CursorStmt,
DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
......@@ -289,6 +289,8 @@ static void doNegateFloat(Value *v);
%type <list> constraints_set_list
%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 +345,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 +448,7 @@ stmt : AlterDatabaseSetStmt
| CopyStmt
| CreateStmt
| CreateAsStmt
| CreateDomainStmt
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
......@@ -776,8 +779,11 @@ DropSchemaStmt: DROP SCHEMA UserId
n->dbname = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* Set PG internal variable
......@@ -1439,7 +1445,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
......@@ -2021,13 +2030,22 @@ 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;
}
| ColId '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
$$->arg = (Node *)$3;
}
| ColLabel
| ColId
{
$$ = makeNode(DefElem);
$$->defname = $1;
......@@ -2056,6 +2074,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;
}
;
......@@ -2088,7 +2115,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
......@@ -2174,6 +2201,7 @@ comment_type: DATABASE { $$ = DATABASE; }
| RULE { $$ = RULE; }
| SEQUENCE { $$ = SEQUENCE; }
| TABLE { $$ = TABLE; }
| DOMAIN_P { $$ = TYPE_P; }
| TYPE_P { $$ = TYPE_P; }
| VIEW { $$ = VIEW; }
;
......@@ -3156,6 +3184,22 @@ createdb_opt_item: LOCATION opt_equal Sconst
{
$$ = lconsi(3, makeListi1(-1));
}
;
/*****************************************************************************
*
* DROP DATABASE
*
*
*****************************************************************************/
DropdbStmt: DROP DATABASE database_name
{
DropdbStmt *n = makeNode(DropdbStmt);
n->dbname = $3;
$$ = (Node *)n;
}
| OWNER opt_equal name
{
$$ = lconsi(4, makeList1($3));
......@@ -3200,22 +3244,30 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
}
;
/*****************************************************************************
*
* DROP DATABASE
* Manipulate a domain
*
*
*****************************************************************************/
DropdbStmt: DROP DATABASE database_name
CreateDomainStmt: CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
{
DropdbStmt *n = makeNode(DropdbStmt);
n->dbname = $3;
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; }
;
/*****************************************************************************
*
......@@ -5857,6 +5909,7 @@ unreserved_keyword:
| DEFERRED { $$ = "deferred"; }
| DELETE { $$ = "delete"; }
| DELIMITERS { $$ = "delimiters"; }
| DOMAIN_P { $$ = "domain"; }
| DOUBLE { $$ = "double"; }
| DROP { $$ = "drop"; }
| EACH { $$ = "each"; }
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.103 2002/03/07 16:35:35 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.104 2002/03/19 02:18:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -97,6 +97,7 @@ static ScanKeyword ScanKeywords[] = {
{"desc", DESC},
{"distinct", DISTINCT},
{"do", DO},
{"domain", DOMAIN_P},
{"double", DOUBLE},
{"drop", DROP},
{"each", EACH},
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.66 2002/03/07 16:35:35 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.67 2002/03/19 02:18:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -605,3 +605,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;
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.108 2002/03/12 00:51:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.109 2002/03/19 02:18:20 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;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.254 2002/03/06 06:10:09 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.255 2002/03/19 02:18:20 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -1722,7 +1722,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.254 $ $Date: 2002/03/06 06:10:09 $\n");
puts("$Revision: 1.255 $ $Date: 2002/03/19 02:18:20 $\n");
}
/*
......@@ -2212,8 +2212,9 @@ CreateCommandTag(Node *parsetree)
}
break;
case T_CreateDomainStmt:
case T_CreateStmt:
tag = "CREATE";
tag = "CREATE DOMAIN";
break;
case T_DropStmt:
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.132 2002/03/07 16:35:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.133 2002/03/19 02:18:20 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;
}
/*
......@@ -726,6 +731,19 @@ ProcessUtility(Node *parsetree,
DropProceduralLanguage((DropPLangStmt *) parsetree);
break;
/*
* ******************************** DOMAIN statements ****
*
*/
case T_CreateDomainStmt:
DefineDomain((CreateDomainStmt *) parsetree);
break;
/*
* ******************************** USER statements ****
*
*/
case T_CreateUserStmt:
CreateUser((CreateUserStmt *) parsetree);
break;
......
......@@ -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.26 2002/03/07 16:35:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.27 2002/03/19 02:18:21 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 */
......
......@@ -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.62 2002/03/07 16:35:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.63 2002/03/19 02:18:21 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;
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.156 2002/03/07 16:35:36 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.157 2002/03/19 02:18:22 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)
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: heap.h,v 1.43 2002/03/07 16:35:38 momjian Exp $
* $Id: heap.h,v 1.44 2002/03/19 02:18:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -15,6 +15,8 @@
#define HEAP_H
#include "catalog/pg_attribute.h"
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
#include "utils/rel.h"
typedef struct RawColumnDefault
......@@ -45,6 +47,12 @@ extern void AddRelationRawConstraints(Relation rel,
List *rawColDefaults,
List *rawConstraints);
extern Node *cookDefault(ParseState *pstate
, Node *raw_default
, Oid atttypid
, int32 atttypmod
, char *attname);
extern int RemoveCheckConstraint(Relation rel, const char *constrName, bool inh);
extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno,
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_attribute.h,v 1.83 2002/03/07 16:35:38 momjian Exp $
* $Id: pg_attribute.h,v 1.84 2002/03/19 02:18:22 momjian Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -240,7 +240,13 @@ typedef FormData_pg_attribute *Form_pg_attribute;
{ 1247, {"typsend"}, 24, 0, 4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1247, {"typalign"}, 18, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \
{ 1247, {"typstorage"}, 18, 0, 1, 16, 0, -1, -1, true, 'p', false, 'c', false, false }, \
{ 1247, {"typdefault"}, 25, 0, -1, 17, 0, -1, -1, false , 'x', false, 'i', false, false }
{ 1247, {"typnotnull"}, 16, 0, 1, 17, 0, -1, -1, true, 'p', false, 'c', false, false }, \
{ 1247, {"typmod"}, 23, 0, 4, 18, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1247, {"typbasetype"}, 26, 0, 4, 19, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1247, {"typndims"}, 23, 0, 4, 20, 0, -1, -1, true, 'p', false, 'i', false, false }, \
{ 1247, {"typdefaultbin"}, 25, 0, -1, 21, 0, -1, -1, false, 'x', false, 'i', false, false }, \
{ 1247, {"typdefault"}, 25, 0, -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false }
DATA(insert ( 1247 typname 19 DEFAULT_ATTSTATTARGET NAMEDATALEN 1 0 -1 -1 f p f i f f));
DATA(insert ( 1247 typowner 23 0 4 2 0 -1 -1 t p f i f f));
......@@ -258,7 +264,12 @@ DATA(insert ( 1247 typreceive 24 0 4 13 0 -1 -1 t p f i f f));
DATA(insert ( 1247 typsend 24 0 4 14 0 -1 -1 t p f i f f));
DATA(insert ( 1247 typalign 18 0 1 15 0 -1 -1 t p f c f f));
DATA(insert ( 1247 typstorage 18 0 1 16 0 -1 -1 t p f c f f));
DATA(insert ( 1247 typdefault 25 0 -1 17 0 -1 -1 f x f i f f));
DATA(insert ( 1247 typnotnull 16 0 1 17 0 -1 -1 t p f c f f));
DATA(insert ( 1247 typmod 23 0 4 18 0 -1 -1 t p f i f f));
DATA(insert ( 1247 typbasetype 26 0 4 19 0 -1 -1 t p f i f f));
DATA(insert ( 1247 typndims 23 0 4 20 0 -1 -1 t p f i f f));
DATA(insert ( 1247 typdefaultbin 25 0 -1 21 0 -1 -1 f x f i f f));
DATA(insert ( 1247 typdefault 25 0 -1 22 0 -1 -1 f x f i f f));
DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p f i f f));
DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p f i f f));
DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p f i f f));
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_class.h,v 1.61 2002/03/07 16:35:38 momjian Exp $
* $Id: pg_class.h,v 1.62 2002/03/19 02:18:22 momjian Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -132,7 +132,7 @@ typedef FormData_pg_class *Form_pg_class;
* ----------------
*/
DATA(insert OID = 1247 ( pg_type 71 PGUID 0 1247 0 0 0 0 f f r 17 0 0 0 0 0 t f f f _null_ ));
DATA(insert OID = 1247 ( pg_type 71 PGUID 0 1247 0 0 0 0 f f r 22 0 0 0 0 0 t f f f _null_ ));
DESCR("");
DATA(insert OID = 1249 ( pg_attribute 75 PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
DESCR("");
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: defrem.h,v 1.30 2002/03/07 16:35:38 momjian Exp $
* $Id: defrem.h,v 1.31 2002/03/19 02:18:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -39,10 +39,12 @@ extern void CreateFunction(ProcedureStmt *stmt);
extern void DefineOperator(char *name, List *parameters);
extern void DefineAggregate(char *name, List *parameters);
extern void DefineType(char *name, List *parameters);
extern void DefineDomain(CreateDomainStmt *stmt);
/*
* prototypes in remove.c
*/
extern void RemoveDomain(char *domainName, int behavior);
extern void RemoveFunction(char *functionName, List *argTypes);
extern void RemoveOperator(char *operatorName,
char *typeName1, char *typeName2);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.100 2002/03/07 16:35:40 momjian Exp $
* $Id: nodes.h,v 1.101 2002/03/19 02:18:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -172,6 +172,7 @@ typedef enum NodeTag
T_TransactionStmt,
T_ViewStmt,
T_LoadStmt,
T_CreateDomainStmt,
T_CreatedbStmt,
T_DropdbStmt,
T_VacuumStmt,
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.160 2002/03/12 00:52:01 tgl Exp $
* $Id: parsenodes.h,v 1.161 2002/03/19 02:18:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -407,6 +407,23 @@ typedef struct DefElem
} DefElem;
/****************************************************************************
* Nodes for a Domain Creation tree
****************************************************************************/
/* ----------------------
* CreateDomain Statement
* ----------------------
* Down here as it required TypeName to be defined first.
*/
typedef struct CreateDomainStmt
{
NodeTag type;
char *domainname; /* name of domain to create */
TypeName *typename; /* the typecast */
List *constraints; /* constraints (list of Constraint nodes) */
} CreateDomainStmt;
/****************************************************************************
* Nodes for a Query tree
****************************************************************************/
......@@ -1055,12 +1072,14 @@ typedef struct DefineStmt
#define DROP_INDEX 4
#define DROP_RULE 5
#define DROP_TYPE_P 6
#define DROP_DOMAIN_P 7
typedef struct DropStmt
{
NodeTag type;
List *names;
int removeType;
int behavior; /* CASCADE or RESTRICT drop behavior */
} DropStmt;
/* ----------------------
......@@ -1269,6 +1288,7 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
/* ----------------------
* Createdb Statement
* ----------------------
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_coerce.h,v 1.39 2002/03/07 16:35:40 momjian Exp $
* $Id: parse_coerce.h,v 1.40 2002/03/19 02:18:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -81,5 +81,6 @@ extern Oid select_common_type(List *typeids, const char *context);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *context);
extern Oid getBaseType(Oid inType);
#endif /* PARSE_COERCE_H */
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: lsyscache.h,v 1.42 2002/03/07 16:35:41 momjian Exp $
* $Id: lsyscache.h,v 1.43 2002/03/19 02:18:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -44,7 +44,7 @@ extern int16 get_typlen(Oid typid);
extern bool get_typbyval(Oid typid);
extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
extern char get_typstorage(Oid typid);
extern bool get_typdefault(Oid typid, Datum *defaultValue);
extern Node *get_typdefault(Oid typid, int32 atttypmod);
extern int32 get_typavgwidth(Oid typid, int32 typmod);
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
extern bool get_attstatsslot(HeapTuple statstuple,
......
-- Test Comment / Drop
create domain domaindroptest int4;
comment on domain domaindroptest is 'About to drop this..';
create domain basetypetest domaindroptest;
ERROR: DefineDomain: domaindroptest is not a basetype
drop domain domaindroptest;
ERROR: parser: parse error at or near ";"
drop domain domaindroptest restrict;
-- TEST Domains.
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test tables using domains
create table basictest
( testint4 domainint4
, testtext domaintext
, testvarchar domainvarchar
, testnumeric domainnumeric
);
INSERT INTO basictest values ('88', 'haha', 'short', '123.12'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
ERROR: value too long for type character varying(5)
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric
select * from basictest;
testint4 | testtext | testvarchar | testnumeric
----------+----------+-------------+-------------
88 | haha | short | 123.12
88 | haha | short | 123.12
(2 rows)
drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext restrict;
-- Array Test
create domain domainint4arr int4[1];
create domain domaintextarr text[2][3];
create table domarrtest
( testint4arr domainint4arr
, testtextarr domaintextarr
);
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
INSERT INTO domarrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}{"e"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a"}{"c"}}');
INSERT INTO domarrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
drop table domarrtest;
drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15) NULL;
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
ERROR: ExecAppend: Fail to add null value in not null attribute col1
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute col1
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute col2
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
ERROR: ExecAppend: Fail to add null value in not null attribute col3
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
select * from nulltest;
col1 | col2 | col3 | col4
------+------+------+------
a | b | c | d
a | b | c |
(2 rows)
drop table nulltest;
drop domain dnotnull restrict;
drop domain dnull restrict;
create domain ddef1 int4 DEFAULT 3;
create domain ddef2 oid DEFAULT '12';
-- Type mixing, function returns int8
create domain ddef3 text DEFAULT 5;
create sequence ddef4_seq;
create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
create table defaulttest
( col1 ddef1
, col2 ddef2
, col3 ddef3
, col4 ddef4
, col5 ddef1 NOT NULL DEFAULT NULL
, col6 ddef2 DEFAULT '88'
, col7 ddef4 DEFAULT 8000
, col8 ddef5
);
insert into defaulttest default values;
insert into defaulttest default values;
insert into defaulttest default values;
select * from defaulttest;
col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8
------+------+------+------+------+------+------+-------
3 | 12 | 5 | 1 | 3 | 88 | 8000 | 12.12
3 | 12 | 5 | 2 | 3 | 88 | 8000 | 12.12
3 | 12 | 5 | 3 | 3 | 88 | 8000 | 12.12
(3 rows)
drop sequence ddef4_seq;
drop table defaulttest;
drop domain ddef1 restrict;
drop domain ddef2 restrict;
drop domain ddef3 restrict;
drop domain ddef4 restrict;
drop domain ddef5 restrict;
......@@ -73,4 +73,4 @@ test: select_views alter_table portals_p2 rules foreign_key
# The sixth group of parallel test
# ----------
# "plpgsql" cannot run concurrently with "rules"
test: limit plpgsql temp
test: limit plpgsql temp domain
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.7 2001/09/28 07:59:38 thomas Exp $
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.8 2002/03/19 02:18:24 momjian Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
......@@ -80,3 +80,5 @@ test: foreign_key
test: limit
test: plpgsql
test: temp
test: domain
-- Test Comment / Drop
create domain domaindroptest int4;
comment on domain domaindroptest is 'About to drop this..';
create domain basetypetest domaindroptest;
drop domain domaindroptest;
drop domain domaindroptest restrict;
-- TEST Domains.
create domain domainvarchar varchar(5);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
-- Test tables using domains
create table basictest
( testint4 domainint4
, testtext domaintext
, testvarchar domainvarchar
, testnumeric domainnumeric
);
INSERT INTO basictest values ('88', 'haha', 'short', '123.12'); -- Good
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212'); -- Truncate numeric
select * from basictest;
drop table basictest;
drop domain domainvarchar restrict;
drop domain domainnumeric restrict;
drop domain domainint4 restrict;
drop domain domaintext restrict;
-- Array Test
create domain domainint4arr int4[1];
create domain domaintextarr text[2][3];
create table domarrtest
( testint4arr domainint4arr
, testtextarr domaintextarr
);
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
INSERT INTO domarrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a","b"}{"c","d"}{"e"}}');
INSERT INTO domarrtest values ('{2,2}', '{{"a"}{"c"}}');
INSERT INTO domarrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
drop table domarrtest;
drop domain domainint4arr restrict;
drop domain domaintextarr restrict;
create domain dnotnull varchar(15) NOT NULL;
create domain dnull varchar(15) NULL;
create table nulltest
( col1 dnotnull
, col2 dnotnull NULL -- NOT NULL in the domain cannot be overridden
, col3 dnull NOT NULL
, col4 dnull
);
INSERT INTO nulltest DEFAULT VALUES;
INSERT INTO nulltest values ('a', 'b', 'c', 'd'); -- Good
INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
select * from nulltest;
drop table nulltest;
drop domain dnotnull restrict;
drop domain dnull restrict;
create domain ddef1 int4 DEFAULT 3;
create domain ddef2 oid DEFAULT '12';
-- Type mixing, function returns int8
create domain ddef3 text DEFAULT 5;
create sequence ddef4_seq;
create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
create table defaulttest
( col1 ddef1
, col2 ddef2
, col3 ddef3
, col4 ddef4
, col5 ddef1 NOT NULL DEFAULT NULL
, col6 ddef2 DEFAULT '88'
, col7 ddef4 DEFAULT 8000
, col8 ddef5
);
insert into defaulttest default values;
insert into defaulttest default values;
insert into defaulttest default values;
select * from defaulttest;
drop sequence ddef4_seq;
drop table defaulttest;
drop domain ddef1 restrict;
drop domain ddef2 restrict;
drop domain ddef3 restrict;
drop domain ddef4 restrict;
drop domain ddef5 restrict;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment