Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
f58eac82
Commit
f58eac82
authored
Oct 13, 2006
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code and docs review for ALTER TABLE INHERIT/NO INHERIT patch.
parent
e1fdd226
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
290 additions
and
303 deletions
+290
-303
doc/src/sgml/ddl.sgml
doc/src/sgml/ddl.sgml
+78
-102
doc/src/sgml/ref/alter_table.sgml
doc/src/sgml/ref/alter_table.sgml
+14
-17
src/backend/commands/tablecmds.c
src/backend/commands/tablecmds.c
+182
-165
src/backend/nodes/copyfuncs.c
src/backend/nodes/copyfuncs.c
+1
-2
src/backend/nodes/equalfuncs.c
src/backend/nodes/equalfuncs.c
+1
-2
src/backend/parser/gram.y
src/backend/parser/gram.y
+7
-7
src/include/nodes/parsenodes.h
src/include/nodes/parsenodes.h
+4
-5
src/test/regress/expected/alter_table.out
src/test/regress/expected/alter_table.out
+3
-3
No files found.
doc/src/sgml/ddl.sgml
View file @
f58eac82
<
!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.6
3 2006/09/20 21:30:20
tgl Exp $ -->
<
!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.6
4 2006/10/13 21:43:17
tgl Exp $ -->
<
chapter
id
=
"ddl"
>
<
title
>
Data
Definition
</
title
>
...
...
@@ -2061,53 +2061,54 @@ VALUES ('New York', NULL, NULL, 'NY');
</para>
<para>
Table inheritance
can be defined using the <xref linkend="sql-createtable"
endterm="sql-createtable-title"> statement using
the
<
command>INHERITS</command> keyword. However the related statement
<command>CREATE TABLE AS</command> does not allow inheritance to be
specified.
Table inheritance
is typically established when the child table is
created, using the <literal>INHERITS</> clause of
the
<
xref linkend="sql-createtable" endterm="sql-createtable-title">
statement. However the related statement <command>CREATE TABLE AS</command>
does not allow inheritance to be
specified.
</para>
<para>
Alternatively
a table which is already defined in a compatible way can have
a new parent added with <xref linkend="sql-altertable"
endterm="sql-altertable-title"> using the <command>INHERIT</command>
subform.
To do this the new child table must already include columns with
the same name
and type
as the columns of the parent. It must also include
check constraints with the same name
and check expression
as those of the
Alternatively
, a table which is already defined in a compatible way can
have a new parent relationship added, using the <literal>INHERIT</literal>
variant of <xref linkend="sql-altertable" endterm="sql-altertable-title">.
To do this the new child table must already include columns with
the same name
s and types
as the columns of the parent. It must also include
check constraints with the same name
s and check expressions
as those of the
parent. Similarly an inheritance link can be removed from a child using the
<command>ALTER TABLE</command> using the <command>NO INHERIT</command>
subform.
<literal>NO INHERIT</literal> variant of <command>ALTER TABLE</>.
Dynamically adding and removing inheritance links like this can be useful
when the inheritance relationship is being used for table
partitioning (see <xref linkend="ddl-partitioning">).
</para>
<para>
One convenient way to create a compatible table t
o be a new child
is specify the <command>LIKE</command
> clause in <command>CREATE
One convenient way to create a compatible table t
hat will later be made
a new child is to use the <literal>LIKE</literal
> clause in <command>CREATE
TABLE</command>. This creates a new table with the same columns as
the source table. If there are any <command>CHECK</command>
constraints defined on the parent table, the <command>INCLUDING
CONSTRAINTS</command> option to <command>LIKE</command> may be
useful, as the new child must have constraints matching the parent
to be considered compatible. Alternatively a compatible table can
be created by first creating a new child using <command>CREATE
TABLE</command> then removing the inheritance link with
<command>ALTER TABLE</command>.
the source table. If there are any <literal>CHECK</literal>
constraints defined on the source table, the <literal>INCLUDING
CONSTRAINTS</literal> option to <literal>LIKE</literal> should be
specified, as the new child must have constraints matching the parent
to be considered compatible.
</para>
<para>
A parent table cannot be dropped while any
of its children remain. If you wish to remove a table and all of its
A parent table cannot be dropped while any of its children remain. Neither
can columns of child tables be dropped or altered if they are inherited
from any parent tables. If you wish to remove a table and all of its
descendants, one easy way is to drop the parent table with the
<literal>CASCADE</literal> option. Neither can columns of child tables be
dropped or altered if they are inherited from any parent tables.
<literal>CASCADE</literal> option.
</para>
<para>
<xref linkend="sql-altertable" endterm="sql-altertable-title"> will
propagate any changes in column data definitions and check constraints down
the inheritance hierarchy. <command>ALTER TABLE</command> follows the same
rules for duplicate column merging and rejection that apply during
<command>CREATE TABLE</command>.
propagate any changes in column data definitions and check
constraints down the inheritance hierarchy. Again, dropping
columns or constraints on parent tables is only possible when using
the <literal>CASCADE</literal> option. <command>ALTER
TABLE</command> follows the same rules for duplicate column merging
and rejection that apply during <command>CREATE TABLE</command>.
</para>
<sect2 id="ddl-inherit-caveats">
...
...
@@ -2162,16 +2163,6 @@ VALUES ('New York', NULL, NULL, 'NY');
not
capital
names
.
There
is
no
good
workaround
for
this
case
.
</
para
>
</
listitem
>
<
listitem
>
<
para
>
If
a
table
is
ever
removed
from
the
inheritance
structure
using
<
command
>
ALTER
TABLE
</
command
>
then
all
its
columns
will
be
marked
as
being
locally
defined
.
This
means
<
command
>
DROP
COLUMN
</
command
>
on
the
parent
table
will
never
cascade
to
drop
those
columns
on
the
child
table
.
They
must
be
dropped
manually
.
</
para
>
</
listitem
>
</
itemizedlist
>
These
deficiencies
will
probably
be
fixed
in
some
future
release
,
...
...
@@ -2222,37 +2213,31 @@ VALUES ('New York', NULL, NULL, 'NY');
<
itemizedlist
>
<
listitem
>
<
para
>
Query
performance
can
be
improved
when
partition
constraints
can
be
combined
with
local
indexes
to
reduce
the
number
of
records
that
need
to
be
accessed
for
a
query
.
Whereas
the
alternative
,
adding
those
columns
to
every
index
,
increases
space
usage
which
can
erase
any
performance
gain
.
</
para
>
<
para
>
When
most
of
the
heavily
accessed
area
of
the
table
is
in
a
single
partition
or
a
small
number
of
partitions
.
That
partition
and
its
indexes
are
more
likely
to
fit
within
memory
than
the
index
of
the
entire
table
.
Query
performance
can
be
improved
dramatically
in
certain
situations
,
particularly
when
most
of
the
heavily
accessed
rows
of
the
table
are
in
a
single
partition
or
a
small
number
of
partitions
.
The
partitioning
substitutes
for
leading
columns
of
indexes
,
reducing
index
size
and
making
it
more
likely
that
the
heavily
-
used
parts
of
the
indexes
fit
in
memory
.
</
para
>
</
listitem
>
<
listitem
>
<
para
>
When
queries
or
updates
access
a
large
percentage
of
a
a
single
partition
performance
can
be
improved
dramatically
by
taking
advantage
of
sequential
disk
access
of
a
single
partition
instead
of
using
an
index
and
random
access
reads
across
the
whole
table
.
partition
,
performance
can
be
improved
by
taking
advantage
of
sequential
scan
of
that
partition
instead
of
using
an
index
and
random
access
reads
scattered
across
the
whole
table
.
</
para
>
</
listitem
>
<
listitem
>
<
para
>
Bulk
loads
and
deletes
may
be
accomplished
by
simply
removing
or
add
ing
one
of
the
partitions
.
<
command
>
ALTER
TABLE
</>
is
far
faster
than
a
bulk
and
takes
the
same
amount
of
time
regardless
of
the
amount
of
data
being
added
or
removed
.
It
also
entirely
avoids
the
<
command
>
VACUUM
</
command
>
overhead
caused
by
a
bulk
<
command
>
delete
</>.
Bulk
loads
and
deletes
may
be
accomplished
by
adding
or
remov
ing
partitions
,
if
that
requirement
is
planned
into
the
partitioning
design
.
<
command
>
ALTER
TABLE
</>
is
far
faster
than
a
bulk
operation
.
It
also
entirely
avoids
the
<
command
>
VACUUM
</
command
>
overhead
caused
by
a
bulk
<
command
>
DELETE
</>.
</
para
>
</
listitem
>
...
...
@@ -2577,6 +2562,25 @@ DO INSTEAD
creating a new partition each month, so it may be wise to write a
script that generates the required DDL automatically.
</para>
<para>
Partitioning can also be arranged using a <literal>UNION ALL</literal>
view:
<programlisting>
CREATE VIEW measurement AS
SELECT * FROM measurement_y2004m02
UNION ALL SELECT * FROM measurement_y2004m03
...
UNION ALL SELECT * FROM measurement_y2005m11
UNION ALL SELECT * FROM measurement_y2005m12
UNION ALL SELECT * FROM measurement_y2006m01;
</programlisting>
However, the need to
recreate the view adds an extra step to adding and dropping
individual partitions of the dataset.
</para>
</sect2>
<sect2 id="ddl-partitioning-managing-partitions">
...
...
@@ -2589,15 +2593,15 @@ DO INSTEAD
add new partitions for new data. One of the most important
advantages of partitioning is precisely that it allows this
otherwise painful task to be executed nearly instantaneously by
manipulating the partition structure, rather than moving large
amounts of data around
physically
.
manipulating the partition structure, rather than
physically
moving large
amounts of data around.
</para>
<para>
The simplest option for removing old data is
to simply
drop the partition
The simplest option for removing old data is
simply to
drop the partition
that is no longer necessary:
<programlisting>
DROP TABLE measurement_y2003m
m
02;
DROP TABLE measurement_y2003m02;
</programlisting>
This can very quickly delete millions of records because it doesn'
t
have
to
individually
delete
every
record
.
...
...
@@ -2608,10 +2612,10 @@ DROP TABLE measurement_y2003mm02;
the
partitioned
table
but
retain
access
to
it
as
a
table
in
its
own
right
:
<
programlisting
>
ALTER
TABLE
measurement_y2003m
m
02
NO
INHERIT
measurement
;
ALTER
TABLE
measurement_y2003m02
NO
INHERIT
measurement
;
</
programlisting
>
This
allows
further
operations
to
be
performed
on
the
data
before
it
is
dropped
.
For
example
,
this
is
often
a
useful
time
to
backup
it
is
dropped
.
For
example
,
this
is
often
a
useful
time
to
back
up
the
data
using
<
command
>
COPY
</>,
<
application
>
pg_dump
</>,
or
similar
tools
.
It
can
also
be
a
useful
time
to
aggregate
data
into
smaller
formats
,
perform
other
data
manipulations
,
or
run
...
...
@@ -2635,10 +2639,12 @@ CREATE TABLE measurement_y2006m02 (
transformed
prior
to
it
appearing
in
the
partitioned
table
.
<
programlisting
>
CREATE
TABLE
measurement_y2006m02
(
LIKE
measurement
INCLUDING
DEFAULTS
INCLUDING
CONSTRAINTS
);
\
COPY
measurement_y2006m02
FROM
'measurement_y2006m02'
UPDATE
...
;
ALTER
TABLE
measurement_y2006m02
ADD
CONSTRAINT
y2006m02
CHECK
(
logdate
&
gt
;=
DATE
'2006-02-01'
AND
logdate
&
lt
;
DATE
'2006-03-01'
);
CREATE
TABLE
measurement_y2006m02
(
LIKE
measurement
INCLUDING
DEFAULTS
INCLUDING
CONSTRAINTS
);
ALTER
TABLE
measurement_y2006m02
ADD
CONSTRAINT
y2006m02
CHECK
(
logdate
&
gt
;=
DATE
'2006-02-01'
AND
logdate
&
lt
;
DATE
'2006-03-01'
);
\
copy
measurement_y2006m02
from
'measurement_y2006m02'
--
possibly
some
other
data
preparation
work
ALTER
TABLE
measurement_y2006m02
INHERIT
measurement
;
</
programlisting
>
</
para
>
...
...
@@ -2670,38 +2676,8 @@ ALTER TABLE measurement_y2006m02 INHERIT measurement;
using
a
set
of
rules
as
suggested
above
.)
</
para
>
</
listitem
>
<
listitem
>
<
para
>
When
using
the
<
literal
>
LIKE
</>
option
above
to
create
new
partitions
,
<
literal
>
CHECK
</>
constraints
are
not
copied
from
the
parent
.
If
there
are
any
<
literal
>
CHECK
</>
constraints
defined
for
the
parent
,
they
must
be
manually
created
in
new
partitions
before
<
command
>
ALTER
TABLE
</
command
>
will
allow
them
to
be
added
.
</
para
>
</
listitem
>
</
itemizedlist
>
</
para
>
<
para
>
Partitioning
can
also
be
arranged
using
a
<
literal
>
UNION
ALL
</
literal
>
view
:
<
programlisting
>
CREATE
VIEW
measurement
AS
SELECT
*
FROM
measurement_y2004m02
UNION
ALL
SELECT
*
FROM
measurement_y2004m03
...
UNION
ALL
SELECT
*
FROM
measurement_y2005m11
UNION
ALL
SELECT
*
FROM
measurement_y2005m12
UNION
ALL
SELECT
*
FROM
measurement_y2006m01
;
</
programlisting
>
However
,
the
need
to
recreate
the
view
adds
an
extra
step
to
adding
and
dropping
individual
partitions
of
the
dataset
.
</
para
>
</
sect2
>
<
sect2
id
=
"ddl-partitioning-constraint-exclusion"
>
...
...
doc/src/sgml/ref/alter_table.sgml
View file @
f58eac82
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.9
0 2006/09/16 00:30:16 momjian
Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.9
1 2006/10/13 21:43:18 tgl
Exp $
PostgreSQL documentation
-->
...
...
@@ -294,28 +294,22 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
<term><literal>INHERIT <replaceable class="PARAMETER">parent_table</replaceable></literal></term>
<listitem>
<para>
This form adds a new parent table to the table. This won't add new
columns to the child table, instead all columns of the parent table must
already exist in the child table. They must have matching data types,
This form adds the target table as a new child of the specified parent
table. Subsequently, queries against the parent will include records
of the target table. To be added as a child, the target table must
already contain all the same columns as the parent (it could have
additional columns, too). The columns must have matching data types,
and if they have <literal>NOT NULL</literal> constraints in the parent
then they must also have <literal>NOT NULL</literal> constraints in the
child.
</para>
<para>
There must also be matching table constraints for all
<literal>CHECK</literal>
table
constraints of the parent. Currently
There must also be matching
child-
table constraints for all
<literal>CHECK</literal> constraints of the parent. Currently
<literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>, and
<literal>FOREIGN KEY</literal> constraints are ignored however this may
change in the future.
</para>
<para>
The easiest way to create a suitable table is to create a table using
<literal>INHERITS</literal> and then remove it via <literal>NO
INHERIT</literal>. Alternatively create a table using
<literal>LIKE</literal> however note that <literal>LIKE</literal> does
not create the necessary constraints.
<literal>FOREIGN KEY</literal> constraints are not considered, but
this may change in the future.
</para>
</listitem>
</varlistentry>
...
...
@@ -324,7 +318,8 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
<term><literal>NO INHERIT <replaceable class="PARAMETER">parent_table</replaceable></literal></term>
<listitem>
<para>
This form removes a parent table from the list of parents of the table.
This form removes the target table from the list of children of the
specified parent table.
Queries against the parent table will no longer include records drawn
from the target table.
</para>
...
...
@@ -392,6 +387,8 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
You must own the table to use <command>ALTER TABLE</>.
To change the schema of a table, you must also have
<literal>CREATE</literal> privilege on the new schema.
To add the table as a new child of a parent table, you must own the
parent table as well.
To alter the owner, you must also be a direct or indirect member of the new
owning role, and that role must have <literal>CREATE</literal> privilege on
the table's schema. (These restrictions enforce that altering the owner
...
...
src/backend/commands/tablecmds.c
View file @
f58eac82
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.20
5 2006/10/11 16:42:5
8 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.20
6 2006/10/13 21:43:1
8 tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -168,7 +168,7 @@ static void add_nonduplicate_constraint(Constraint *cdef,
static
bool
change_varattnos_walker
(
Node
*
node
,
const
AttrNumber
*
newattno
);
static
void
StoreCatalogInheritance
(
Oid
relationId
,
List
*
supers
);
static
void
StoreCatalogInheritance1
(
Oid
relationId
,
Oid
parentOid
,
int16
seqNumber
,
Relation
catalog
Relation
);
int16
seqNumber
,
Relation
inh
Relation
);
static
int
findAttrByName
(
const
char
*
attributeName
,
List
*
schema
);
static
void
setRelhassubclassInRelation
(
Oid
relationId
,
bool
relhassubclass
);
static
void
AlterIndexNamespaces
(
Relation
classRel
,
Relation
rel
,
...
...
@@ -253,8 +253,8 @@ static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
static
void
ATExecSetRelOptions
(
Relation
rel
,
List
*
defList
,
bool
isReset
);
static
void
ATExecEnableDisableTrigger
(
Relation
rel
,
char
*
trigname
,
bool
enable
,
bool
skip_system
);
static
void
ATExecAddInherit
s
(
Relation
rel
,
RangeVar
*
parent
);
static
void
ATExecDropInherit
s
(
Relation
rel
,
RangeVar
*
parent
);
static
void
ATExecAddInherit
(
Relation
rel
,
RangeVar
*
parent
);
static
void
ATExecDropInherit
(
Relation
rel
,
RangeVar
*
parent
);
static
void
copy_relation_data
(
Relation
rel
,
SMgrRelation
dst
);
static
void
update_ri_trigger_args
(
Oid
relid
,
const
char
*
oldname
,
...
...
@@ -1272,25 +1272,34 @@ StoreCatalogInheritance(Oid relationId, List *supers)
seqNumber
=
1
;
foreach
(
entry
,
supers
)
{
StoreCatalogInheritance1
(
relationId
,
lfirst_oid
(
entry
),
seqNumber
,
relation
);
Oid
parentOid
=
lfirst_oid
(
entry
);
StoreCatalogInheritance1
(
relationId
,
parentOid
,
seqNumber
,
relation
);
seqNumber
++
;
}
heap_close
(
relation
,
RowExclusiveLock
);
}
/*
* Make catalog entries showing relationId as being an inheritance child
* of parentOid. inhRelation is the already-opened pg_inherits catalog.
*/
static
void
StoreCatalogInheritance1
(
Oid
relationId
,
Oid
parentOid
,
int16
seqNumber
,
Relation
r
elation
)
int16
seqNumber
,
Relation
inhR
elation
)
{
TupleDesc
desc
=
RelationGetDescr
(
inhRelation
);
Datum
datum
[
Natts_pg_inherits
];
char
nullarr
[
Natts_pg_inherits
];
ObjectAddress
childobject
,
parentobject
;
HeapTuple
tuple
;
TupleDesc
desc
=
RelationGetDescr
(
relation
);
datum
[
0
]
=
ObjectIdGetDatum
(
relationId
);
/* inhrel */
/*
* Make the pg_inherits entry
*/
datum
[
0
]
=
ObjectIdGetDatum
(
relationId
);
/* inhrelid */
datum
[
1
]
=
ObjectIdGetDatum
(
parentOid
);
/* inhparent */
datum
[
2
]
=
Int16GetDatum
(
seqNumber
);
/* inhseqno */
...
...
@@ -1300,9 +1309,9 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
tuple
=
heap_formtuple
(
desc
,
datum
,
nullarr
);
simple_heap_insert
(
r
elation
,
tuple
);
simple_heap_insert
(
inhR
elation
,
tuple
);
CatalogUpdateIndexes
(
r
elation
,
tuple
);
CatalogUpdateIndexes
(
inhR
elation
,
tuple
);
heap_freetuple
(
tuple
);
...
...
@@ -2150,8 +2159,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
case
AT_DisableTrig
:
/* DISABLE TRIGGER variants */
case
AT_DisableTrigAll
:
case
AT_DisableTrigUser
:
case
AT_AddInherit
s
:
case
AT_DropInherit
s
:
case
AT_AddInherit
:
/* INHERIT / NO INHERIT */
case
AT_DropInherit
:
ATSimplePermissions
(
rel
,
false
);
/* These commands never recurse */
/* No command-specific prep needed */
...
...
@@ -2335,11 +2344,11 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
case
AT_DisableTrigUser
:
/* DISABLE TRIGGER USER */
ATExecEnableDisableTrigger
(
rel
,
NULL
,
false
,
true
);
break
;
case
AT_
DropInherits
:
ATExec
DropInherits
(
rel
,
cmd
->
parent
);
case
AT_
AddInherit
:
ATExec
AddInherit
(
rel
,
(
RangeVar
*
)
cmd
->
def
);
break
;
case
AT_
AddInherits
:
ATExec
AddInherits
(
rel
,
cmd
->
parent
);
case
AT_
DropInherit
:
ATExec
DropInherit
(
rel
,
(
RangeVar
*
)
cmd
->
def
);
break
;
default:
/* oops */
elog
(
ERROR
,
"unrecognized alter table type: %d"
,
...
...
@@ -6087,46 +6096,32 @@ ATExecEnableDisableTrigger(Relation rel, char *trigname,
EnableDisableTrigger
(
rel
,
trigname
,
enable
,
skip_system
);
}
static
char
*
decompile_conbin
(
HeapTuple
contup
,
TupleDesc
tupdesc
)
{
Form_pg_constraint
con
;
bool
isnull
;
Datum
attr
;
Datum
expr
;
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
contup
);
attr
=
heap_getattr
(
contup
,
Anum_pg_constraint_conbin
,
tupdesc
,
&
isnull
);
if
(
isnull
)
elog
(
ERROR
,
"null conbin for constraint %u"
,
HeapTupleGetOid
(
contup
));
expr
=
DirectFunctionCall2
(
pg_get_expr
,
attr
,
ObjectIdGetDatum
(
con
->
conrelid
));
return
DatumGetCString
(
DirectFunctionCall1
(
textout
,
expr
));
}
/*
* ALTER TABLE INHERIT
*
* Add a parent to the child's parents. This verifies that all the columns and
* check constraints of the parent appear in the child and that they have the
* same data type and expressions.
* same data type
s
and expressions.
*/
static
void
ATExecAddInherit
s
(
Relation
child_rel
,
RangeVar
*
parent
)
ATExecAddInherit
(
Relation
child_rel
,
RangeVar
*
parent
)
{
Relation
parent_rel
,
catalogRelation
;
SysScanDesc
scan
;
ScanKeyData
key
;
HeapTuple
inheritsTuple
;
int
4
inhseqno
;
int
32
inhseqno
;
List
*
children
;
/*
* AccessShareLock on the parent is what's obtained during normal CREATE
* TABLE ... INHERITS ..., so should be enough here.
*/
parent_rel
=
heap_openrv
(
parent
,
AccessShareLock
);
/*
* Must be owner of both parent and child -- child
is taken care of
by
* Must be owner of both parent and child -- child
was checked
by
* ATSimplePermissions call in ATPrepCmd
*/
ATSimplePermissions
(
parent_rel
,
false
);
...
...
@@ -6137,19 +6132,15 @@ ATExecAddInherits(Relation child_rel, RangeVar *parent)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_WRONG_OBJECT_TYPE
),
errmsg
(
"cannot inherit from temporary relation
\"
%s
\"
"
,
parent
->
relname
)));
/* If parent has OIDs then all children must have OIDs */
if
(
parent_rel
->
rd_rel
->
relhasoids
&&
!
child_rel
->
rd_rel
->
relhasoids
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_WRONG_OBJECT_TYPE
),
errmsg
(
"table
\"
%s
\"
without OIDs cannot inherit from table
\"
%s
\"
with OIDs"
,
RelationGetRelationName
(
child_rel
),
parent
->
relname
)));
RelationGetRelationName
(
parent_rel
))));
/*
* Don't allow any duplicates in the list of parents. We scan through the
* list of parents in pg_inherit and keep track of the first open inhseqno
* slot found to use for the new parent.
* Check for duplicates in the list of parents, and determine the highest
* inhseqno already present; we'll use the next one for the new parent.
* (Note: get RowExclusiveLock because we will write pg_inherits below.)
*
* Note: we do not reject the case where the child already inherits from
* the parent indirectly; CREATE TABLE doesn't reject comparable cases.
*/
catalogRelation
=
heap_open
(
InheritsRelationId
,
RowExclusiveLock
);
ScanKeyInit
(
&
key
,
...
...
@@ -6169,37 +6160,57 @@ ATExecAddInherits(Relation child_rel, RangeVar *parent)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DUPLICATE_TABLE
),
errmsg
(
"inherited relation
\"
%s
\"
duplicated"
,
parent
->
relname
)));
if
(
inh
->
inhseqno
==
inhseqno
+
1
)
RelationGetRelationName
(
parent_rel
)
)));
if
(
inh
->
inhseqno
>
inhseqno
)
inhseqno
=
inh
->
inhseqno
;
}
systable_endscan
(
scan
);
heap_close
(
catalogRelation
,
RowExclusiveLock
);
/*
* If the new parent is found in our list of inheritors, we have a
* circular structure
* Prevent circularity by seeing if proposed parent inherits from child.
* (In particular, this disallows making a rel inherit from itself.)
*
* This is not completely bulletproof because of race conditions: in
* multi-level inheritance trees, someone else could concurrently
* be making another inheritance link that closes the loop but does
* not join either of the rels we have locked. Preventing that seems
* to require exclusive locks on the entire inheritance tree, which is
* a cure worse than the disease. find_all_inheritors() will cope with
* circularity anyway, so don't sweat it too much.
*/
children
=
find_all_inheritors
(
RelationGetRelid
(
child_rel
));
if
(
list_member_oid
(
children
,
RelationGetRelid
(
parent_rel
)))
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DUPLICATE_TABLE
),
errmsg
(
"circular inheritance
structure foun
d"
),
errmsg
(
"circular inheritance
not allowe
d"
),
errdetail
(
"
\"
%s
\"
is already a child of
\"
%s
\"
."
,
parent
->
relname
,
RelationGetRelationName
(
child_rel
))));
/* If parent has OIDs then child must have OIDs */
if
(
parent_rel
->
rd_rel
->
relhasoids
&&
!
child_rel
->
rd_rel
->
relhasoids
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_WRONG_OBJECT_TYPE
),
errmsg
(
"table
\"
%s
\"
without OIDs cannot inherit from table
\"
%s
\"
with OIDs"
,
RelationGetRelationName
(
child_rel
),
RelationGetRelationName
(
parent_rel
))));
/* Match up the columns and bump attinhcount and attislocal */
MergeAttributesIntoExisting
(
child_rel
,
parent_rel
);
/* Match up the constraints and make sure they're present in child */
MergeConstraintsIntoExisting
(
child_rel
,
parent_rel
);
catalogRelation
=
heap_open
(
InheritsRelationId
,
RowExclusiveLock
);
/*
* OK, it looks valid. Make the catalog entries that show inheritance.
*/
StoreCatalogInheritance1
(
RelationGetRelid
(
child_rel
),
RelationGetRelid
(
parent_rel
),
inhseqno
+
1
,
catalogRelation
);
inhseqno
+
1
,
catalogRelation
);
/* Now we're done with pg_inherits */
heap_close
(
catalogRelation
,
RowExclusiveLock
);
/* keep our lock on the parent relation until commit */
...
...
@@ -6207,26 +6218,53 @@ ATExecAddInherits(Relation child_rel, RangeVar *parent)
}
/*
* Check columns in child table match up with columns in parent
* Obtain the source-text form of the constraint expression for a check
* constraint, given its pg_constraint tuple
*/
static
char
*
decompile_conbin
(
HeapTuple
contup
,
TupleDesc
tupdesc
)
{
Form_pg_constraint
con
;
bool
isnull
;
Datum
attr
;
Datum
expr
;
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
contup
);
attr
=
heap_getattr
(
contup
,
Anum_pg_constraint_conbin
,
tupdesc
,
&
isnull
);
if
(
isnull
)
elog
(
ERROR
,
"null conbin for constraint %u"
,
HeapTupleGetOid
(
contup
));
expr
=
DirectFunctionCall2
(
pg_get_expr
,
attr
,
ObjectIdGetDatum
(
con
->
conrelid
));
return
DatumGetCString
(
DirectFunctionCall1
(
textout
,
expr
));
}
/*
* Check columns in child table match up with columns in parent, and increment
* their attinhcount.
*
* Called by ATExecAddInherit
s
* Called by ATExecAddInherit
*
* Currently all columns must be found in child. Missing columns are an error.
* One day we might consider creating new columns like CREATE TABLE does.
* Currently all parent columns must be found in child. Missing columns are an
* error. One day we might consider creating new columns like CREATE TABLE
* does. However, that is widely unpopular --- in the common use case of
* partitioned tables it's a foot-gun.
*
* The data type must match
perfe
ctly. If the parent column is NOT NULL then
* the child
table must be as well. Defaults are ignored
however.
* The data type must match
exa
ctly. If the parent column is NOT NULL then
* the child
must be as well. Defaults are not compared,
however.
*/
static
void
MergeAttributesIntoExisting
(
Relation
child_rel
,
Relation
parent_rel
)
{
Relation
attr
desc
;
Relation
attr
rel
;
AttrNumber
parent_attno
;
int
parent_natts
;
TupleDesc
tupleDesc
;
TupleConstr
*
constr
;
HeapTuple
tuple
;
attrrel
=
heap_open
(
AttributeRelationId
,
RowExclusiveLock
);
tupleDesc
=
RelationGetDescr
(
parent_rel
);
parent_natts
=
tupleDesc
->
natts
;
constr
=
tupleDesc
->
constr
;
...
...
@@ -6240,17 +6278,12 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
if
(
attribute
->
attisdropped
)
continue
;
/* Does it conflict with an existing column? */
attrdesc
=
heap_open
(
AttributeRelationId
,
RowExclusiveLock
);
/* Find same column in child (matching on column name). */
tuple
=
SearchSysCacheCopyAttName
(
RelationGetRelid
(
child_rel
),
attributeName
);
if
(
HeapTupleIsValid
(
tuple
))
{
/*
* Yes, try to merge the two column definitions. They must have
* the same type and typmod.
*/
/* Check they are same type and typmod */
Form_pg_attribute
childatt
=
(
Form_pg_attribute
)
GETSTRUCT
(
tuple
);
if
(
attribute
->
atttypid
!=
childatt
->
atttypid
||
...
...
@@ -6258,45 +6291,40 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"child table
\"
%s
\"
has different type for column
\"
%s
\"
"
,
RelationGetRelationName
(
child_rel
),
NameStr
(
attribute
->
attname
))));
RelationGetRelationName
(
child_rel
),
attributeName
)));
if
(
attribute
->
attnotnull
&&
!
childatt
->
attnotnull
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"column
\"
%s
\"
in child table must be marked NOT NULL"
,
NameStr
(
attribute
->
attname
))));
childatt
->
attinhcount
++
;
simple_heap_update
(
attrdesc
,
&
tuple
->
t_self
,
tuple
);
/* XXX strength reduce open indexes to outside loop? */
CatalogUpdateIndexes
(
attrdesc
,
tuple
);
heap_freetuple
(
tuple
);
attributeName
)));
/*
*
We don't touch default at all since we're not making any other
*
DDL changes to the child
*
OK, bump the child column's inheritance count. (If we fail
*
later on, this change will just roll back.)
*/
childatt
->
attinhcount
++
;
simple_heap_update
(
attrrel
,
&
tuple
->
t_self
,
tuple
);
CatalogUpdateIndexes
(
attrrel
,
tuple
);
heap_freetuple
(
tuple
);
}
else
{
/*
* Creating inherited columns in this case seems to be unpopular.
* In the common use case of partitioned tables it's a foot-gun.
*/
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"child table is missing column
\"
%s
\"
"
,
NameStr
(
attribute
->
attname
)
)));
attributeName
)));
}
heap_close
(
attrdesc
,
RowExclusiveLock
);
}
heap_close
(
attrrel
,
RowExclusiveLock
);
}
/*
* Check constraints in child table match up with constraints in parent
*
* Called by ATExecAddInherit
s
* Called by ATExecAddInherit
*
* Currently all constraints in parent must be present in the child. One day we
* may consider adding new constraints like CREATE TABLE does. We may also want
...
...
@@ -6305,9 +6333,9 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
* make it possible to ensure no records are mistakenly inserted into the
* master in partitioned tables rather than the appropriate child.
*
* XXX
this is O(n^2) which may be
issue with tables with hundreds of
* XXX
This is O(N^2) which may be an
issue with tables with hundreds of
* constraints. As long as tables have more like 10 constraints it shouldn't be
* a
n issue
though. Even 100 constraints ought not be the end of the world.
* a
problem
though. Even 100 constraints ought not be the end of the world.
*/
static
void
MergeConstraintsIntoExisting
(
Relation
child_rel
,
Relation
parent_rel
)
...
...
@@ -6326,13 +6354,12 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
ScanKeyInit
(
&
key
,
Anum_pg_constraint_conrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
RelationGetRelid
(
child_rel
)));
scan
=
systable_beginscan
(
catalogRelation
,
ConstraintRelidIndexId
,
true
,
SnapshotNow
,
1
,
&
key
);
constraints
=
NIL
;
constraints
=
NIL
;
while
(
HeapTupleIsValid
(
constraintTuple
=
systable_getnext
(
scan
)))
{
Form_pg_constraint
con
=
(
Form_pg_constraint
)
GETSTRUCT
(
constraintTuple
);
...
...
@@ -6342,20 +6369,21 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
constraints
=
lappend
(
constraints
,
heap_copytuple
(
constraintTuple
));
}
systable_endscan
(
scan
);
/* Then
loop through the parent's constraints looking for them in the list
*/
/* Then
scan through the parent's constraints looking for matches
*/
ScanKeyInit
(
&
key
,
Anum_pg_constraint_conrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
RelationGetRelid
(
parent_rel
)));
scan
=
systable_beginscan
(
catalogRelation
,
ConstraintRelidIndexId
,
true
,
SnapshotNow
,
1
,
&
key
);
while
(
HeapTupleIsValid
(
constraintTuple
=
systable_getnext
(
scan
)))
{
bool
found
=
false
;
Form_pg_constraint
parent_con
=
(
Form_pg_constraint
)
GETSTRUCT
(
constraintTuple
);
bool
found
=
false
;
Form_pg_constraint
child_con
=
NULL
;
HeapTuple
child_contuple
=
NULL
;
...
...
@@ -6364,10 +6392,10 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
foreach
(
elem
,
constraints
)
{
child_contuple
=
lfirst
(
elem
);
child_contuple
=
(
HeapTuple
)
lfirst
(
elem
);
child_con
=
(
Form_pg_constraint
)
GETSTRUCT
(
child_contuple
);
if
(
!
strcmp
(
NameStr
(
parent_con
->
conname
),
NameStr
(
child_con
->
conname
))
)
if
(
strcmp
(
NameStr
(
parent_con
->
conname
),
NameStr
(
child_con
->
conname
))
==
0
)
{
found
=
true
;
break
;
...
...
@@ -6377,14 +6405,13 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
if
(
!
found
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"child table
missing constraint matching parent table
constraint
\"
%s
\"
"
,
errmsg
(
"child table
is missing
constraint
\"
%s
\"
"
,
NameStr
(
parent_con
->
conname
))));
if
(
parent_con
->
condeferrable
!=
child_con
->
condeferrable
||
parent_con
->
condeferred
!=
child_con
->
condeferred
||
parent_con
->
contypid
!=
child_con
->
contypid
||
strcmp
(
decompile_conbin
(
constraintTuple
,
tupleDesc
),
decompile_conbin
(
child_contuple
,
tupleDesc
)))
decompile_conbin
(
child_contuple
,
tupleDesc
))
!=
0
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"constraint definition for check constraint
\"
%s
\"
does not match"
,
...
...
@@ -6407,37 +6434,42 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
* and attislocal of the columns and removes the pg_inherit and pg_depend
* entries.
*
* If attinhcount goes to 0 then attislocal gets set to true. If it goes back
up
*
attislocal stays 0 which means if a child is ever removed from a parent then
*
its columns will never be automatically dropped which may surprise. But at
*
least we'll never surprise by dropping columns someone isn't expecting to b
e
* dropped which would actually mean data loss.
* If attinhcount goes to 0 then attislocal gets set to true. If it goes back
*
up attislocal stays true, which means if a child is ever removed from a
*
parent then its columns will never be automatically dropped which may
*
surprise. But at least we'll never surprise by dropping columns someon
e
*
isn't expecting to be
dropped which would actually mean data loss.
*/
static
void
ATExecDropInherit
s
(
Relation
rel
,
RangeVar
*
parent
)
ATExecDropInherit
(
Relation
rel
,
RangeVar
*
parent
)
{
Relation
parent_rel
;
Relation
catalogRelation
;
SysScanDesc
scan
;
ScanKeyData
key
[
2
];
ScanKeyData
key
[
3
];
HeapTuple
inheritsTuple
,
attributeTuple
,
depTuple
;
Oid
inhparent
;
Oid
dropparent
;
int
found
=
false
;
bool
found
=
false
;
/*
* Get the OID of parent -- if no schema is specified use the regular
* search path and only drop the one table that's found. We could try to
* be clever and look at each parent and see if it matches but that would
* be inconsistent with other operations I think.
* AccessShareLock on the parent is probably enough, seeing that DROP TABLE
* doesn't lock parent tables at all. We need some lock since we'll be
* inspecting the parent's schema.
*/
dropparent
=
RangeVarGetRelid
(
parent
,
false
);
parent_rel
=
heap_openrv
(
parent
,
AccessShareLock
);
/* Search through the direct parents of rel looking for dropparent oid */
/*
* We don't bother to check ownership of the parent table --- ownership
* of the child is presumed enough rights.
*/
/*
* Find and destroy the pg_inherits entry linking the two, or error out
* if there is none.
*/
catalogRelation
=
heap_open
(
InheritsRelationId
,
RowExclusiveLock
);
ScanKeyInit
(
key
,
ScanKeyInit
(
&
key
[
0
]
,
Anum_pg_inherits_inhrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
RelationGetRelid
(
rel
)));
...
...
@@ -6446,8 +6478,10 @@ ATExecDropInherits(Relation rel, RangeVar *parent)
while
(
HeapTupleIsValid
(
inheritsTuple
=
systable_getnext
(
scan
)))
{
Oid
inhparent
;
inhparent
=
((
Form_pg_inherits
)
GETSTRUCT
(
inheritsTuple
))
->
inhparent
;
if
(
inhparent
==
dropparent
)
if
(
inhparent
==
RelationGetRelid
(
parent_rel
)
)
{
simple_heap_delete
(
catalogRelation
,
&
inheritsTuple
->
t_self
);
found
=
true
;
...
...
@@ -6459,26 +6493,19 @@ ATExecDropInherits(Relation rel, RangeVar *parent)
heap_close
(
catalogRelation
,
RowExclusiveLock
);
if
(
!
found
)
{
if
(
parent
->
schemaname
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_TABLE
),
errmsg
(
"relation
\"
%s.%s
\"
is not a parent of relation
\"
%s
\"
"
,
parent
->
schemaname
,
parent
->
relname
,
RelationGetRelationName
(
rel
))));
else
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_TABLE
),
ereport
(
ERROR
,
(
errcode
(
ERRCODE_UNDEFINED_TABLE
),
errmsg
(
"relation
\"
%s
\"
is not a parent of relation
\"
%s
\"
"
,
parent
->
relname
,
RelationGetRelationName
(
rel
))));
}
/* Search through columns looking for matching columns from parent table */
RelationGetRelationName
(
parent_rel
),
RelationGetRelationName
(
rel
))));
/*
* Search through child columns looking for ones matching parent rel
*/
catalogRelation
=
heap_open
(
AttributeRelationId
,
RowExclusiveLock
);
ScanKeyInit
(
key
,
ScanKeyInit
(
&
key
[
0
]
,
Anum_pg_attribute_attrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
RelationGetRelid
(
rel
)));
scan
=
systable_beginscan
(
catalogRelation
,
AttributeRelidNumIndexId
,
true
,
SnapshotNow
,
1
,
key
);
...
...
@@ -6486,18 +6513,16 @@ ATExecDropInherits(Relation rel, RangeVar *parent)
{
Form_pg_attribute
att
=
(
Form_pg_attribute
)
GETSTRUCT
(
attributeTuple
);
/*
* Not an inherited column at all (do NOT use islocal for this
* test--it can be true for inherited columns)
*/
if
(
att
->
attinhcount
==
0
)
continue
;
/* Ignore if dropped or not inherited */
if
(
att
->
attisdropped
)
continue
;
if
(
att
->
attinhcount
<=
0
)
continue
;
if
(
SearchSysCacheExistsAttName
(
dropparent
,
NameStr
(
att
->
attname
)))
if
(
SearchSysCacheExistsAttName
(
RelationGetRelid
(
parent_rel
),
NameStr
(
att
->
attname
)))
{
/* Decrement inhcount and possibly set islocal to
1
*/
/* Decrement inhcount and possibly set islocal to
true
*/
HeapTuple
copyTuple
=
heap_copytuple
(
attributeTuple
);
Form_pg_attribute
copy_att
=
(
Form_pg_attribute
)
GETSTRUCT
(
copyTuple
);
...
...
@@ -6506,14 +6531,6 @@ ATExecDropInherits(Relation rel, RangeVar *parent)
copy_att
->
attislocal
=
true
;
simple_heap_update
(
catalogRelation
,
&
copyTuple
->
t_self
,
copyTuple
);
/*
* XXX "Avoid using it for multiple tuples, since opening the
* indexes and building the index info structures is moderately
* expensive." Perhaps this can be moved outside the loop or else
* at least the CatalogOpenIndexes/CatalogCloseIndexes moved
* outside the loop but when I try that it seg faults?!
*/
CatalogUpdateIndexes
(
catalogRelation
,
copyTuple
);
heap_freetuple
(
copyTuple
);
}
...
...
@@ -6526,40 +6543,40 @@ ATExecDropInherits(Relation rel, RangeVar *parent)
*
* There's no convenient way to do this, so go trawling through pg_depend
*/
catalogRelation
=
heap_open
(
DependRelationId
,
RowExclusiveLock
);
ScanKeyInit
(
&
key
[
0
],
Anum_pg_depend_classid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
RelationRelationId
);
ObjectIdGetDatum
(
RelationRelationId
)
);
ScanKeyInit
(
&
key
[
1
],
Anum_pg_depend_objid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
RelationGetRelid
(
rel
)));
ScanKeyInit
(
&
key
[
2
],
Anum_pg_depend_objsubid
,
BTEqualStrategyNumber
,
F_INT4EQ
,
Int32GetDatum
(
0
));
scan
=
systable_beginscan
(
catalogRelation
,
DependDependerIndexId
,
true
,
SnapshotNow
,
2
,
key
);
SnapshotNow
,
3
,
key
);
while
(
HeapTupleIsValid
(
depTuple
=
systable_getnext
(
scan
)))
{
Form_pg_depend
dep
=
(
Form_pg_depend
)
GETSTRUCT
(
depTuple
);
if
(
dep
->
refclassid
==
RelationRelationId
&&
dep
->
refobjid
==
dropparent
&&
dep
->
refobjid
==
RelationGetRelid
(
parent_rel
)
&&
dep
->
refobjsubid
==
0
&&
dep
->
deptype
==
DEPENDENCY_NORMAL
)
{
/*
* Only delete a single dependency -- there shouldn't be more but
* just in case...
*/
simple_heap_delete
(
catalogRelation
,
&
depTuple
->
t_self
);
break
;
}
}
systable_endscan
(
scan
);
heap_close
(
catalogRelation
,
RowExclusiveLock
);
/* keep our lock on the parent relation until commit */
heap_close
(
parent_rel
,
NoLock
);
}
...
...
src/backend/nodes/copyfuncs.c
View file @
f58eac82
...
...
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.35
1 2006/10/04 00:29:53 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.35
2 2006/10/13 21:43:18 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -1821,7 +1821,6 @@ _copyAlterTableCmd(AlterTableCmd *from)
COPY_SCALAR_FIELD
(
subtype
);
COPY_STRING_FIELD
(
name
);
COPY_NODE_FIELD
(
parent
);
COPY_NODE_FIELD
(
def
);
COPY_NODE_FIELD
(
transform
);
COPY_SCALAR_FIELD
(
behavior
);
...
...
src/backend/nodes/equalfuncs.c
View file @
f58eac82
...
...
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.28
5 2006/10/04 00:29:53 momjian
Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.28
6 2006/10/13 21:43:18 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -768,7 +768,6 @@ _equalAlterTableCmd(AlterTableCmd *a, AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD
(
subtype
);
COMPARE_STRING_FIELD
(
name
);
COMPARE_NODE_FIELD
(
parent
);
COMPARE_NODE_FIELD
(
def
);
COMPARE_NODE_FIELD
(
transform
);
COMPARE_SCALAR_FIELD
(
behavior
);
...
...
src/backend/parser/gram.y
View file @
f58eac82
...
...
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.56
6 2006/09/28 20:51:42
tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.56
7 2006/10/13 21:43:19
tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
...
...
@@ -1506,20 +1506,20 @@ alter_table_cmd:
n->subtype = AT_DisableTrigUser;
$$ = (Node *)n;
}
/* ALTER TABLE <name>
ALTER INHERITS ADD
<parent> */
/* ALTER TABLE <name>
INHERIT
<parent> */
| INHERIT qualified_name
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_AddInherit
s
;
n->
parent =
$2;
n->subtype = AT_AddInherit;
n->
def = (Node *)
$2;
$$ = (Node *)n;
}
/* ALTER TABLE <name>
alter INHERITS DROP
<parent> */
/* ALTER TABLE <name>
NO INHERIT
<parent> */
| NO INHERIT qualified_name
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_DropInherit
s
;
n->
parent =
$3;
n->subtype = AT_DropInherit;
n->
def = (Node *)
$3;
$$ = (Node *)n;
}
| alter_rel_cmd
...
...
src/include/nodes/parsenodes.h
View file @
f58eac82
...
...
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.33
2 2006/10/11 16:42:5
9 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.33
3 2006/10/13 21:43:1
9 tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -905,8 +905,8 @@ typedef enum AlterTableType
AT_DisableTrigAll
,
/* DISABLE TRIGGER ALL */
AT_EnableTrigUser
,
/* ENABLE TRIGGER USER */
AT_DisableTrigUser
,
/* DISABLE TRIGGER USER */
AT_AddInherit
s
,
/* ADD INHERITS
parent */
AT_DropInherit
s
/* DROP INHERITS
parent */
AT_AddInherit
,
/* INHERIT
parent */
AT_DropInherit
/* NO INHERIT
parent */
}
AlterTableType
;
typedef
struct
AlterTableCmd
/* one subcommand of an ALTER TABLE */
...
...
@@ -915,9 +915,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
AlterTableType
subtype
;
/* Type of table alteration to apply */
char
*
name
;
/* column, constraint, or trigger to act on,
* or new owner or tablespace */
RangeVar
*
parent
;
/* Parent table for add/drop inherits */
Node
*
def
;
/* definition of new column, column type,
* index,
or constraint
*/
* index,
constraint, or parent table
*/
Node
*
transform
;
/* transformation expr for ALTER TYPE */
DropBehavior
behavior
;
/* RESTRICT or CASCADE for DROP cases */
}
AlterTableCmd
;
...
...
src/test/regress/expected/alter_table.out
View file @
f58eac82
...
...
@@ -324,7 +324,7 @@ select test2 from atacc2;
-- fail due to missing constraint
alter table atacc2 add constraint foo check (test2>0);
alter table atacc3 inherit atacc2;
ERROR: child table
missing constraint matching parent table
constraint "foo"
ERROR: child table
is missing
constraint "foo"
-- fail due to missing column
alter table atacc3 rename test2 to testx;
alter table atacc3 inherit atacc2;
...
...
@@ -342,10 +342,10 @@ alter table atacc3 inherit atacc2;
alter table atacc3 inherit atacc2;
ERROR: inherited relation "atacc2" duplicated
alter table atacc2 inherit atacc3;
ERROR: circular inheritance
structure foun
d
ERROR: circular inheritance
not allowe
d
DETAIL: "atacc3" is already a child of "atacc2".
alter table atacc2 inherit atacc2;
ERROR: circular inheritance
structure foun
d
ERROR: circular inheritance
not allowe
d
DETAIL: "atacc2" is already a child of "atacc2".
-- test that we really are a child now (should see 4 not 3 and cascade should go through)
select test2 from atacc2;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment