Commit 01c76f74 authored by Bruce Momjian's avatar Bruce Momjian

Ok. Updated patch attached.

- domain.patch -> source patch against pgsql in cvs
- drop_domain.sgml and create_domain.sgml -> New doc/src/sgml/ref docs

- dominfo.txt -> basic domain related queries I used for testing
[ ADDED TO /doc]

Enables domains of array elements -> CREATE DOMAIN dom int4[3][2];

Uses a typbasetype column to describe the origin of the domain.

Copies data to attnotnull rather than processing in execMain().

Some documentation differences from earlier.

If this is approved, I'll start working on pg_dump, and a \dD <domain>
option in psql, and regression tests.  I don't really feel like doing
those until the system table structure settles for pg_type.


CHECKS when added, will also be copied to to the table attributes.  FK
Constraints (if I ever figure out how) will be done similarly.  Both
will lbe handled by MergeDomainAttributes() which is called shortly
before MergeAttributes().

Rod Taylor
parent 3d9f865e
-- Test Comment / Drop
create domain domaindroptest int4;
comment on domain domaindroptest is 'About to drop this..';
select * from pg_type where typname = 'domaindroptest';
drop domain domaindroptest restrict;
select * from pg_type where typname = 'domaindroptest';
-- 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;
-- Array Test
create domain domainint4arr int4[1];
create domain domaintextarr text[2][3];
create table arrtest
( testint4arr domainint4arr
, testtextarr domaintextarr
);
INSERT INTO arrtest values ('{2,2}', '{{"a","b"}{"c","d"}}');
INSERT INTO arrtest values ('{{2,2}{2,2}}', '{{"a","b"}}');
INSERT INTO arrtest values ('{2,2}', '{{"a","b"}{"c","d"}{"e"}}');
INSERT INTO arrtest values ('{2,2}', '{{"a"}{"c"}}');
INSERT INTO arrtest values (NULL, '{{"a","b"}{"c","d","e"}}');
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;
create domain ddef1 int4 DEFAULT 3;
create domain ddef2 numeric(8,6) DEFAULT '1234.123456789';
-- 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 table defaulttest
( col1 ddef1
, col2 ddef2
, col3 ddef3
, col4 ddef4
, col5 ddef1 NOT NULL DEFAULT NULL
, col6 ddef2 DEFAULT '88.1'
, col7 ddef4 DEFAULT 8000
);
insert into defaulttest default values;
insert into defaulttest default values;
insert into defaulttest default values;
select * from defaulttest;
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.31 2002/03/01 22:45:03 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.32 2002/03/06 20:34:43 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
off of. 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. Normally used only for domains.
</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.33 2002/03/01 22:45:07 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.34 2002/03/06 20:34:44 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.12 2001/12/27 21:36:57 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.13 2002/03/06 20:34:44 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 'Domains are like abstracted fields';
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.1 2002/03/06 20:34:44 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.1 2002/03/06 20:34:44 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.21 2002/03/01 22:45:04 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.22 2002/03/06 20:34:43 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.184 2002/03/06 06:09:25 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.185 2002/03/06 20:34:45 momjian Exp $
*
*
* INTERFACE ROUTINES
......@@ -698,10 +698,15 @@ AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid)
"oidin", /* receive procedure */
"oidout", /* send procedure */
NULL, /* array element type - irrelevant */
NULL, /* baseType Name -- typically for domiains */
NULL, /* default type value - none */
NULL, /* default type binary representation */
true, /* passed by value */
'i', /* default alignment - same as for OID */
'p'); /* Not TOASTable */
'p', /* Not TOASTable */
-1, /* Type mod length */
0, /* array dimensions for typBaseType */
false); /* Type NOT NULL */
}
/* --------------------------------
......@@ -1584,6 +1589,10 @@ AddRelationRawConstraints(Relation rel,
int numchecks;
List *listptr;
/* Probably shouldn't be null by default */
Node *expr = NULL;
/*
* Get info about existing constraints.
*/
......@@ -1614,68 +1623,13 @@ AddRelationRawConstraints(Relation rel,
foreach(listptr, rawColDefaults)
{
RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);
Node *expr;
Oid type_id;
Assert(colDef->raw_default != NULL);
/*
* Transform raw parsetree to executable expression.
*/
expr = transformExpr(pstate, colDef->raw_default, EXPR_COLUMN_FIRST);
/*
* Make sure default expr does not refer to any vars.
*/
if (contain_var_clause(expr))
elog(ERROR, "cannot use column references in DEFAULT clause");
/*
* No subplans or aggregates, either...
*/
if (contain_subplans(expr))
elog(ERROR, "cannot use subselects in DEFAULT clause");
if (contain_agg_clause(expr))
elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
/*
* Check that it will be possible to coerce the expression to the
* column's type. We store the expression without coercion,
* however, to avoid premature coercion in cases like
*
* CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
*
* NB: this should match the code in optimizer/prep/preptlist.c that
* will actually do the coercion, to ensure we don't accept an
* unusable default expression.
*/
type_id = exprType(expr);
if (type_id != InvalidOid)
{
Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
if (type_id != atp->atttypid)
{
if (CoerceTargetExpr(NULL, expr, type_id,
atp->atttypid, atp->atttypmod) == NULL)
elog(ERROR, "Column \"%s\" is of type %s"
" but default expression is of type %s"
"\n\tYou will need to rewrite or cast the expression",
NameStr(atp->attname),
format_type_be(atp->atttypid),
format_type_be(type_id));
}
}
Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];
/*
* Might as well try to reduce any constant expressions.
*/
expr = eval_const_expressions(expr);
/*
* Must fix opids, in case any operators remain...
*/
fix_opids(expr);
expr = cookDefault(pstate, colDef->raw_default
, atp->atttypid, atp->atttypmod
, NameStr(atp->attname));
/*
* OK, store it.
......@@ -1892,6 +1846,88 @@ SetRelationNumChecks(Relation rel, int numchecks)
heap_close(relrel, RowExclusiveLock);
}
/*
* Take a raw default and convert it to a cooked format ready for
* storage.
*
* Parse state, attypid, attypmod and attname are required for
* CoerceTargetExpr() and more importantly transformExpr().
*/
Node *
cookDefault(ParseState *pstate
, Node *raw_default
, Oid atttypid
, int32 atttypmod
, char *attname) {
Oid type_id;
Node *expr;
Assert(raw_default != NULL);
/*
* Transform raw parsetree to executable expression.
*/
expr = transformExpr(pstate, raw_default, EXPR_COLUMN_FIRST);
/*
* Make sure default expr does not refer to any vars.
*/
if (contain_var_clause(expr))
elog(ERROR, "cannot use column references in DEFAULT clause");
/*
* No subplans or aggregates, either...
*/
if (contain_subplans(expr))
elog(ERROR, "cannot use subselects in DEFAULT clause");
if (contain_agg_clause(expr))
elog(ERROR, "cannot use aggregate functions in DEFAULT clause");
/*
* Check that it will be possible to coerce the expression to the
* column's type. We store the expression without coercion,
* however, to avoid premature coercion in cases like
*
* CREATE TABLE tbl (fld datetime DEFAULT 'now'::text);
*
* NB: this should match the code in optimizer/prep/preptlist.c that
* will actually do the coercion, to ensure we don't accept an
* unusable default expression.
*/
type_id = exprType(expr);
if (type_id != InvalidOid && atttypid != InvalidOid) {
if (type_id != atttypid) {
/* Try coercing to the base type of the domain if available */
if (CoerceTargetExpr(pstate, expr, type_id,
getBaseType(atttypid),
atttypmod) == NULL) {
elog(ERROR, "Column \"%s\" is of type %s"
" but default expression is of type %s"
"\n\tYou will need to rewrite or cast the expression",
attname,
format_type_be(atttypid),
format_type_be(type_id));
}
}
}
/*
* Might as well try to reduce any constant expressions.
*/
expr = eval_const_expressions(expr);
/*
* Must fix opids, in case any operators remain...
*/
fix_opids(expr);
return(expr);
}
static void
RemoveAttrDefaults(Relation rel)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.65 2001/10/25 05:49:23 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.66 2002/03/06 20:34:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -178,8 +178,13 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
values[i++] = CharGetDatum('i'); /* 15 */
values[i++] = CharGetDatum('p'); /* 16 */
values[i++] = BoolGetDatum(false); /* 17 */
values[i++] = Int32GetDatum(-1); /* 18 */
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(typeName)); /* 17 */
CStringGetDatum(typeName)); /* 19 */
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(typeName)); /* 20 */
/*
* create a new type tuple with FormHeapTuple
......@@ -264,7 +269,7 @@ TypeShellMake(char *typeName)
Oid
TypeCreate(char *typeName,
Oid assignedTypeOid,
Oid relationOid, /* only for 'c'atalog typeTypes */
Oid relationOid, /* only for 'c'atalog typeTypes */
int16 internalSize,
int16 externalSize,
char typeType,
......@@ -274,10 +279,15 @@ TypeCreate(char *typeName,
char *receiveProcedure,
char *sendProcedure,
char *elementTypeName,
char *defaultTypeValue, /* internal rep */
char *baseTypeName,
char *defaultTypeValue, /* human readable rep */
char *defaultTypeBin, /* cooked rep */
bool passedByValue,
char alignment,
char storage)
char storage,
int32 typeMod,
int32 typNDims, /* Array dimensions for baseTypeName */
bool typeNotNull) /* binary default representation (cooked) */
{
int i,
j;
......@@ -285,6 +295,7 @@ TypeCreate(char *typeName,
HeapScanDesc pg_type_scan;
Oid typeObjectId;
Oid elementObjectId = InvalidOid;
Oid baseObjectId = InvalidOid;
HeapTuple tup;
char nulls[Natts_pg_type];
char replaces[Natts_pg_type];
......@@ -317,6 +328,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 +410,7 @@ TypeCreate(char *typeName,
* signature is 0,OIDOID,INT4OID. The output procedures may
* take 2 args (data value, element OID).
*/
if (OidIsValid(elementObjectId))
if (OidIsValid(elementObjectId) || OidIsValid(baseObjectId))
{
int nargs;
......@@ -411,6 +433,7 @@ TypeCreate(char *typeName,
PointerGetDatum(argList),
0);
}
if (!OidIsValid(procOid))
func_error("TypeCreate", procname, 1, argList, NULL);
}
......@@ -428,6 +451,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 +487,7 @@ TypeCreate(char *typeName,
CStringGetDatum(defaultTypeValue));
else
nulls[i] = 'n';
i++; /* 17 */
i++; /* 22 */
/*
* open pg_type and begin a scan for the type name.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.83 2002/03/06 06:09:31 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.84 2002/03/06 20:34:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -39,7 +39,7 @@ static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
static List *MergeDomainAttributes(List *schema);
/* ----------------------------------------------------------------
* DefineRelation
......@@ -69,6 +69,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
*/
StrNCpy(relname, stmt->relname, NAMEDATALEN);
/*
* Merge domain attributes into the known columns before inheritance
* applies it's changes otherwise we risk adding double constraints
* to a domain thats inherited.
*/
schema = MergeDomainAttributes(schema);
/*
* Look up inheritance ancestors and generate relation schema,
* including inherited attributes.
......@@ -237,6 +244,88 @@ TruncateRelation(char *name)
heap_truncate(name);
}
/*
* MergeDomainAttributes
* Returns a new schema with the constraints, types, and other
* attributes of the domain resolved.
*
* Defaults are processed at execution time by taking the default of
* the type (domain) if it is null. This does not need to be merged
* here.
*/
static List *
MergeDomainAttributes(List *schema)
{
List *entry;
/*
* Loop through the table elements supplied. These should
* never include inherited domains else they'll be
* double (or more) processed.
*/
foreach(entry, schema)
{
ColumnDef *coldef = lfirst(entry);
HeapTuple tuple;
Form_pg_type typeTup;
tuple = SearchSysCache(TYPENAME,
CStringGetDatum(coldef->typename->name),
0,0,0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "MergeDomainAttributes: Type %s does not exist",
coldef->typename->name);
typeTup = (Form_pg_type) GETSTRUCT(tuple);
if (typeTup->typtype == 'd') {
/*
* This is a domain, lets force the properties of the domain on to
* the new column.
*/
/* Enforce the typmod value */
coldef->typename->typmod = typeTup->typmod;
/* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
coldef->is_not_null |= typeTup->typnotnull;
/* Enforce the element type in the event the domain is an array
*
* BUG: How do we fill out arrayBounds and attrname from typelem and typNDimms?
*/
}
ReleaseSysCache(tuple);
//typedef struct TypeName
//{
//NodeTag type;
//char *name; /* name of the type */
//bool timezone; /* timezone specified? */
//bool setof; /* is a set? */
//int32 typmod; /* type modifier */
//List *arrayBounds; /* array bounds */
//char *attrname; /* field name when using %TYPE */
//} TypeName;
// ColumnDef
// NodeTag type;
// char *colname; /* name of column */
// TypeName *typename; /* type of column */
// bool is_not_null; /* NOT NULL constraint specified? */
// Node *raw_default; /* default value (untransformed parse
// * tree) */
// char *cooked_default; /* nodeToString representation */
// List *constraints; /* other constraints on column */
}
return schema;
}
/*----------
* MergeAttributes
* Returns new schema given initial schema and superclasses.
......
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.66 2002/03/06 06:09:35 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.67 2002/03/06 20:34:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -22,6 +22,7 @@
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse.h"
#include "parser/parse_agg.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
......@@ -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.165 2002/03/01 22:45:11 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.166 2002/03/06 20:34:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -2227,6 +2227,19 @@ _copyLoadStmt(LoadStmt *from)
return newnode;
}
static CreateDomainStmt *
_copyCreateDomainStmt(CreateDomainStmt *from)
{
CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
if (from->domainname)
newnode->domainname = pstrdup(from->domainname);
if (from->typename)
newnode->typename = from->typename;
return newnode;
}
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
......
......@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.113 2002/03/06 06:09:49 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.114 2002/03/06 20:34:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1095,6 +1095,17 @@ _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;
return true;
}
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
......@@ -2011,6 +2022,9 @@ equal(void *a, void *b)
case T_LoadStmt:
retval = _equalLoadStmt(a, b);
break;
case T_CreateDomainStmt:
retval = _equalCreateDomainStmt(a, b);
break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.46 2001/11/05 17:46:26 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.47 2002/03/06 20:34:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -355,7 +355,6 @@ build_column_default(Relation rel, int attrno)
Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];
Oid atttype = att_tup->atttypid;
int32 atttypmod = att_tup->atttypmod;
bool hasdefault;
Datum typedefault;
int16 typlen;
bool typbyval;
......@@ -392,7 +391,7 @@ build_column_default(Relation rel, int attrno)
if (type_id != atttype)
{
expr = CoerceTargetExpr(NULL, expr, type_id,
atttype, atttypmod);
getBaseType(atttype), atttypmod);
/*
* This really shouldn't fail; should have checked the
......@@ -430,41 +429,53 @@ build_column_default(Relation rel, int attrno)
* element type is, and the element type's default is irrelevant
* too.
*/
hasdefault = false;
typedefault = (Datum) 0;
typlen = sizeof(Oid);
typbyval = true;
expr = (Node *) makeConst(atttype,
typlen,
(Datum) 0,
true,
typbyval,
false, /* not a set */
false);
}
else
{
#ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(att_tup))
{
hasdefault = false;
typedefault = (Datum) 0;
expr = (Node *) makeConst(atttype,
typlen,
(Datum) 0,
true,
typbyval,
false, /* not a set */
false);
}
else
#endif /* _DROP_COLUMN_HACK__ */
hasdefault = get_typdefault(atttype, &typedefault);
expr = get_typdefault(atttype, atttypmod);
if (expr == NULL) {
expr = (Node *) makeConst(atttype,
typlen,
(Datum) 0,
true,
typbyval,
false, /* not a set */
false);
}
get_typlenbyval(atttype, &typlen, &typbyval);
}
expr = (Node *) makeConst(atttype,
typlen,
typedefault,
!hasdefault,
typbyval,
false, /* not a set */
false);
/*
* If the column is a fixed-length type, it may need a length coercion
* as well as a type coercion. But NULLs don't need that.
* as well as a type coercion, as well as direction to the final type.
*/
if (hasdefault)
expr = coerce_type_typmod(NULL, expr,
atttype, atttypmod);
expr = coerce_type_typmod(NULL, expr,
atttype, atttypmod);
return expr;
}
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.285 2002/03/06 06:09:53 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.286 2002/03/06 20:34:49 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -135,7 +135,8 @@ static void doNegateFloat(Value *v);
ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
CopyStmt, CreateAsStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
CreateUserStmt, CreateDomainStmt, CreatedbStmt, CursorStmt,
DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
......@@ -289,6 +290,8 @@ static void doNegateFloat(Value *v);
%type <list> constraints_set_namelist
%type <boolean> constraints_set_mode
%type <boolean> opt_as
/*
* If you make any token changes, remember to:
* - use "yacc -d" and update parse.h
......@@ -343,7 +346,7 @@ static void doNegateFloat(Value *v);
WITHOUT
/* Keywords (in SQL92 non-reserved words) */
%token COMMITTED, SERIALIZABLE, TYPE_P
%token COMMITTED, SERIALIZABLE, TYPE_P, DOMAIN_P
/* Keywords for Postgres support (not in SQL92 reserved words)
*
......@@ -446,6 +449,7 @@ stmt : AlterDatabaseSetStmt
| CopyStmt
| CreateStmt
| CreateAsStmt
| CreateDomainStmt
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
......@@ -776,7 +780,10 @@ DropSchemaStmt: DROP SCHEMA UserId
n->dbname = $3;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
......@@ -1461,7 +1468,10 @@ ColConstraintElem:
n->name = NULL;
if (exprIsNullConstant($2))
{
/* DEFAULT NULL should be reported as empty expr */
/*
* DEFAULT NULL should be reported as empty expr
* Required for NOT NULL Domain overrides
*/
n->raw_expr = NULL;
}
else
......@@ -2043,7 +2053,16 @@ def_list: def_elem { $$ = makeList1($1); }
| def_list ',' def_elem { $$ = lappend($1, $3); }
;
def_elem: ColLabel '=' def_arg
def_elem: DEFAULT '=' b_expr
{
$$ = makeNode(DefElem);
$$->defname = "default";
if (exprIsNullConstant($3))
$$->arg = (Node *)NULL;
else
$$->arg = $3;
}
| ColLabel '=' def_arg
{
$$ = makeNode(DefElem);
$$->defname = $1;
......@@ -2078,6 +2097,15 @@ DropStmt: DROP drop_type name_list
DropStmt *n = makeNode(DropStmt);
n->removeType = $2;
n->names = $3;
n->behavior = RESTRICT; /* Restricted by default */
$$ = (Node *)n;
}
| DROP DOMAIN_P name_list drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->removeType = DROP_DOMAIN_P;
n->names = $3;
n->behavior = $4;
$$ = (Node *)n;
}
;
......@@ -2110,7 +2138,7 @@ TruncateStmt: TRUNCATE opt_table relation_name
* The COMMENT ON statement can take different forms based upon the type of
* the object associated with the comment. The form of the statement is:
*
* COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
* COMMENT ON [ [ DATABASE | DOMAIN | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
* <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
* <funcname> (arg1, arg2, ...) | OPERATOR <op>
* (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
......@@ -2196,6 +2224,7 @@ comment_type: DATABASE { $$ = DATABASE; }
| RULE { $$ = RULE; }
| SEQUENCE { $$ = SEQUENCE; }
| TABLE { $$ = TABLE; }
| DOMAIN_P { $$ = TYPE_P; }
| TYPE_P { $$ = TYPE_P; }
| VIEW { $$ = VIEW; }
;
......@@ -3222,6 +3251,30 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
}
;
/*****************************************************************************
*
* Manipulate a domain
*
*
*****************************************************************************/
CreateDomainStmt: CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
{
CreateDomainStmt *n = makeNode(CreateDomainStmt);
n->domainname = $3;
n->typename = $5;
n->constraints = $6;
if ($7 != NULL)
elog(NOTICE,"CREATE DOMAIN / COLLATE %s not yet "
"implemented; clause ignored", $7);
$$ = (Node *)n;
}
;
opt_as: AS {$$ = TRUE; }
| /* EMPTY */ {$$ = FALSE; }
;
/*****************************************************************************
*
......@@ -5879,6 +5932,7 @@ unreserved_keyword:
| DEFERRED { $$ = "deferred"; }
| DELETE { $$ = "delete"; }
| DELIMITERS { $$ = "delimiters"; }
| DOMAIN_P { $$ = "domain"; }
| DOUBLE { $$ = "double"; }
| DROP { $$ = "drop"; }
| EACH { $$ = "each"; }
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.101 2002/03/05 05:33:15 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.102 2002/03/06 20:34:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -97,6 +97,7 @@ static ScanKeyword ScanKeywords[] = {
{"desc", DESC},
{"distinct", DISTINCT},
{"do", DO},
{"domain", DOMAIN_P},
{"double", DOUBLE},
{"drop", DROP},
{"each", EACH},
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.64 2001/10/25 05:49:39 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.65 2002/03/06 20:34:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -38,6 +38,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
{
Node *result;
if (targetTypeId == inputTypeId ||
targetTypeId == InvalidOid ||
node == NULL)
......@@ -605,3 +606,32 @@ PreferredType(CATEGORY category, Oid type)
}
return result;
} /* PreferredType() */
/*
* If the targetTypeId is a domain, we really want to coerce
* the tuple to the domain type -- not the domain itself
*/
Oid
getBaseType(Oid inType)
{
HeapTuple tup;
Form_pg_type typTup;
tup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(inType),
0, 0, 0);
typTup = ((Form_pg_type) GETSTRUCT(tup));
/*
* Assume that typbasetype exists and is a base type, where inType
* was a domain
*/
if (typTup->typtype == 'd')
inType = typTup->typbasetype;
ReleaseSysCache(tup);
return inType;
}
\ No newline at end of file
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.105 2001/11/12 20:05:24 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.106 2002/03/06 20:34:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1027,7 +1027,8 @@ parser_typecast_expression(ParseState *pstate,
if (inputType != targetType)
{
expr = CoerceTargetExpr(pstate, expr, inputType,
targetType, typename->typmod);
getBaseType(targetType),
typename->typmod);
if (expr == NULL)
elog(ERROR, "Cannot cast type '%s' to '%s'",
format_type_be(inputType),
......@@ -1039,7 +1040,7 @@ parser_typecast_expression(ParseState *pstate,
* as well as a type coercion.
*/
expr = coerce_type_typmod(pstate, expr,
targetType, typename->typmod);
getBaseType(targetType), typename->typmod);
return expr;
}
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.129 2002/03/05 05:33:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.130 2002/03/06 20:34:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -282,6 +282,11 @@ ProcessUtility(Node *parsetree,
/* RemoveType does its own permissions checks */
RemoveType(relname);
break;
case DROP_DOMAIN_P:
/* RemoveDomain does its own permissions checks */
RemoveDomain(relname, stmt->behavior);
break;
}
/*
......@@ -742,6 +747,16 @@ ProcessUtility(Node *parsetree,
DropProceduralLanguage((DropPLangStmt *) parsetree);
break;
/*
* ******************************** DOMAIN statements ****
*
*/
case T_CreateDomainStmt:
set_ps_display(commandTag = "CREATE DOMAIN");
DefineDomain((CreateDomainStmt *) parsetree);
break;
/*
* ******************************** USER statements ****
*
......
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.24 2002/03/02 21:39:32 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.25 2002/03/06 20:34:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -126,6 +126,7 @@ format_type_internal(Oid type_oid, int32 typemod,
bool is_array;
char *name;
char *buf;
char typtype;
if (type_oid == InvalidOid && allow_invalid)
return pstrdup("-");
......@@ -144,6 +145,31 @@ format_type_internal(Oid type_oid, int32 typemod,
array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype;
/*
* Domains look alot like arrays, so lets process them first, and return
* back to avoid the array and 'standard' formatting procedures that are
* use for base types.
*/
if (typtype == 'd') {
name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
/*
* Double-quote the name if it's not a standard identifier.
* Note this is *necessary* for ruleutils.c's use.
*/
if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
|| isdigit((unsigned char) name[0]))
buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
else
buf = pstrdup(name);
ReleaseSysCache(tuple);
return buf;
}
if (array_base_type != InvalidOid && typlen < 0)
{
/* Switch our attention to the array element type */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.60 2002/03/01 04:09:26 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.61 2002/03/06 20:34:54 momjian Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
......@@ -23,6 +23,7 @@
#include "catalog/pg_shadow.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
......@@ -822,16 +823,17 @@ get_typstorage(Oid typid)
* Returns FALSE if there is no default (effectively, default is NULL).
* The result points to palloc'd storage for pass-by-reference types.
*/
bool
get_typdefault(Oid typid, Datum *defaultValue)
Node *
get_typdefault(Oid typid, int32 atttypmod)
{
HeapTuple typeTuple;
Form_pg_type type;
Oid typinput,
typelem;
Datum textDefaultVal;
Oid typinput;
Oid typbasetype;
char typtype;
Datum datum;
bool isNull;
char *strDefaultVal;
Node *expr;
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
......@@ -843,38 +845,41 @@ get_typdefault(Oid typid, Datum *defaultValue)
type = (Form_pg_type) GETSTRUCT(typeTuple);
typinput = type->typinput;
typelem = type->typelem;
typbasetype = type->typbasetype;
typtype = type->typtype;
/*
* typdefault is potentially null, so don't try to access it as a
* typdefaultbin is potentially null, so don't try to access it as a
* struct field. Must do it the hard way with SysCacheGetAttr.
*/
textDefaultVal = SysCacheGetAttr(TYPEOID,
typeTuple,
Anum_pg_type_typdefault,
&isNull);
datum = SysCacheGetAttr(TYPEOID,
typeTuple,
Anum_pg_type_typdefaultbin,
&isNull);
ReleaseSysCache(typeTuple);
if (isNull)
{
ReleaseSysCache(typeTuple);
*defaultValue = (Datum) 0;
return false;
}
return (Node *) NULL;
/* Convert text datum to C string */
strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
textDefaultVal));
/* Convert Datum to a Node */
expr = stringToNode(DatumGetCString(
DirectFunctionCall1(textout, datum)));
/* Convert C string to a value of the given type */
*defaultValue = OidFunctionCall3(typinput,
CStringGetDatum(strDefaultVal),
ObjectIdGetDatum(typelem),
Int32GetDatum(-1));
pfree(strDefaultVal);
ReleaseSysCache(typeTuple);
/*
* Ensure we goto the basetype before the domain type.
*
* Prevents scenarios like the below from failing:
* CREATE DOMAIN dom text DEFAULT random();
*
*/
if (typbasetype != InvalidOid) {
expr = coerce_type(NULL, expr, typid,
typbasetype, atttypmod);
}
return true;
return expr;
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.154 2002/03/06 06:10:21 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.155 2002/03/06 20:34:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -512,8 +512,12 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
(char *) attp,
ATTRIBUTE_TUPLE_SIZE);
/* Update constraint/default info */
if (attp->attnotnull)
/*
* Update constraint/default info
*/
if (attp->attnotnull)
constr->has_not_null = true;
if (attp->atthasdef)
......
......@@ -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.41 2001/11/05 17:46:31 momjian Exp $
* $Id: heap.h,v 1.42 2002/03/06 20:34:55 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.81 2002/03/01 22:45:16 petere Exp $
* $Id: pg_attribute.h,v 1.82 2002/03/06 20:34:56 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.59 2002/03/01 22:45:17 petere Exp $
* $Id: pg_class.h,v 1.60 2002/03/06 20:34:56 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.28 2001/11/05 17:46:33 momjian Exp $
* $Id: defrem.h,v 1.29 2002/03/06 20:34:59 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.98 2002/03/01 22:45:17 petere Exp $
* $Id: nodes.h,v 1.99 2002/03/06 20:35:00 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.156 2002/03/05 05:33:31 momjian Exp $
* $Id: parsenodes.h,v 1.157 2002/03/06 20:35:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -468,12 +468,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;
/* ----------------------
......@@ -682,6 +684,7 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
/* ----------------------
* Createdb Statement
* ----------------------
......@@ -1280,6 +1283,22 @@ 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
****************************************************************************/
......
......@@ -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.37 2001/11/05 17:46:34 momjian Exp $
* $Id: parse_coerce.h,v 1.38 2002/03/06 20:35:01 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.40 2002/03/01 04:09:28 tgl Exp $
* $Id: lsyscache.h,v 1.41 2002/03/06 20:35:02 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,
......
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