Fixed database corruption when target tables have dropped columns, and

there are views or functions depending on columns after dropped ones.
The issue was reported by depesz, and original patch by Denish Patel.

Improved documentation how to build binaries from source.

COPYRIGHT updated.
This commit is contained in:
Takahiro Itagaki 2011-04-29 05:06:48 +00:00
parent 830ef422ad
commit 960930b645
24 changed files with 198 additions and 177 deletions

View File

@ -1,4 +1,5 @@
Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
Portions Copyright (c) 2011, Itagaki Takahiro
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -9,10 +10,9 @@ modification, are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the NIPPON TELEGRAPH AND TELEPHONE CORPORATION
(NTT) nor the names of its contributors may be used to endorse or
promote products derived from this software without specific prior
written permission.
* Neither the name of the authors nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

View File

@ -1,7 +1,8 @@
#
# pg_reorg: Makefile
#
# Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2011, Itagaki Takahiro
#
ifndef USE_PGXS
top_builddir = ../..

View File

@ -1,7 +1,8 @@
#
# pg_reorg: bin/Makefile
#
# Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2011, Itagaki Takahiro
#
SRCS = pg_reorg.c pgut/pgut.c pgut/pgut-fe.c
OBJS = $(SRCS:.c=.o)

View File

@ -66,6 +66,8 @@ ALTER TABLE tbl_with_dropped_column DROP COLUMN d1;
ALTER TABLE tbl_with_dropped_column DROP COLUMN d2;
ALTER TABLE tbl_with_dropped_column DROP COLUMN d3;
ALTER TABLE tbl_with_dropped_column ADD COLUMN c3 text;
CREATE VIEW view_for_dropped_column AS
SELECT * FROM tbl_with_dropped_column;
INSERT INTO tbl_with_dropped_toast VALUES(1, 10, 'abc');
INSERT INTO tbl_with_dropped_toast VALUES(2, 20, sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text);
ALTER TABLE tbl_with_dropped_toast DROP COLUMN t;
@ -79,6 +81,13 @@ SELECT * FROM tbl_with_dropped_column;
c1 | 1 | c2 |
(2 rows)
SELECT * FROM view_for_dropped_column;
c1 | id | c2 | c3
----+----+----+----
c1 | 2 | c2 |
c1 | 1 | c2 |
(2 rows)
SELECT * FROM tbl_with_dropped_toast;
i | j
---+----
@ -188,6 +197,8 @@ SELECT * FROM tbl_gistkey ORDER BY 1;
2 | <(4,5),6>
(2 rows)
SET enable_seqscan = on;
SET enable_indexscan = off;
SELECT * FROM tbl_with_dropped_column;
c1 | id | c2 | c3
----+----+----+----
@ -195,6 +206,13 @@ SELECT * FROM tbl_with_dropped_column;
c1 | 2 | c2 |
(2 rows)
SELECT * FROM view_for_dropped_column;
c1 | id | c2 | c3
----+----+----+----
c1 | 1 | c2 |
c1 | 2 | c2 |
(2 rows)
SELECT * FROM tbl_with_dropped_toast;
i | j
---+----
@ -202,6 +220,31 @@ SELECT * FROM tbl_with_dropped_toast;
2 | 20
(2 rows)
SET enable_seqscan = off;
SET enable_indexscan = on;
SELECT * FROM tbl_with_dropped_column;
c1 | id | c2 | c3
----+----+----+----
c1 | 1 | c2 |
c1 | 2 | c2 |
(2 rows)
SELECT * FROM view_for_dropped_column;
c1 | id | c2 | c3
----+----+----+----
c1 | 1 | c2 |
c1 | 2 | c2 |
(2 rows)
SELECT * FROM tbl_with_dropped_toast;
i | j
---+----
1 | 10
2 | 20
(2 rows)
RESET enable_seqscan;
RESET enable_indexscan;
--
-- check broken links or orphan toast relations
--

View File

