From 232c9bb6c909aa259dde68c3eac875ce36ef3e13 Mon Sep 17 00:00:00 2001 From: Takahiro Itagaki Date: Thu, 6 Jan 2011 09:35:15 +0000 Subject: [PATCH] Use one of not-null unique keys to identify rows when the target table doesn't have a primary key. Some of users want to use not-null unique keys rather than primary keys because postgres doesn't support REINDEX PRIMARY KEY CONCURRENTLY. - Support 9.1dev. - Improve Makefile to use PGXS automatically. --- Makefile | 14 +++++++++++--- bin/Makefile | 16 ++++++++++++---- bin/expected/reorg.out | 17 +++++++++++++++++ bin/pg_reorg.c | 2 +- bin/sql/reorg.sql | 16 ++++++++++++++++ lib/Makefile | 16 ++++++++++++---- lib/pg_reorg.sql.in | 21 +++++++++++++++++++-- lib/pgut/pgut-be.h | 6 ++++++ lib/reorg.c | 2 +- 9 files changed, 95 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index bc72c51..db2b3da 100755 --- a/Makefile +++ b/Makefile @@ -3,14 +3,22 @@ # # Copyright (c) 2008-2010, NIPPON TELEGRAPH AND TELEPHONE CORPORATION # +ifndef USE_PGXS +top_builddir = ../.. +makefile_global = $(top_builddir)/src/Makefile.global +ifeq "$(wildcard $(makefile_global))" "" +USE_PGXS = 1 # use pgxs if not in contrib directory +endif +endif + ifdef USE_PGXS PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) else -subdir = pg_statsinfo -top_builddir = ../.. -include $(top_builddir)/src/Makefile.global +subdir = pg_reorg +include $(makefile_global) +include $(top_srcdir)/contrib/contrib-global.mk endif SUBDIRS = bin lib diff --git a/bin/Makefile b/bin/Makefile index 400a88f..1749ab8 100755 --- a/bin/Makefile +++ b/bin/Makefile @@ -15,13 +15,21 @@ PG_CPPFLAGS = -I$(libpq_srcdir) endif PG_LIBS = $(libpq) +ifndef USE_PGXS +top_builddir = ../../.. +makefile_global = $(top_builddir)/src/Makefile.global +ifeq "$(wildcard $(makefile_global))" "" +USE_PGXS = 1 # use pgxs if not in contrib directory +endif +endif + ifdef USE_PGXS -PGXS := $(shell pg_config --pgxs) +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) else -subdir = contrib/pg_reorg -top_builddir = ../../.. -include $(top_builddir)/src/Makefile.global +subdir = contrib/$(MODULE_big) +include $(makefile_global) include $(top_srcdir)/contrib/contrib-global.mk endif diff --git a/bin/expected/reorg.out b/bin/expected/reorg.out index 66654d7..a0aff7d 100755 --- a/bin/expected/reorg.out +++ b/bin/expected/reorg.out @@ -222,3 +222,20 @@ SELECT oid, relname -----+--------- (0 rows) +-- +-- NOT NULL UNIQUE +-- +CREATE TABLE tbl_nn (col1 int NOT NULL, col2 int NOT NULL); +CREATE TABLE tbl_uk (col1 int NOT NULL, col2 int , UNIQUE(col1, col2)); +CREATE TABLE tbl_nn_uk (col1 int NOT NULL, col2 int NOT NULL, UNIQUE(col1, col2)); +CREATE TABLE tbl_pk_uk (col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1, col2), UNIQUE(col2, col1)); +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn +ERROR: relation "tbl_nn" must have a primary key or not-null unique keys +-- => ERROR +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_uk +ERROR: relation "tbl_uk" must have a primary key or not-null unique keys +-- => ERROR +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_uk +-- => OK +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_pk_uk +-- => OK diff --git a/bin/pg_reorg.c b/bin/pg_reorg.c index 0e79fb7..4d3c2bc 100755 --- a/bin/pg_reorg.c +++ b/bin/pg_reorg.c @@ -293,7 +293,7 @@ reorg_one_database(const char *orderby, const char *table) if (table.pkid == 0) ereport(ERROR, (errcode(E_PG_COMMAND), - errmsg("relation \"%s\" has no primary key", table.target_name))); + errmsg("relation \"%s\" must have a primary key or not-null unique keys", table.target_name))); table.create_pktype = getstr(res, i, c++); table.create_log = getstr(res, i, c++); diff --git a/bin/sql/reorg.sql b/bin/sql/reorg.sql index fc29e0e..ea05ada 100755 --- a/bin/sql/reorg.sql +++ b/bin/sql/reorg.sql @@ -130,3 +130,19 @@ SELECT oid, relname WHERE relkind = 'r' AND reltoastrelid <> 0 AND reltoastrelid NOT IN (SELECT oid FROM pg_class WHERE relkind = 't'); + +-- +-- NOT NULL UNIQUE +-- +CREATE TABLE tbl_nn (col1 int NOT NULL, col2 int NOT NULL); +CREATE TABLE tbl_uk (col1 int NOT NULL, col2 int , UNIQUE(col1, col2)); +CREATE TABLE tbl_nn_uk (col1 int NOT NULL, col2 int NOT NULL, UNIQUE(col1, col2)); +CREATE TABLE tbl_pk_uk (col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1, col2), UNIQUE(col2, col1)); +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn +-- => ERROR +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_uk +-- => ERROR +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_uk +-- => OK +\! pg_reorg --dbname=contrib_regression --no-order --table=tbl_pk_uk +-- => OK diff --git a/lib/Makefile b/lib/Makefile index 41926e9..0027dbf 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,13 +9,21 @@ MODULE_big = pg_reorg DATA_built = pg_reorg.sql DATA = uninstall_pg_reorg.sql +ifndef USE_PGXS +top_builddir = ../../.. +makefile_global = $(top_builddir)/src/Makefile.global +ifeq "$(wildcard $(makefile_global))" "" +USE_PGXS = 1 # use pgxs if not in contrib directory +endif +endif + ifdef USE_PGXS -PGXS := $(shell pg_config --pgxs) +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) else -subdir = contrib/pg_reorg -top_builddir = ../../.. -include $(top_builddir)/src/Makefile.global +subdir = contrib/$(MODULE_big) +include $(makefile_global) include $(top_srcdir)/contrib/contrib-global.mk endif diff --git a/lib/pg_reorg.sql.in b/lib/pg_reorg.sql.in index d30c5cb..27173bd 100755 --- a/lib/pg_reorg.sql.in +++ b/lib/pg_reorg.sql.in @@ -106,6 +106,20 @@ $$ $$ 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 + FROM (SELECT indrelid, indexrelid FROM pg_index + WHERE indisunique + AND 0 <> ALL(indkey) + AND NOT EXISTS( + SELECT 1 FROM pg_attribute + WHERE attrelid = indrelid + AND attnum = ANY(indkey) + AND NOT attnotnull) + ORDER BY indrelid, indisprimary DESC, indnatts, indkey) tmp + GROUP BY indrelid; + CREATE VIEW reorg.tables AS SELECT R.oid::regclass AS relname, R.oid AS relid, @@ -127,10 +141,13 @@ CREATE VIEW reorg.tables AS 'DELETE FROM reorg.log_' || R.oid || ' WHERE id <= $1' AS sql_pop FROM pg_class R LEFT JOIN pg_class T ON R.reltoastrelid = T.oid - LEFT JOIN (SELECT * FROM pg_index WHERE indisprimary) PK + LEFT JOIN reorg.primary_keys PK ON R.oid = PK.indrelid LEFT JOIN (SELECT CKI.* FROM pg_index CKI, pg_class CKT - WHERE CKI.indexrelid = CKT.oid AND CKI.indisclustered AND CKT.relam = 403) CK + WHERE CKI.indisvalid + AND CKI.indexrelid = CKT.oid + AND CKI.indisclustered + AND CKT.relam = 403) CK ON R.oid = CK.indrelid LEFT JOIN pg_namespace N ON N.oid = R.relnamespace LEFT JOIN pg_tablespace S ON S.oid = R.reltablespace diff --git a/lib/pgut/pgut-be.h b/lib/pgut/pgut-be.h index 56b43cc..cb5436f 100755 --- a/lib/pgut/pgut-be.h +++ b/lib/pgut/pgut-be.h @@ -151,6 +151,12 @@ extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, #endif +#if PG_VERSION_NUM < 90100 + +#define ATExecChangeOwner(relationOid, newOwnerId, recursing, lockmode) \ + ATExecChangeOwner((relationOid), (newOwnerId), (recursing)) +#endif + #if PG_VERSION_NUM < 80300 #define RelationSetNewRelfilenode(rel, xid) \ setNewRelfilenode((rel)) diff --git a/lib/reorg.c b/lib/reorg.c index 928f4b1..2fe3039 100755 --- a/lib/reorg.c +++ b/lib/reorg.c @@ -766,7 +766,7 @@ reorg_swap(PG_FUNCTION_ARGS) /* change owner of new relation to original owner */ if (owner1 != owner2) { - ATExecChangeOwner(oid2, owner1, true); + ATExecChangeOwner(oid2, owner1, true, AccessExclusiveLock); CommandCounterIncrement(); }