@ -1,14 +1,15 @@
/*
* pg_reorg.c: bin/pg_reorg.c
*
* Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*/
/**
* @brief Client Modules
*/
const char *PROGRAM_VERSION = "1.1.5";
const char *PROGRAM_VERSION = "1.1.6";
const char *PROGRAM_URL = "http://reorg.projects.postgresql.org/";
const char *PROGRAM_EMAIL = "reorg-general@lists.pgfoundry.org";
@ -19,6 +20,10 @@ const char *PROGRAM_EMAIL = "reorg-general@lists.pgfoundry.org";
#include <unistd.h>
#include <time.h>
/*
* APPLY_COUNT: Number of applied logs per transaction. Larger values
* could be faster, but will be long transactions in the REDO phase.
*/
#define APPLY_COUNT 1000
#define SQL_XID_SNAPSHOT_80300 \
@ -60,6 +65,7 @@ typedef struct reorg_table
const char *create_log; /* CREATE TABLE log */
const char *create_trigger; /* CREATE TRIGGER z_reorg_trigger */
const char *create_table; /* CREATE TABLE table AS SELECT */
const char *drop_columns; /* ALTER TABLE DROP COLUMNs */
const char *delete_log; /* DELETE FROM log */
const char *lock_table; /* LOCK TABLE table */
const char *sql_peek; /* SQL used in flush */
@ -300,6 +306,7 @@ reorg_one_database(const char *orderby, const char *table)
table.create_trigger = getstr(res, i, c++);
create_table = getstr(res, i, c++);
table.drop_columns = getstr(res, i, c++);
table.delete_log = getstr(res, i, c++);
table.lock_table = getstr(res, i, c++);
ckey = getstr(res, i, c++);
@ -393,6 +400,7 @@ reorg_one_table(const reorg_table *table, const char *orderby)
elog(DEBUG2, "create_log : %s", table->create_log);
elog(DEBUG2, "create_trigger : %s", table->create_trigger);
elog(DEBUG2, "create_table : %s", table->create_table);
elog(DEBUG2, "drop_columns : %s", table->drop_columns ? table->drop_columns : "(skipped)");
elog(DEBUG2, "delete_log : %s", table->delete_log);
elog(DEBUG2, "lock_table : %s", table->lock_table);
elog(DEBUG2, "sql_peek : %s", table->sql_peek);
@ -450,6 +458,8 @@ reorg_one_table(const reorg_table *table, const char *orderby)
command(table->delete_log, 0, NULL);
command(table->create_table, 0, NULL);
printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.table_%u')", table->target_oid);
if (table->drop_columns)
command(table->drop_columns, 0, NULL);
command(sql.data, 0, NULL);
command("COMMIT", 0, NULL);
@ -635,7 +645,7 @@ reorg_cleanup(bool fatal, void *userdata)
if (fatal)
{
fprintf(stderr, "!!!FATAL ERROR!!! Please refer to a manual.\n\n");
fprintf(stderr, "!!!FATAL ERROR!!! Please refer to the manual.\n\n");
}
else
{
@ -671,6 +681,6 @@ pgut_help(bool details)
printf(" -t, --table=TABLE reorg specific table only\n");
printf(" -n, --no-order do vacuum full instead of cluster\n");
printf(" -o, --order-by=columns order by columns instead of cluster keys\n");
printf(" -T, --wait-timeout=secs timeout to cancel other backends on conflict.\n");
printf(" -T, --wait-timeout=secs timeout to cancel other backends on conflict\n");
printf(" -Z, --no-analyze don't analyze at end\n");
}

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-fe.c
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-fe.h
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut.c
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut.h
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -80,6 +80,8 @@ ALTER TABLE tbl_with_dropped_column DROP COLUMN d1;
ALTER TABLE tbl_with_dropped_column DROP COLUMN d2;
ALTER TABLE tbl_with_dropped_column DROP COLUMN d3;
ALTER TABLE tbl_with_dropped_column ADD COLUMN c3 text;
CREATE VIEW view_for_dropped_column AS
SELECT * FROM tbl_with_dropped_column;
INSERT INTO tbl_with_dropped_toast VALUES(1, 10, 'abc');
INSERT INTO tbl_with_dropped_toast VALUES(2, 20, sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text);
@ -89,6 +91,7 @@ ALTER TABLE tbl_with_dropped_toast DROP COLUMN t;
--
SELECT * FROM tbl_with_dropped_column;
SELECT * FROM view_for_dropped_column;
SELECT * FROM tbl_with_dropped_toast;
--
@ -114,8 +117,19 @@ SELECT col1, to_char("time", 'YYYY-MM-DD HH24:MI:SS'), ","")" FROM tbl_cluster;
SELECT * FROM tbl_only_ckey ORDER BY 1;
SELECT * FROM tbl_only_pkey ORDER BY 1;
SELECT * FROM tbl_gistkey ORDER BY 1;
SET enable_seqscan = on;
SET enable_indexscan = off;
SELECT * FROM tbl_with_dropped_column;
SELECT * FROM view_for_dropped_column;
SELECT * FROM tbl_with_dropped_toast;
SET enable_seqscan = off;
SET enable_indexscan = on;
SELECT * FROM tbl_with_dropped_column;
SELECT * FROM view_for_dropped_column;
SELECT * FROM tbl_with_dropped_toast;
RESET enable_seqscan;
RESET enable_indexscan;
--
-- check broken links or orphan toast relations

View File

@ -121,7 +121,10 @@ CREATE INDEX idx_rnd ON tbl (rndkey);</pre></code></td>
</div>
<hr />
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<p class="footer">
Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION<br />
Portions Copyright (c) 2011, Itagaki Takahiro
</p>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");

View File

@ -122,7 +122,10 @@ CREATE INDEX idx_rnd ON tbl (rndkey);</pre></code></td>
</center>
<hr />
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<p class="footer">
Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION<br />
Portions Copyright (c) 2011, Itagaki Takahiro
</p>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");

View File

@ -8,7 +8,7 @@
</head>
<body>
<h1 id="pg_reorg">pg_reorg 1.1.3</h1>
<h1 id="pg_reorg">pg_reorg 1.1.6</h1>
<div class="navigation">
<a href="index-ja.html">Top</a> &gt;
<a href="pg_reorg-ja.html">pg_reorg</a>
@ -291,20 +291,29 @@ pg_reorg の実行中には、VACUUM と ANALYZE <STRONG>以外</STRONG> のDDL
最後にシステムカタログを直接書き換えることで、元のテーブルと名前を交換しています。</p>
<h2 id="install">インストール方法</h2>
<p>pgxs を使ってビルドできます。</p>
<p>
UNIX や Linux では、make を実行すると自動的に pgxs を使ってビルドできます。
前もって PostgreSQL 開発用パッケージ (postgresql-devel 等) をインストールし、pg_config にパスを通してください。
</p>
<pre>$ cd pg_reorg
$ make USE_PGXS=1
$ make
$ su
$ make USE_PGXS=1 install</pre>
$ make install</pre>
<p>
Windows では Microsoft Visual C++ 2010 でビルドできます。
msvc フォルダ内にプロジェクトファイルがあります。
</p>
<p>その後、データベースに関数を登録します。</p>
<pre>$ pg_ctl start
$ psql -f $PGSHARE/contrib/pg_reorg.sql your_database</pre>
$ psql -f $PGSHARE/contrib/pg_reorg.sql -d your_database</pre>
<p>(注意: <code>CREATE EXTENSION</code> はまだサポートしていません。)</p>
<h2 id="requirement">動作環境</h2>
<dl>
<dt>PostgreSQLバージョン</dt>
<dd>PostgreSQL 8.3, 8.4, 9.0</dd>
<dd>PostgreSQL 8.2, 8.3, 8.4, 9.0, 9.1</dd>
<dt>OS</dt>
<dd>RHEL 5.2, Windows XP SP3</dd>
<dt>ディスク容量</dt>
@ -320,7 +329,10 @@ $ psql -f $PGSHARE/contrib/pg_reorg.sql your_database</pre>
<a href="index-ja.html">Top</a> &gt;
<a href="pg_reorg-ja.html">pg_reorg</a>
<div>
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<p class="footer">
Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION<br />
Portions Copyright (c) 2011, Itagaki Takahiro
</p>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");

View File

@ -8,7 +8,7 @@
</head>
<body>
<h1 id="pg_reorg">pg_reorg 1.1.3</h1>
<h1 id="pg_reorg">pg_reorg 1.1.6</h1>
<div class="navigation">
<a href="index.html">Top</a> &gt;
<a href="pg_reorg.html">pg_reorg</a>
@ -279,20 +279,31 @@ In many case pg_reorg would fail and rollback collectly, but there are some case
Then, it updates system catalog directly to swap the work table and the original one.</p>
<h2 id="install">Installations</h2>
<p>pg_reorg can be built with pgxs.</p>
<p>
pg_reorg can be built with "make" on UNIX or Linux.
pgxs build framework is used automatically.
Before build, you might need to install postgres packages for developper (postgresql-devel, etc.)
and add <code>pg_config</code> to your $PATH.
</p>
<pre>$ cd pg_reorg
$ make USE_PGXS=1
$ make
$ su
$ make USE_PGXS=1 install</pre>
$ make install</pre>
<p>
You can also use Microsoft Visual C++ 2010 to build the program on Windows.
There are project files in the msvc folder.
</p>
<p>Start PostgreSQL and execute the script to register functions to your database.</p>
<pre>$ pg_ctl start
$ psql -f $PGSHARE/contrib/pg_reorg.sql your_database</pre>
$ psql -f $PGSHARE/contrib/pg_reorg.sql -d your_database</pre>
<p>(NOTE: <code>CREATE EXTENSION</code> is not supported yet.)</p>
<h2 id="requirement">Requirements</h2>
<dl>
<dt>PostgreSQL version</dt>
<dd>PostgreSQL 8.3, 8.4, 9.0</dd>
<dd>PostgreSQL 8.2, 8.3, 8.4, 9.0, 9.1</dd>
<dt>OS</dt><dd>RHEL 5.2, Windows XP SP3</dd>
<dt>Disks</dt><dd>Requires amount of disks twice larger than target table and indexes. (If the total size of targets are 1GB, additional 2GB of disks are required.)</dd>
</dl>
@ -306,7 +317,10 @@ $ psql -f $PGSHARE/contrib/pg_reorg.sql your_database</pre>
<a href="index.html">Top</a> &gt;
<a href="pg_reorg.html">pg_reorg</a>
<div>
<p class="footer">Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION</p>
<p class="footer">
Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION<br />
Portions Copyright (c) 2011, Itagaki Takahiro
</p>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");

View File

@ -1,7 +1,8 @@
#
# pg_reorg: lib/Makefile
#
# Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
# Portions Copyright (c) 2011, Itagaki Takahiro
#
SRCS = reorg.c pgut/pgut-be.c pgut/pgut-spi.c
OBJS = $(SRCS:.c=.o)

View File

@ -1,7 +1,8 @@
/*
* pg_reorg: lib/pg_reorg.sql.in
*
* Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*/
-- Adjust this setting to control where the objects get created.
@ -106,6 +107,43 @@ $$
$$
LANGUAGE sql STABLE STRICT;
-- Get a column list for SELECT all columns including dropped ones.
-- We use NULLs of integer types for dropped columns (types are not important).
CREATE FUNCTION reorg.get_columns_for_create_as(oid)
RETURNS text AS
$$
SELECT array_to_string(reorg.array_accum(c), ',') FROM (SELECT
CASE WHEN attisdropped
THEN 'NULL::integer AS ' || quote_ident(attname)
ELSE quote_ident(attname)
END AS c
FROM pg_attribute
WHERE attrelid = $1 AND attnum > 0 ORDER BY attnum
) AS COL
$$
LANGUAGE sql STABLE STRICT;
-- Get a SQL text to DROP dropped columns for the table,
-- or NULL if it has no dropped columns.
CREATE FUNCTION reorg.get_drop_columns(oid, text)
RETURNS text AS
$$
SELECT
'ALTER TABLE ' || $2 || ' ' || array_to_string(dropped_columns, ', ')
FROM (
SELECT
reorg.array_accum('DROP COLUMN ' || quote_ident(attname)) AS dropped_columns
FROM (
SELECT * FROM pg_attribute
WHERE attrelid = $1 AND attnum > 0 AND attisdropped
ORDER BY attnum
) T
) T
WHERE
array_upper(dropped_columns, 1) > 0
$$
LANGUAGE sql STABLE STRICT;
-- includes not only PRIMARY KEYS but also UNIQUE NOT NULL keys
CREATE VIEW reorg.primary_keys AS
SELECT indrelid, (reorg.array_accum(indexrelid))[1] AS indexrelid
@ -130,7 +168,8 @@ CREATE VIEW reorg.tables AS
reorg.get_create_index_type(PK.indexrelid, 'reorg.pk_' || R.oid) AS create_pktype,
'CREATE TABLE reorg.log_' || R.oid || ' (id bigserial PRIMARY KEY, pk reorg.pk_' || R.oid || ', row ' || reorg.oid2text(R.oid) || ')' AS create_log,
reorg.get_create_trigger(R.oid, PK.indexrelid) AS create_trigger,
'CREATE TABLE reorg.table_' || R.oid || ' WITH (' || array_to_string(array_append(R.reloptions, 'oids=' || CASE WHEN R.relhasoids THEN 'true' ELSE 'false' END), ',') || ') TABLESPACE ' || coalesce(quote_ident(S.spcname), 'pg_default') || ' AS SELECT * FROM ONLY ' || reorg.oid2text(R.oid) AS create_table,
'CREATE TABLE reorg.table_' || R.oid || ' WITH (' || array_to_string(array_append(R.reloptions, 'oids=' || CASE WHEN R.relhasoids THEN 'true' ELSE 'false' END), ',') || ') TABLESPACE ' || coalesce(quote_ident(S.spcname), 'pg_default') || ' AS SELECT ' || reorg.get_columns_for_create_as(R.oid) || ' FROM ONLY ' || reorg.oid2text(R.oid) AS create_table,
reorg.get_drop_columns(R.oid, 'reorg.table_' || R.oid) AS drop_columns,
'DELETE FROM reorg.log_' || R.oid AS delete_log,
'LOCK TABLE ' || reorg.oid2text(R.oid) || ' IN ACCESS EXCLUSIVE MODE' AS lock_table,
reorg.get_index_keys(CK.indexrelid, R.oid) AS ckey,

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-be.c
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-be.h
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-spi.c
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,9 +1,8 @@
/*-------------------------------------------------------------------------
*
* pgut-spi.h
*
* Copyright (c) 2009-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
*
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*-------------------------------------------------------------------------
*/

View File

@ -1,7 +1,8 @@
/*
* pg_reorg: lib/reorg.c
*
* Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*/
#include "postgres.h"
@ -75,7 +76,7 @@ static void RenameRelationInternal(Oid myrelid, const char *newrelname, Oid name
Datum
reorg_version(PG_FUNCTION_ARGS)
{
return CStringGetTextDatum("pg_reorg 1.1.5");
return CStringGetTextDatum("pg_reorg 1.1.6");
}
/**
@ -592,101 +593,6 @@ getint16(HeapTuple tuple, TupleDesc desc, int column)
return isnull ? 0 : DatumGetInt16(datum);
}
static void
remove_dropped_columns_and_adjust_attnum(Oid oid, int16 natts1, int16 natts2)
{
/* delete dropped columns */
execute_with_format(SPI_OK_DELETE,
"DELETE FROM pg_catalog.pg_attribute"
" WHERE attrelid = %u AND attisdropped",
oid);
if (SPI_processed != natts1 - natts2)
elog(ERROR, "cannot remove %d dropped columns (%u columns removed)",
natts2 - natts1, SPI_processed);
/* renumber attnum */
#if PG_VERSION_NUM >= 90000
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_attribute m"
" SET attnum = (SELECT count(*) FROM pg_attribute a"
" WHERE m.attrelid = a.attrelid"
" AND m.attnum >= a.attnum"
" AND a.attnum > 0 AND NOT a.attisdropped)"
" WHERE attrelid = %u AND attnum > 0 AND NOT attisdropped",
oid);
if (SPI_processed != natts2)
elog(ERROR, "cannot update %d columns (%u columns updated)",
natts2, SPI_processed);
#elif PG_VERSION_NUM >= 80300
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_attribute"
" SET attnum = (SELECT count(*) FROM pg_attribute a"
" WHERE pg_catalog.pg_attribute.attrelid = a.attrelid"
" AND pg_catalog.pg_attribute.attnum >= a.attnum"
" AND a.attnum > 0 AND NOT a.attisdropped)"
" WHERE attrelid = %u AND attnum > 0 AND NOT attisdropped",
oid);
if (SPI_processed != natts2)
elog(ERROR, "cannot update %d columns (%u columns updated)",
natts2, SPI_processed);
#else
/*
* Use count(*) in subquery because 8.2 doesn't support aggregates
* in UPDATE SET.
*/
do
{
uint32 i;
uint32 ntuples;
SPITupleTable *tuptable;
TupleDesc desc;
execute_with_format(SPI_OK_SELECT,
"SELECT attnum FROM pg_catalog.pg_attribute"
" WHERE attrelid = %u AND attnum > 0 AND NOT attisdropped"
" ORDER BY attnum",
oid);
if (SPI_processed != natts2)
elog(ERROR, "number of columns should be %d (%d returned)",
natts2, SPI_processed);
ntuples = SPI_processed;
tuptable = SPI_tuptable;
desc = tuptable->tupdesc;
for (i = 0; i < ntuples; i++)
{
int attnum;
int count;
attnum = getint16(tuptable->vals[i], desc, 1);
execute_with_format(SPI_OK_SELECT,
"SELECT count(*)::smallint FROM pg_catalog.pg_attribute"
" WHERE attrelid = %u AND attnum > 0 AND attnum <= %d",
oid, attnum);
if (SPI_processed != 1)
elog(ERROR, "cannot adjust column %d", attnum);
count = getint16(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_attribute"
" SET attnum = %d"
" WHERE attrelid = %u AND attnum = %d",
count, oid, attnum);
if (SPI_processed != 1)
elog(ERROR, "cannot update column %d", attnum);
}
} while(0);
#endif
/* adjust attribute number of the table */
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_class SET relnatts = %d WHERE oid = %u",
natts2, oid);
}
/**
* @fn Datum reorg_swap(PG_FUNCTION_ARGS)
* @brief Swapping relfilenode of tables and relation ids of toast tables
@ -799,27 +705,6 @@ reorg_swap(PG_FUNCTION_ARGS)
idx2 = getoid(tuple, desc, 2);
swap_heap_or_index_files(idx1, idx2);
/* adjust key attnum if the target table has dropped columns */
if (natts1 != natts2)
{
#if PG_VERSION_NUM >= 90000
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_index m SET indkey = n.indkey"
" FROM pg_catalog.pg_index n"
" WHERE m.indexrelid = %u"
" AND n.indexrelid = 'reorg.index_%u'::regclass",
idx1, idx1);
#else
execute_with_format(SPI_OK_UPDATE,
"UPDATE pg_catalog.pg_index SET indkey = n.indkey"
" FROM pg_catalog.pg_index n"
" WHERE pg_catalog.pg_index.indexrelid = %u"
" AND n.indexrelid = 'reorg.index_%u'::regclass",
idx1, idx1);
#endif
if (SPI_processed != 1)
elog(ERROR, "failed to update pg_index.indkey (%u rows updated)", SPI_processed);
}
CommandCounterIncrement();
}
@ -876,10 +761,6 @@ reorg_swap(PG_FUNCTION_ARGS)
CommandCounterIncrement();
}
/* adjust attribute numbers if the target table has dropped columns */
if (natts1 != natts2)
remove_dropped_columns_and_adjust_attnum(oid, natts1, natts2);
/* drop reorg trigger */
execute_with_format(
SPI_OK_UTILITY,

View File

@ -1,7 +1,8 @@
/*
* pg_reorg: lib/uninstall_reorg.sql
*
* Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
* Portions Copyright (c) 2011, Itagaki Takahiro
*/
DROP SCHEMA IF EXISTS reorg CASCADE;

View File

@ -312,11 +312,13 @@
<None Include="..\bin\Makefile" />
<None Include="..\bin\sql\init.sql" />
<None Include="..\bin\sql\reorg.sql" />
<None Include="..\COPYRIGHT" />
<None Include="..\doc\index-ja.html" />
<None Include="..\doc\index.html" />
<None Include="..\doc\pg_reorg-ja.html" />
<None Include="..\doc\pg_reorg.html" />
<None Include="..\doc\style.css" />
<None Include="..\Makefile" />
<None Include="readme.txt" />
</ItemGroup>
<ItemGroup>

View File

@ -54,6 +54,10 @@
<None Include="..\bin\sql\reorg.sql">
<Filter>regress\sql</Filter>
</None>
<None Include="..\COPYRIGHT">
<Filter>doc</Filter>
</None>
<None Include="..\Makefile" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\bin\pg_reorg.c">