├── .gitignore ├── .travis.yml ├── COPYRIGHT ├── META.json ├── Makefile ├── README.md ├── SPECS ├── pg_reorg84.spec └── pg_reorg90.spec ├── bin ├── .gitignore ├── Makefile ├── expected │ ├── init.out │ └── reorg.out ├── pg_reorg.c ├── pgut │ ├── pgut-fe.c │ ├── pgut-fe.h │ ├── pgut.c │ └── pgut.h └── sql │ ├── init-extension.sql │ ├── init-legacy.sql │ └── reorg.sql ├── doc ├── index-ja.html ├── index.html ├── pg_reorg-ja.html ├── pg_reorg.html └── style.css ├── lib ├── .gitignore ├── Makefile ├── pg_reorg.control ├── pg_reorg.sql.in ├── pgut │ ├── pgut-be.c │ ├── pgut-be.h │ ├── pgut-spi.c │ └── pgut-spi.h ├── reorg.c └── uninstall_pg_reorg.sql └── msvc ├── bin.2010.vcxproj ├── bin.2010.vcxproj.filters ├── bin.vcproj ├── lib.2010.vcxproj ├── lib.2010.vcxproj.filters ├── lib.vcproj ├── pg_reorg.2010.sln ├── pg_reorg.sln └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Global excludes across all subdirectories 2 | *.o 3 | *.so 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - psql --version 3 | - sudo service postgresql stop 4 | - sudo apt-get -y --purge remove postgresql libpq-dev libpq5 postgresql-client-common postgresql-common 5 | - sudo rm -rf /var/lib/postgresql 6 | - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - 7 | - sudo sh -c "echo deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main $PGVERSION >> /etc/apt/sources.list.d/postgresql.list" 8 | - sudo apt-get update -qq 9 | - sudo apt-get -y install bc libpam-dev libedit-dev 10 | - sudo apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::="--force-confnew" install postgresql-$PGVERSION postgresql-server-dev-$PGVERSION postgresql-contrib-$PGVERSION 11 | - if [ $PGVERSION = 9.2 ] ; then sudo apt-get -y --force-yes install libpq5=9.2.9-1.pgdg12.4+1 libpq-dev=9.2.9-1.pgdg12.4+1 ; fi 12 | - if [ $PGVERSION = 9.1 ] ; then sudo apt-get -y --force-yes install libpq5=9.1.14-1.pgdg12.4+1 libpq-dev=9.1.14-1.pgdg12.4+1 ; fi 13 | - if [ $PGVERSION = 9.0 ] ; then sudo apt-get -y --force-yes install libpq5=9.0.18-1.pgdg12.4+1 libpq-dev=9.0.18-1.pgdg12.4+1 ; fi 14 | - if [ $PGVERSION = 8.4 ] ; then sudo apt-get -y --force-yes install libpq5=8.4.22-1.pgdg12.4+1 libpq-dev=8.4.22-1.pgdg12.4+1 ; fi 15 | - sudo service postgresql stop 16 | - echo 'export PATH=$PATH:/usr/lib/postgresql/$PGVERSION/bin' >> ~/.bashrc 17 | - export PATH=$PATH:/usr/lib/postgresql/$PGVERSION/bin 18 | - echo 'export PGDATA=/home/travis/build/bwtakacy/pg_reorg/pg_data/$PGVERSION' >> ~/.bashrc 19 | - export PGDATA=/home/travis/build/bwtakacy/pg_reorg/pg_data/$PGVERSION 20 | - mkdir pg_data 21 | - initdb --no-locale -D pg_data/$PGVERSION 22 | - sudo chmod 777 /var/run/postgresql 23 | - sudo echo "local all postgres trust" > $PGDATA/pg_hba.conf 24 | - sudo echo "local all all trust" >> $PGDATA/pg_hba.conf 25 | - sudo echo "host all all 127.0.0.1/32 trust" >> $PGDATA/pg_hba.conf 26 | - sudo echo "host all all ::1/128 trust" >> $PGDATA/pg_hba.conf 27 | - sudo echo "logging_collector = on" >> $PGDATA/postgresql.conf 28 | - pg_ctl -V 29 | - pg_ctl -D $PGDATA start 30 | 31 | before_script: 32 | - git clone https://github.com/bwtakacy/pg_reorg.git pg_reorg 33 | - cd pg_reorg && git describe --alway 34 | - make 35 | - sudo make install 36 | 37 | env: 38 | matrix: 39 | # - PGVERSION=9.4 40 | # - PGVERSION=9.3 41 | # - PGVERSION=9.2 42 | - PGVERSION=9.1 43 | - PGVERSION=9.0 44 | - PGVERSION=8.4 45 | 46 | language: cpp 47 | compiler: 48 | # - clang 49 | - gcc 50 | 51 | script: make installcheck 52 | 53 | after_script: 54 | - cat /home/travis/build/bwtakacy/pg_reorg/pg_reorg/bin/regression.diffs 55 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 2 | Portions Copyright (c) 2011, Itagaki Takahiro 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the authors nor the names of its contributors may 14 | be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /META.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pg_reorg", 3 | "abstract": "PostgreSQL module for data reorganization", 4 | "description": "pg_reorg is a PostgreSQL module allowing to reorganize a table without any locks.", 5 | "version": "1.2dev0", 6 | "maintainer": "Takahiro Itagaki", 7 | "tags": [ "bloat", "maintenance", "vacuum", "cluster" ], 8 | "release_status": "stable", 9 | "license": "bsd", 10 | "provides": { 11 | "pg_reorg": { 12 | "file": "lib/pg_reorg.sql", 13 | "version": "1.2dev0", 14 | "abstract": "PostgreSQL module for data reorganization" 15 | } 16 | }, 17 | "prereqs": { 18 | "runtime": { 19 | "requires": { 20 | "PostgreSQL": "8.2.0" 21 | } 22 | } 23 | }, 24 | "resources": { 25 | "homepage": "http://reorg.projects.postgresql.org/", 26 | "bugtracker": { 27 | "web": "http://pgfoundry.org/tracker/?atid=1376&group_id=1000411&func=browse" 28 | } 29 | }, 30 | "meta-spec": { 31 | "version": "1.0.0", 32 | "url": "http://pgxn.org/meta/spec.txt" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # pg_reorg: Makefile 3 | # 4 | # Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | # Portions Copyright (c) 2011, Itagaki Takahiro 6 | # 7 | ifndef USE_PGXS 8 | top_builddir = ../.. 9 | makefile_global = $(top_builddir)/src/Makefile.global 10 | ifeq "$(wildcard $(makefile_global))" "" 11 | USE_PGXS = 1 # use pgxs if not in contrib directory 12 | endif 13 | endif 14 | 15 | ifdef USE_PGXS 16 | PG_CONFIG = pg_config 17 | PGXS := $(shell $(PG_CONFIG) --pgxs) 18 | include $(PGXS) 19 | else 20 | subdir = pg_reorg 21 | include $(makefile_global) 22 | include $(top_srcdir)/contrib/contrib-global.mk 23 | endif 24 | 25 | SUBDIRS = bin lib 26 | 27 | # Pull out the version number from pg_config 28 | VERSION = $(shell $(PG_CONFIG) --version | awk '{print $$2}') 29 | 30 | # We support PostgreSQL 8.3 and later. 31 | ifneq ($(shell echo $(VERSION) | grep -E "^7\.|^8\.[012]"),) 32 | $(error pg_reorg requires PostgreSQL 8.3 or later. This is $(VERSION)) 33 | endif 34 | 35 | 36 | all install installdirs uninstall distprep clean distclean maintainer-clean debug: 37 | @for dir in $(SUBDIRS); do \ 38 | $(MAKE) -C $$dir $@ || exit; \ 39 | done 40 | 41 | # We'd like check operations to run all the subtests before failing. 42 | check installcheck: 43 | @CHECKERR=0; for dir in $(SUBDIRS); do \ 44 | $(MAKE) -C $$dir $@ || CHECKERR=$$?; \ 45 | done; \ 46 | exit $$CHECKERR 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pg_reorg 2 | ======= 3 | This tools re-organize tables on a PostgreSQL database without keeping any locks so that you can retrieve or update rows. 4 | 5 | Now, the development and maintenounce of pg_reorg has been stopped. 6 | The laste stable branch maint_1.1 supported PostgreSQL version, 8.4 to 9.4. 7 | 8 | * maint_1.1 : [![Build Status](https://travis-ci.org/ossc-db/pg_reorg.svg?branch=maint_1.1)](https://travis-ci.org/ossc-db/pg_reorg) 9 | 10 | Now,we join to [pg_repack](http://github.com/reorg/pg_repack) project. 11 | Please use it instead of pg_reorg. 12 | 13 | How to use 14 | ---------- 15 | pg_reorg run for a specified table like below: 16 | 17 | ```` 18 | $ pg_reorg -t test1 -o a 19 | INFO: ---- reorganize one table with 7 steps. ---- 20 | INFO: target table name : test1 21 | INFO: ---- STEP1. setup ---- 22 | INFO: This needs EXCLUSIVE LOCK against the target table. 23 | INFO: ---- STEP2. copy tuples into temp table---- 24 | INFO: ---- STEP3. create indexes ---- 25 | INFO: ---- STEP4. apply logs ---- 26 | INFO: ---- STEP5. swap tables ---- 27 | INFO: This needs EXCLUSIVE LOCK against the target table. 28 | INFO: ---- STEP6. drop old table---- 29 | INFO: ---- STEP7. analyze --- 30 | ```` 31 | 32 | See documentation about detail usage. 33 | 34 | http://ossc-db.github.io/pg_reorg/index.html 35 | 36 | How to build and install from source code 37 | ----------------------------------------- 38 | Change directory into top directory of pg_reorg sorce codes and 39 | run the below commands. 40 | 41 | ```` 42 | $ make 43 | # make install 44 | ```` 45 | 46 | How to run regression tests 47 | --------------------------- 48 | Start PostgreSQL server and run the below command. 49 | 50 | ```` 51 | $ make installcheck 52 | ```` 53 | 54 | -------------------------------------------------------------------------------- /SPECS/pg_reorg84.spec: -------------------------------------------------------------------------------- 1 | # SPEC file for pg_reorg 2 | # Copyright(C) 2009-2010 NIPPON TELEGRAPH AND TELEPHONE CORPORATION 3 | %define sname pg_reorg 4 | 5 | Summary: Reorganize tables in PostgreSQL databases without any locks. 6 | Name: %{sname} 7 | Version: 1.1.5 8 | Release: 1%{?dist} 9 | License: BSD 10 | Group: Applications/Databases 11 | Source0: %{sname}-%{version}.tar.gz 12 | URL: http://pgfoundry.org/projects/%{sname}/ 13 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n) 14 | 15 | BuildRequires: postgresql-devel, postgresql 16 | Requires: postgresql, postgresql-libs 17 | 18 | %description 19 | pg_reorg can re-organize tables on a postgres database without any locks so that 20 | you can retrieve or update rows in tables being reorganized. 21 | The module is developed to be a better alternative of CLUSTER and VACUUM FULL. 22 | 23 | %prep 24 | %setup -q -n %{sname}-%{version} 25 | 26 | %build 27 | USE_PGXS=1 make %{?_smp_mflags} 28 | 29 | %install 30 | rm -rf %{buildroot} 31 | USE_PGXS=1 make DESTDIR=%{buildroot} 32 | 33 | install -d %{buildroot}%{_libdir}/pgsql 34 | install -d %{buildroot}%{_bindir} 35 | install -d %{buildroot}%{_datadir}/pgsql/contrib 36 | 37 | install -m 755 bin/pg_reorg %{buildroot}%{_bindir}/pg_reorg 38 | install -m 755 lib/pg_reorg.so %{buildroot}%{_libdir}/pgsql/pg_reorg.so 39 | install -m 644 lib/pg_reorg.sql %{buildroot}%{_datadir}/pgsql/contrib/pg_reorg.sql 40 | install -m 644 lib/uninstall_pg_reorg.sql %{buildroot}%{_datadir}/pgsql/contrib/uninstall_pg_reorg.sql 41 | 42 | %define pg_sharedir 43 | 44 | %files 45 | %defattr(755,root,root,755) 46 | %{_bindir}/pg_reorg 47 | %{_libdir}/pgsql/pg_reorg.so 48 | %defattr(644,root,root,755) 49 | %{_datadir}/pgsql/contrib/pg_reorg.sql 50 | %{_datadir}/pgsql/contrib/uninstall_pg_reorg.sql 51 | 52 | %clean 53 | rm -rf %{buildroot} 54 | 55 | %changelog 56 | * Thu Oct 21 2010 - NTT OSS Center 1.1.5-1 57 | * Wed Sep 22 2010 - NTT OSS Center 1.1.4-1 58 | * Thu Apr 22 2010 - NTT OSS Center 1.1.2-1 59 | * Mon Jan 15 2010 - Toru SHIMOGAKI 1.0.8-1 60 | * Tue Sep 08 2009 - Toru SHIMOGAKI 1.0.6-1 61 | * Fri May 15 2009 - Toru SHIMOGAKI 1.0.4-1 62 | - Initial packaging 63 | -------------------------------------------------------------------------------- /SPECS/pg_reorg90.spec: -------------------------------------------------------------------------------- 1 | # SPEC file for pg_reorg 2 | # Copyright(C) 2009-2010 NIPPON TELEGRAPH AND TELEPHONE CORPORATION 3 | %define sname pg_reorg 4 | 5 | %define _pgdir /usr/pgsql-9.0 6 | %define _bindir %{_pgdir}/bin 7 | %define _libdir %{_pgdir}/lib 8 | %define _datadir %{_pgdir}/share 9 | 10 | Summary: Reorganize tables in PostgreSQL databases without any locks. 11 | Name: %{sname} 12 | Version: 1.1.5 13 | Release: 1%{?dist} 14 | License: BSD 15 | Group: Applications/Databases 16 | Source0: %{sname}-%{version}.tar.gz 17 | URL: http://pgfoundry.org/projects/%{sname}/ 18 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n) 19 | 20 | BuildRequires: postgresql90-devel, postgresql90 21 | Requires: postgresql90, postgresql90-libs 22 | 23 | %description 24 | pg_reorg can re-organize tables on a postgres database without any locks so that 25 | you can retrieve or update rows in tables being reorganized. 26 | The module is developed to be a better alternative of CLUSTER and VACUUM FULL. 27 | 28 | %prep 29 | %setup -q -n %{sname}-%{version} 30 | 31 | %build 32 | USE_PGXS=1 make %{?_smp_mflags} 33 | 34 | %install 35 | rm -rf %{buildroot} 36 | USE_PGXS=1 make DESTDIR=%{buildroot} 37 | 38 | install -d %{buildroot}%{_libdir} 39 | install -d %{buildroot}%{_bindir} 40 | install -d %{buildroot}%{_datadir}/contrib 41 | 42 | install -m 755 bin/pg_reorg %{buildroot}%{_bindir}/pg_reorg 43 | install -m 755 lib/pg_reorg.so %{buildroot}%{_libdir}/pg_reorg.so 44 | install -m 644 lib/pg_reorg.sql %{buildroot}%{_datadir}/contrib/pg_reorg.sql 45 | install -m 644 lib/uninstall_pg_reorg.sql %{buildroot}%{_datadir}/contrib/uninstall_pg_reorg.sql 46 | 47 | %define pg_sharedir 48 | 49 | %files 50 | %defattr(755,root,root,755) 51 | %{_bindir}/pg_reorg 52 | %{_libdir}/pg_reorg.so 53 | %defattr(644,root,root,755) 54 | %{_datadir}/contrib/pg_reorg.sql 55 | %{_datadir}/contrib/uninstall_pg_reorg.sql 56 | 57 | %clean 58 | rm -rf %{buildroot} 59 | 60 | %changelog 61 | * Thu Oct 21 2010 - NTT OSS Center 1.1.5-1 62 | * Wed Sep 22 2010 - NTT OSS Center 1.1.4-1 63 | * Thu Apr 22 2010 - NTT OSS Center 1.1.2-1 64 | * Mon Jan 15 2010 - Toru SHIMOGAKI 1.0.8-1 65 | * Tue Sep 08 2009 - Toru SHIMOGAKI 1.0.6-1 66 | * Fri May 15 2009 - Toru SHIMOGAKI 1.0.4-1 67 | - Initial packaging 68 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /pg_reorg 3 | /results/ 4 | /sql/init.sql 5 | /sql/init-*.*.sql 6 | -------------------------------------------------------------------------------- /bin/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # pg_reorg: bin/Makefile 3 | # 4 | # Portions Copyright (c) 2008-2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | # Portions Copyright (c) 2011, Itagaki Takahiro 6 | # 7 | SRCS = pg_reorg.c pgut/pgut.c pgut/pgut-fe.c 8 | OBJS = $(SRCS:.c=.o) 9 | PROGRAM = pg_reorg 10 | REGRESS = init reorg 11 | 12 | EXTRA_CLEAN = sql/init-$(MAJORVERSION).sql sql/init.sql 13 | 14 | ifdef DEBUG_REORG 15 | PG_CPPFLAGS = -I$(libpq_srcdir) -DDEBUG_REORG 16 | else 17 | PG_CPPFLAGS = -I$(libpq_srcdir) 18 | endif 19 | PG_LIBS = $(libpq) 20 | 21 | ifndef USE_PGXS 22 | top_builddir = ../../.. 23 | makefile_global = $(top_builddir)/src/Makefile.global 24 | ifeq "$(wildcard $(makefile_global))" "" 25 | USE_PGXS = 1 # use pgxs if not in contrib directory 26 | endif 27 | endif 28 | 29 | ifdef USE_PGXS 30 | PG_CONFIG = pg_config 31 | PGXS := $(shell $(PG_CONFIG) --pgxs) 32 | include $(PGXS) 33 | else 34 | subdir = contrib/$(MODULE_big) 35 | include $(makefile_global) 36 | include $(top_srcdir)/contrib/contrib-global.mk 37 | endif 38 | 39 | # remove dependency to libxml2 and libxslt 40 | LIBS := $(filter-out -lxml2, $(LIBS)) 41 | LIBS := $(filter-out -lxslt, $(LIBS)) 42 | 43 | ifndef MAJORVERSION 44 | MAJORVERSION := $(basename $(VERSION)) 45 | endif 46 | 47 | sql/init.sql: sql/init-$(MAJORVERSION).sql 48 | cp sql/init-$(MAJORVERSION).sql sql/init.sql 49 | expected/init.out: expected/init-$(MAJORVERSION).out 50 | cp expected/init-$(MAJORVERSION).out expected/init.out 51 | sql/init-8.3.sql: 52 | cp sql/init-legacy.sql sql/init-8.3.sql 53 | sql/init-8.4.sql: 54 | cp sql/init-legacy.sql sql/init-8.4.sql 55 | sql/init-9.0.sql: 56 | cp sql/init-legacy.sql sql/init-9.0.sql 57 | sql/init-9.1.sql: 58 | cp sql/init-extension.sql sql/init-9.1.sql 59 | sql/init-9.2.sql: 60 | cp sql/init-extension.sql sql/init-9.2.sql 61 | sql/init-9.3.sql: 62 | cp sql/init-extension.sql sql/init-9.3.sql 63 | 64 | installcheck: sql/init.sql 65 | -------------------------------------------------------------------------------- /bin/expected/init.out: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | \set ECHO none 3 | RESET client_min_messages; 4 | -------------------------------------------------------------------------------- /bin/expected/reorg.out: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | -- 3 | -- create table. 4 | -- 5 | CREATE TABLE tbl_cluster ( 6 | col1 int, 7 | "time" timestamp, 8 | ","")" text, 9 | PRIMARY KEY (","")", col1) WITH (fillfactor = 75) 10 | ) WITH (fillfactor = 70); 11 | CREATE INDEX ","") cluster" ON tbl_cluster ("time", length(","")"), ","")" text_pattern_ops) WITH (fillfactor = 75); 12 | ALTER TABLE tbl_cluster CLUSTER ON ","") cluster"; 13 | CREATE TABLE tbl_only_pkey ( 14 | col1 int PRIMARY KEY, 15 | ","")" text 16 | ); 17 | CREATE TABLE tbl_only_ckey ( 18 | col1 int, 19 | col2 timestamp, 20 | ","")" text 21 | ) WITH (fillfactor = 70); 22 | CREATE INDEX cidx_only_ckey ON tbl_only_ckey (col2, ","")"); 23 | ALTER TABLE tbl_only_ckey CLUSTER ON cidx_only_ckey; 24 | CREATE TABLE tbl_gistkey ( 25 | id integer PRIMARY KEY, 26 | c circle 27 | ); 28 | CREATE INDEX cidx_circle ON tbl_gistkey USING gist (c); 29 | ALTER TABLE tbl_gistkey CLUSTER ON cidx_circle; 30 | CREATE TABLE tbl_with_dropped_column ( 31 | d1 text, 32 | c1 text, 33 | id integer PRIMARY KEY, 34 | d2 text, 35 | c2 text, 36 | d3 text 37 | ); 38 | ALTER INDEX tbl_with_dropped_column_pkey SET (fillfactor = 75); 39 | ALTER TABLE tbl_with_dropped_column CLUSTER ON tbl_with_dropped_column_pkey; 40 | CREATE INDEX idx_c1c2 ON tbl_with_dropped_column (c1, c2) WITH (fillfactor = 75); 41 | CREATE INDEX idx_c2c1 ON tbl_with_dropped_column (c2, c1); 42 | CREATE TABLE tbl_with_dropped_toast ( 43 | i integer, 44 | j integer, 45 | t text, 46 | PRIMARY KEY (i, j) 47 | ); 48 | ALTER TABLE tbl_with_dropped_toast CLUSTER ON tbl_with_dropped_toast_pkey; 49 | CREATE TABLE tbl_badindex ( 50 | id integer PRIMARY KEY, 51 | n integer 52 | ); 53 | CREATE TABLE tbl_idxopts ( 54 | i integer PRIMARY KEY, 55 | t text 56 | ); 57 | CREATE INDEX idxopts_t ON tbl_idxopts (t DESC NULLS LAST) WHERE (t != 'aaa'); 58 | -- 59 | -- insert data 60 | -- 61 | INSERT INTO tbl_cluster VALUES(1, '2008-12-31 10:00:00', 'admin'); 62 | INSERT INTO tbl_cluster VALUES(2, '2008-01-01 00:00:00', 'king'); 63 | INSERT INTO tbl_cluster VALUES(3, '2008-03-04 12:00:00', 'joker'); 64 | INSERT INTO tbl_cluster VALUES(4, '2008-03-05 15:00:00', 'queen'); 65 | INSERT INTO tbl_cluster VALUES(5, '2008-01-01 00:30:00', sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text); 66 | INSERT INTO tbl_only_pkey VALUES(1, 'abc'); 67 | INSERT INTO tbl_only_pkey VALUES(2, 'def'); 68 | INSERT INTO tbl_only_ckey VALUES(1, '2008-01-01 00:00:00', 'abc'); 69 | INSERT INTO tbl_only_ckey VALUES(2, '2008-02-01 00:00:00', 'def'); 70 | INSERT INTO tbl_gistkey VALUES(1, '<(1,2),3>'); 71 | INSERT INTO tbl_gistkey VALUES(2, '<(4,5),6>'); 72 | INSERT INTO tbl_with_dropped_column VALUES('d1', 'c1', 2, 'd2', 'c2', 'd3'); 73 | INSERT INTO tbl_with_dropped_column VALUES('d1', 'c1', 1, 'd2', 'c2', 'd3'); 74 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d1; 75 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d2; 76 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d3; 77 | ALTER TABLE tbl_with_dropped_column ADD COLUMN c3 text; 78 | CREATE VIEW view_for_dropped_column AS 79 | SELECT * FROM tbl_with_dropped_column; 80 | INSERT INTO tbl_with_dropped_toast VALUES(1, 10, 'abc'); 81 | INSERT INTO tbl_with_dropped_toast VALUES(2, 20, sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text); 82 | ALTER TABLE tbl_with_dropped_toast DROP COLUMN t; 83 | INSERT INTO tbl_badindex VALUES(1, 10); 84 | INSERT INTO tbl_badindex VALUES(2, 10); 85 | -- This will fail. Silence the message as it's different across PG versions. 86 | SET client_min_messages = fatal; 87 | CREATE UNIQUE INDEX CONCURRENTLY idx_badindex_n ON tbl_badindex (n); 88 | SET client_min_messages = warning; 89 | INSERT INTO tbl_idxopts VALUES (0, 'abc'), (1, 'aaa'), (2, NULL), (3, 'bbb'); 90 | -- 91 | -- before 92 | -- 93 | SELECT * FROM tbl_with_dropped_column; 94 | c1 | id | c2 | c3 95 | ----+----+----+---- 96 | c1 | 2 | c2 | 97 | c1 | 1 | c2 | 98 | (2 rows) 99 | 100 | SELECT * FROM view_for_dropped_column; 101 | c1 | id | c2 | c3 102 | ----+----+----+---- 103 | c1 | 2 | c2 | 104 | c1 | 1 | c2 | 105 | (2 rows) 106 | 107 | SELECT * FROM tbl_with_dropped_toast; 108 | i | j 109 | ---+---- 110 | 1 | 10 111 | 2 | 20 112 | (2 rows) 113 | 114 | -- 115 | -- do reorg 116 | -- 117 | \! pg_reorg --dbname=contrib_regression --no-order 118 | WARNING: skipping invalid index: CREATE UNIQUE INDEX idx_badindex_n ON tbl_badindex USING btree (n) 119 | \! pg_reorg --dbname=contrib_regression 120 | \! pg_reorg --dbname=contrib_regression --table=tbl_cluster 121 | -- 122 | -- after 123 | -- 124 | \d tbl_cluster 125 | Table "public.tbl_cluster" 126 | Column | Type | Modifiers 127 | --------+-----------------------------+----------- 128 | col1 | integer | not null 129 | time | timestamp without time zone | 130 | ,") | text | not null 131 | Indexes: 132 | "tbl_cluster_pkey" PRIMARY KEY, btree (","")", col1) WITH (fillfactor=75) 133 | ",") cluster" btree ("time", length(","")"), ","")" text_pattern_ops) WITH (fillfactor=75) CLUSTER 134 | 135 | \d tbl_gistkey 136 | Table "public.tbl_gistkey" 137 | Column | Type | Modifiers 138 | --------+---------+----------- 139 | id | integer | not null 140 | c | circle | 141 | Indexes: 142 | "tbl_gistkey_pkey" PRIMARY KEY, btree (id) 143 | "cidx_circle" gist (c) CLUSTER 144 | 145 | \d tbl_only_ckey 146 | Table "public.tbl_only_ckey" 147 | Column | Type | Modifiers 148 | --------+-----------------------------+----------- 149 | col1 | integer | 150 | col2 | timestamp without time zone | 151 | ,") | text | 152 | Indexes: 153 | "cidx_only_ckey" btree (col2, ","")") CLUSTER 154 | 155 | \d tbl_only_pkey 156 | Table "public.tbl_only_pkey" 157 | Column | Type | Modifiers 158 | --------+---------+----------- 159 | col1 | integer | not null 160 | ,") | text | 161 | Indexes: 162 | "tbl_only_pkey_pkey" PRIMARY KEY, btree (col1) 163 | 164 | \d tbl_with_dropped_column 165 | Table "public.tbl_with_dropped_column" 166 | Column | Type | Modifiers 167 | --------+---------+----------- 168 | c1 | text | 169 | id | integer | not null 170 | c2 | text | 171 | c3 | text | 172 | Indexes: 173 | "tbl_with_dropped_column_pkey" PRIMARY KEY, btree (id) WITH (fillfactor=75) CLUSTER 174 | "idx_c1c2" btree (c1, c2) WITH (fillfactor=75) 175 | "idx_c2c1" btree (c2, c1) 176 | 177 | \d tbl_with_dropped_toast 178 | Table "public.tbl_with_dropped_toast" 179 | Column | Type | Modifiers 180 | --------+---------+----------- 181 | i | integer | not null 182 | j | integer | not null 183 | Indexes: 184 | "tbl_with_dropped_toast_pkey" PRIMARY KEY, btree (i, j) CLUSTER 185 | 186 | \d tbl_idxopts 187 | Table "public.tbl_idxopts" 188 | Column | Type | Modifiers 189 | --------+---------+----------- 190 | i | integer | not null 191 | t | text | 192 | Indexes: 193 | "tbl_idxopts_pkey" PRIMARY KEY, btree (i) 194 | "idxopts_t" btree (t DESC NULLS LAST) WHERE t <> 'aaa'::text 195 | 196 | SELECT col1, to_char("time", 'YYYY-MM-DD HH24:MI:SS'), ","")" FROM tbl_cluster; 197 | col1 | to_char | ,") 198 | ------+---------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 199 | 2 | 2008-01-01 00:00:00 | king 200 | 5 | 2008-01-01 00:30:00 | 1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079896872533965463318088296406206152583523950547457502877599617298355752203375318570113543746034084988471603868999706990048150305440277903164542478230684929369186215805784631115966687130130156185689872372352885092648612494977154218334204285686060146824720771435854874155657069677653720226485447015858801620758474922657226002085584466521458398893944370926591800311388246468157082630100594858704003186480342194897278290641045072636881313739855256117322040245091227700226941127573627280495738108967504018369868368450725799364729060762996941380475654823728997180326802474420629269124859052181004459842150591120249441341728531478105803603371077309182869314710171111683916581726889419758716582152128229518488471.732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248575675626141415406703029969945094998952478811655512094373648528093231902305582067974820101084674923265015312343266903322886650672254668921837971227047131660367861588019049986537379859389467650347506576050756618348129606100947602187190325083145829523959832997789824508288714463832917347224163984587855397667958063818353666110843173780894378316102088305524901670023520711144288695990956365797087168498072899493296484283020786408603988738697537582317317831395992983007838702877053913369563312103707264019249106768231199288375641141422016742752102372994270831059898459475987664288897796147837958390228854852903576033852808064381972344661059689722872865264153822664698420021195484155278441181286534507035191650016689294415480846071277143999762926834629577438361895110127148638746976545982451788550975379013880664961911962222957110555242923723192197738262561631468842032853716682938649611917049738836395495938 201 | 3 | 2008-03-04 12:00:00 | joker 202 | 4 | 2008-03-05 15:00:00 | queen 203 | 1 | 2008-12-31 10:00:00 | admin 204 | (5 rows) 205 | 206 | SELECT * FROM tbl_only_ckey ORDER BY 1; 207 | col1 | col2 | ,") 208 | ------+--------------------------+----- 209 | 1 | Tue Jan 01 00:00:00 2008 | abc 210 | 2 | Fri Feb 01 00:00:00 2008 | def 211 | (2 rows) 212 | 213 | SELECT * FROM tbl_only_pkey ORDER BY 1; 214 | col1 | ,") 215 | ------+----- 216 | 1 | abc 217 | 2 | def 218 | (2 rows) 219 | 220 | SELECT * FROM tbl_gistkey ORDER BY 1; 221 | id | c 222 | ----+----------- 223 | 1 | <(1,2),3> 224 | 2 | <(4,5),6> 225 | (2 rows) 226 | 227 | SET enable_seqscan = on; 228 | SET enable_indexscan = off; 229 | SELECT * FROM tbl_with_dropped_column; 230 | c1 | id | c2 | c3 231 | ----+----+----+---- 232 | c1 | 1 | c2 | 233 | c1 | 2 | c2 | 234 | (2 rows) 235 | 236 | SELECT * FROM view_for_dropped_column; 237 | c1 | id | c2 | c3 238 | ----+----+----+---- 239 | c1 | 1 | c2 | 240 | c1 | 2 | c2 | 241 | (2 rows) 242 | 243 | SELECT * FROM tbl_with_dropped_toast; 244 | i | j 245 | ---+---- 246 | 1 | 10 247 | 2 | 20 248 | (2 rows) 249 | 250 | SET enable_seqscan = off; 251 | SET enable_indexscan = on; 252 | SELECT * FROM tbl_with_dropped_column; 253 | c1 | id | c2 | c3 254 | ----+----+----+---- 255 | c1 | 1 | c2 | 256 | c1 | 2 | c2 | 257 | (2 rows) 258 | 259 | SELECT * FROM view_for_dropped_column; 260 | c1 | id | c2 | c3 261 | ----+----+----+---- 262 | c1 | 1 | c2 | 263 | c1 | 2 | c2 | 264 | (2 rows) 265 | 266 | SELECT * FROM tbl_with_dropped_toast; 267 | i | j 268 | ---+---- 269 | 1 | 10 270 | 2 | 20 271 | (2 rows) 272 | 273 | RESET enable_seqscan; 274 | RESET enable_indexscan; 275 | -- 276 | -- check broken links or orphan toast relations 277 | -- 278 | SELECT oid, relname 279 | FROM pg_class 280 | WHERE relkind = 't' 281 | AND oid NOT IN (SELECT reltoastrelid FROM pg_class WHERE relkind = 'r'); 282 | oid | relname 283 | -----+--------- 284 | (0 rows) 285 | 286 | SELECT oid, relname 287 | FROM pg_class 288 | WHERE relkind = 'r' 289 | AND reltoastrelid <> 0 290 | AND reltoastrelid NOT IN (SELECT oid FROM pg_class WHERE relkind = 't'); 291 | oid | relname 292 | -----+--------- 293 | (0 rows) 294 | 295 | -- 296 | -- NOT NULL UNIQUE 297 | -- 298 | CREATE TABLE tbl_nn (col1 int NOT NULL, col2 int NOT NULL); 299 | CREATE TABLE tbl_uk (col1 int NOT NULL, col2 int , UNIQUE(col1, col2)); 300 | CREATE TABLE tbl_nn_uk (col1 int NOT NULL, col2 int NOT NULL, UNIQUE(col1, col2)); 301 | CREATE TABLE tbl_pk_uk (col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1, col2), UNIQUE(col2, col1)); 302 | CREATE TABLE tbl_nn_puk (col1 int NOT NULL, col2 int NOT NULL); 303 | CREATE UNIQUE INDEX tbl_nn_puk_pcol1_idx ON tbl_nn_puk(col1) WHERE col1 < 10; 304 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn 305 | ERROR: relation "tbl_nn" must have a primary key or not-null unique keys 306 | -- => ERROR 307 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_uk 308 | ERROR: relation "tbl_uk" must have a primary key or not-null unique keys 309 | -- => ERROR 310 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_uk 311 | -- => OK 312 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_pk_uk 313 | -- => OK 314 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_puk 315 | ERROR: relation "tbl_nn_puk" must have a primary key or not-null unique keys 316 | -- => ERROR 317 | -------------------------------------------------------------------------------- /bin/pg_reorg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pg_reorg.c: bin/pg_reorg.c 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | */ 7 | 8 | /** 9 | * @brief Client Modules 10 | */ 11 | 12 | const char *PROGRAM_VERSION = "1.1.7"; 13 | const char *PROGRAM_URL = "http://reorg.projects.postgresql.org/"; 14 | const char *PROGRAM_EMAIL = "reorg-general@lists.pgfoundry.org"; 15 | 16 | #include "pgut/pgut-fe.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* 24 | * APPLY_COUNT: Number of applied logs per transaction. Larger values 25 | * could be faster, but will be long transactions in the REDO phase. 26 | */ 27 | #define APPLY_COUNT 1000 28 | 29 | /* The '1/1, -1/0' lock skipped is from the bgwriter on newly promoted 30 | * servers. See GH ticket #1. 31 | */ 32 | #define SQL_XID_SNAPSHOT \ 33 | "SELECT reorg.array_accum(virtualtransaction) FROM pg_locks"\ 34 | " WHERE locktype = 'virtualxid' AND pid <> pg_backend_pid()"\ 35 | " AND (virtualxid, virtualtransaction) <> ('1/1', '-1/0')" 36 | 37 | #define SQL_XID_ALIVE \ 38 | "SELECT pid FROM pg_locks WHERE locktype = 'virtualxid'"\ 39 | " AND pid <> pg_backend_pid() AND virtualtransaction = ANY($1)" 40 | 41 | /* 42 | * per-table information 43 | */ 44 | typedef struct reorg_table 45 | { 46 | const char *target_name; /* target: relname */ 47 | Oid target_oid; /* target: OID */ 48 | Oid target_toast; /* target: toast OID */ 49 | Oid target_tidx; /* target: toast index OID */ 50 | Oid pkid; /* target: PK OID */ 51 | Oid ckid; /* target: CK OID */ 52 | const char *create_pktype; /* CREATE TYPE pk */ 53 | const char *create_log; /* CREATE TABLE log */ 54 | const char *create_trigger; /* CREATE TRIGGER z_reorg_trigger */ 55 | const char *enable_trigger; /* ALTER TABLE ENABLE ALWAYS TRIGGER z_reorg_trigger */ 56 | const char *create_table; /* CREATE TABLE table AS SELECT */ 57 | const char *drop_columns; /* ALTER TABLE DROP COLUMNs */ 58 | const char *delete_log; /* DELETE FROM log */ 59 | const char *lock_table; /* LOCK TABLE table */ 60 | const char *sql_peek; /* SQL used in flush */ 61 | const char *sql_insert; /* SQL used in flush */ 62 | const char *sql_delete; /* SQL used in flush */ 63 | const char *sql_update; /* SQL used in flush */ 64 | const char *sql_pop; /* SQL used in flush */ 65 | } reorg_table; 66 | 67 | /* 68 | * per-index information 69 | */ 70 | typedef struct reorg_index 71 | { 72 | Oid target_oid; /* target: OID */ 73 | const char *create_index; /* CREATE INDEX */ 74 | } reorg_index; 75 | 76 | static void reorg_all_databases(const char *order_by); 77 | static bool reorg_one_database(const char *order_by, const char *table); 78 | static void reorg_one_table(const reorg_table *table, const char *order_by); 79 | static void reorg_cleanup(bool fatal, void *userdata); 80 | 81 | static char *getstr(PGresult *res, int row, int col); 82 | static Oid getoid(PGresult *res, int row, int col); 83 | static void lock_exclusive(const char *relid, const char *lock_query); 84 | 85 | #define SQLSTATE_INVALID_SCHEMA_NAME "3F000" 86 | #define SQLSTATE_QUERY_CANCELED "57014" 87 | 88 | static bool sqlstate_equals(PGresult *res, const char *state) 89 | { 90 | return strcmp(PQresultErrorField(res, PG_DIAG_SQLSTATE), state) == 0; 91 | } 92 | 93 | static bool analyze = true; 94 | static bool alldb = false; 95 | static bool noorder = false; 96 | static char *table = NULL; 97 | static char *orderby = NULL; 98 | static int wait_timeout = 60; /* in seconds */ 99 | 100 | /* buffer should have at least 11 bytes */ 101 | static char * 102 | utoa(unsigned int value, char *buffer) 103 | { 104 | sprintf(buffer, "%u", value); 105 | return buffer; 106 | } 107 | 108 | static pgut_option options[] = 109 | { 110 | { 'b', 'a', "all", &alldb }, 111 | { 's', 't', "table", &table }, 112 | { 'b', 'n', "no-order", &noorder }, 113 | { 's', 'o', "order-by", &orderby }, 114 | { 'i', 'T', "wait-timeout", &wait_timeout }, 115 | { 'B', 'Z', "no-analyze", &analyze }, 116 | { 0 }, 117 | }; 118 | 119 | int 120 | main(int argc, char *argv[]) 121 | { 122 | int i; 123 | 124 | i = pgut_getopt(argc, argv, options); 125 | 126 | if (i == argc - 1) 127 | dbname = argv[i]; 128 | else if (i < argc) 129 | ereport(ERROR, 130 | (errcode(EINVAL), 131 | errmsg("too many arguments"))); 132 | 133 | if (noorder) 134 | orderby = ""; 135 | 136 | if (alldb) 137 | { 138 | if (table) 139 | ereport(ERROR, 140 | (errcode(EINVAL), 141 | errmsg("cannot reorg a specific table in all databases"))); 142 | reorg_all_databases(orderby); 143 | } 144 | else 145 | { 146 | if (!reorg_one_database(orderby, table)) 147 | ereport(ERROR, 148 | (errcode(ENOENT), 149 | errmsg("%s is not installed", PROGRAM_NAME))); 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | /* 156 | * Call reorg_one_database for each database. 157 | */ 158 | static void 159 | reorg_all_databases(const char *orderby) 160 | { 161 | PGresult *result; 162 | int i; 163 | 164 | dbname = "postgres"; 165 | reconnect(ERROR); 166 | result = execute("SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", 0, NULL); 167 | disconnect(); 168 | 169 | for (i = 0; i < PQntuples(result); i++) 170 | { 171 | bool ret; 172 | 173 | dbname = PQgetvalue(result, i, 0); 174 | 175 | if (pgut_log_level >= INFO) 176 | { 177 | printf("%s: reorg database \"%s\"", PROGRAM_NAME, dbname); 178 | fflush(stdout); 179 | } 180 | 181 | ret = reorg_one_database(orderby, NULL); 182 | 183 | if (pgut_log_level >= INFO) 184 | { 185 | if (ret) 186 | printf("\n"); 187 | else 188 | printf(" ... skipped\n"); 189 | fflush(stdout); 190 | } 191 | } 192 | 193 | PQclear(result); 194 | } 195 | 196 | /* result is not copied */ 197 | static char * 198 | getstr(PGresult *res, int row, int col) 199 | { 200 | if (PQgetisnull(res, row, col)) 201 | return NULL; 202 | else 203 | return PQgetvalue(res, row, col); 204 | } 205 | 206 | static Oid 207 | getoid(PGresult *res, int row, int col) 208 | { 209 | if (PQgetisnull(res, row, col)) 210 | return InvalidOid; 211 | else 212 | return (Oid)strtoul(PQgetvalue(res, row, col), NULL, 10); 213 | } 214 | 215 | /* 216 | * Call reorg_one_table for the target table or each table in a database. 217 | */ 218 | static bool 219 | reorg_one_database(const char *orderby, const char *table) 220 | { 221 | bool ret = true; 222 | PGresult *res; 223 | int i; 224 | int num; 225 | StringInfoData sql; 226 | 227 | initStringInfo(&sql); 228 | 229 | reconnect(ERROR); 230 | 231 | /* Disable statement timeout. */ 232 | command("SET statement_timeout = 0", 0, NULL); 233 | 234 | /* Restrict search_path to system catalog. */ 235 | command("SET search_path = pg_catalog, pg_temp, public", 0, NULL); 236 | 237 | /* To avoid annoying "create implicit ..." messages. */ 238 | command("SET client_min_messages = warning", 0, NULL); 239 | 240 | /* acquire target tables */ 241 | appendStringInfoString(&sql, "SELECT * FROM reorg.tables WHERE "); 242 | if (table) 243 | { 244 | appendStringInfoString(&sql, "relid = $1::regclass"); 245 | res = execute_elevel(sql.data, 1, &table, DEBUG2); 246 | } 247 | else 248 | { 249 | appendStringInfoString(&sql, "pkid IS NOT NULL"); 250 | if (!orderby) 251 | appendStringInfoString(&sql, " AND ckid IS NOT NULL"); 252 | res = execute_elevel(sql.data, 0, NULL, DEBUG2); 253 | } 254 | 255 | if (PQresultStatus(res) != PGRES_TUPLES_OK) 256 | { 257 | if (sqlstate_equals(res, SQLSTATE_INVALID_SCHEMA_NAME)) 258 | { 259 | /* Schema reorg does not exist. Skip the database. */ 260 | ret = false; 261 | goto cleanup; 262 | } 263 | else 264 | { 265 | /* exit otherwise */ 266 | printf("%s", PQerrorMessage(connection)); 267 | PQclear(res); 268 | exit(1); 269 | } 270 | } 271 | 272 | num = PQntuples(res); 273 | 274 | for (i = 0; i < num; i++) 275 | { 276 | reorg_table table; 277 | const char *create_table; 278 | const char *ckey; 279 | int c = 0; 280 | 281 | table.target_name = getstr(res, i, c++); 282 | table.target_oid = getoid(res, i, c++); 283 | table.target_toast = getoid(res, i, c++); 284 | table.target_tidx = getoid(res, i, c++); 285 | table.pkid = getoid(res, i, c++); 286 | table.ckid = getoid(res, i, c++); 287 | 288 | if (table.pkid == 0) 289 | ereport(ERROR, 290 | (errcode(E_PG_COMMAND), 291 | errmsg("relation \"%s\" must have a primary key or not-null unique keys", table.target_name))); 292 | 293 | table.create_pktype = getstr(res, i, c++); 294 | table.create_log = getstr(res, i, c++); 295 | table.create_trigger = getstr(res, i, c++); 296 | table.enable_trigger = getstr(res, i, c++); 297 | 298 | create_table = getstr(res, i, c++); 299 | table.drop_columns = getstr(res, i, c++); 300 | table.delete_log = getstr(res, i, c++); 301 | table.lock_table = getstr(res, i, c++); 302 | ckey = getstr(res, i, c++); 303 | 304 | resetStringInfo(&sql); 305 | if (!orderby) 306 | { 307 | /* CLUSTER mode */ 308 | if (ckey == NULL) 309 | ereport(ERROR, 310 | (errcode(E_PG_COMMAND), 311 | errmsg("relation \"%s\" has no cluster key", table.target_name))); 312 | appendStringInfo(&sql, "%s ORDER BY %s", create_table, ckey); 313 | table.create_table = sql.data; 314 | } 315 | else if (!orderby[0]) 316 | { 317 | /* VACUUM FULL mode */ 318 | table.create_table = create_table; 319 | } 320 | else 321 | { 322 | /* User specified ORDER BY */ 323 | appendStringInfo(&sql, "%s ORDER BY %s", create_table, orderby); 324 | table.create_table = sql.data; 325 | } 326 | 327 | table.sql_peek = getstr(res, i, c++); 328 | table.sql_insert = getstr(res, i, c++); 329 | table.sql_delete = getstr(res, i, c++); 330 | table.sql_update = getstr(res, i, c++); 331 | table.sql_pop = getstr(res, i, c++); 332 | 333 | reorg_one_table(&table, orderby); 334 | } 335 | 336 | cleanup: 337 | PQclear(res); 338 | disconnect(); 339 | termStringInfo(&sql); 340 | return ret; 341 | } 342 | 343 | static int 344 | apply_log(const reorg_table *table, int count) 345 | { 346 | int result; 347 | PGresult *res; 348 | const char *params[6]; 349 | char buffer[12]; 350 | 351 | params[0] = table->sql_peek; 352 | params[1] = table->sql_insert; 353 | params[2] = table->sql_delete; 354 | params[3] = table->sql_update; 355 | params[4] = table->sql_pop; 356 | params[5] = utoa(count, buffer); 357 | 358 | res = execute("SELECT reorg.reorg_apply($1, $2, $3, $4, $5, $6)", 359 | 6, params); 360 | result = atoi(PQgetvalue(res, 0, 0)); 361 | PQclear(res); 362 | 363 | return result; 364 | } 365 | 366 | /* 367 | * Re-organize one table. 368 | */ 369 | static void 370 | reorg_one_table(const reorg_table *table, const char *orderby) 371 | { 372 | PGresult *res; 373 | const char *params[1]; 374 | int num; 375 | int i; 376 | int num_waiting = 0; 377 | char *vxid; 378 | char buffer[12]; 379 | StringInfoData sql; 380 | 381 | initStringInfo(&sql); 382 | 383 | elog(DEBUG2, "---- reorg_one_table ----"); 384 | elog(DEBUG2, "target_name : %s", table->target_name); 385 | elog(DEBUG2, "target_oid : %u", table->target_oid); 386 | elog(DEBUG2, "target_toast : %u", table->target_toast); 387 | elog(DEBUG2, "target_tidx : %u", table->target_tidx); 388 | elog(DEBUG2, "pkid : %u", table->pkid); 389 | elog(DEBUG2, "ckid : %u", table->ckid); 390 | elog(DEBUG2, "create_pktype : %s", table->create_pktype); 391 | elog(DEBUG2, "create_log : %s", table->create_log); 392 | elog(DEBUG2, "create_trigger : %s", table->create_trigger); 393 | elog(DEBUG2, "enable_trigger : %s", table->enable_trigger); 394 | elog(DEBUG2, "create_table : %s", table->create_table); 395 | elog(DEBUG2, "drop_columns : %s", table->drop_columns ? table->drop_columns : "(skipped)"); 396 | elog(DEBUG2, "delete_log : %s", table->delete_log); 397 | elog(DEBUG2, "lock_table : %s", table->lock_table); 398 | elog(DEBUG2, "sql_peek : %s", table->sql_peek); 399 | elog(DEBUG2, "sql_insert : %s", table->sql_insert); 400 | elog(DEBUG2, "sql_delete : %s", table->sql_delete); 401 | elog(DEBUG2, "sql_update : %s", table->sql_update); 402 | elog(DEBUG2, "sql_pop : %s", table->sql_pop); 403 | 404 | /* 405 | * 1. Setup workspaces and a trigger. 406 | */ 407 | elog(DEBUG2, "---- setup ----"); 408 | lock_exclusive(utoa(table->target_oid, buffer), table->lock_table); 409 | 410 | /* 411 | * Check z_reorg_trigger is the trigger executed at last so that 412 | * other before triggers cannot modify triggered tuples. 413 | */ 414 | params[0] = utoa(table->target_oid, buffer); 415 | 416 | res = execute("SELECT reorg.conflicted_triggers($1)", 1, params); 417 | if (PQntuples(res) > 0) 418 | ereport(ERROR, 419 | (errcode(E_PG_COMMAND), 420 | errmsg("trigger %s conflicted for %s", 421 | PQgetvalue(res, 0, 0), table->target_name))); 422 | PQclear(res); 423 | 424 | command(table->create_pktype, 0, NULL); 425 | command(table->create_log, 0, NULL); 426 | command(table->create_trigger, 0, NULL); 427 | command(table->enable_trigger, 0, NULL); 428 | printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.log_%u')", table->target_oid); 429 | command(sql.data, 0, NULL); 430 | command("COMMIT", 0, NULL); 431 | 432 | /* 433 | * Register the table to be dropped on error. We use pktype as 434 | * an advisory lock. The registration should be done after 435 | * the first command succeeds. 436 | */ 437 | pgut_atexit_push(&reorg_cleanup, (void *) table); 438 | 439 | /* 440 | * 2. Copy tuples into temp table. 441 | */ 442 | elog(DEBUG2, "---- copy tuples ----"); 443 | 444 | command("BEGIN ISOLATION LEVEL SERIALIZABLE", 0, NULL); 445 | /* SET work_mem = maintenance_work_mem */ 446 | command("SELECT set_config('work_mem', current_setting('maintenance_work_mem'), true)", 0, NULL); 447 | if (orderby && !orderby[0]) 448 | command("SET LOCAL synchronize_seqscans = off", 0, NULL); 449 | res = execute(SQL_XID_SNAPSHOT, 0, NULL); 450 | vxid = strdup(PQgetvalue(res, 0, 0)); 451 | PQclear(res); 452 | command(table->delete_log, 0, NULL); 453 | command(table->create_table, 0, NULL); 454 | printfStringInfo(&sql, "SELECT reorg.disable_autovacuum('reorg.table_%u')", table->target_oid); 455 | if (table->drop_columns) 456 | command(table->drop_columns, 0, NULL); 457 | command(sql.data, 0, NULL); 458 | command("COMMIT", 0, NULL); 459 | 460 | /* 461 | * 3. Create indexes on temp table. 462 | */ 463 | elog(DEBUG2, "---- create indexes ----"); 464 | 465 | params[0] = utoa(table->target_oid, buffer); 466 | res = execute("SELECT indexrelid," 467 | " reorg.reorg_indexdef(indexrelid, indrelid)," 468 | " indisvalid," 469 | " pg_get_indexdef(indexrelid)" 470 | " FROM pg_index WHERE indrelid = $1", 1, params); 471 | 472 | num = PQntuples(res); 473 | for (i = 0; i < num; i++) 474 | { 475 | reorg_index index; 476 | int c = 0; 477 | const char *isvalid; 478 | const char *indexdef; 479 | 480 | index.target_oid = getoid(res, i, c++); 481 | index.create_index = getstr(res, i, c++); 482 | isvalid = getstr(res, i, c++); 483 | indexdef = getstr(res, i, c++); 484 | 485 | if (isvalid && isvalid[0] == 'f') { 486 | elog(WARNING, "skipping invalid index: %s", indexdef); 487 | continue; 488 | } 489 | 490 | elog(DEBUG2, "[%d]", i); 491 | elog(DEBUG2, "target_oid : %u", index.target_oid); 492 | elog(DEBUG2, "create_index : %s", index.create_index); 493 | 494 | /* 495 | * NOTE: If we want to create multiple indexes in parallel, 496 | * we need to call create_index in multiple connections. 497 | */ 498 | command(index.create_index, 0, NULL); 499 | } 500 | PQclear(res); 501 | 502 | /* 503 | * 4. Apply log to temp table until no tuples are left in the log 504 | * and all of the old transactions are finished. 505 | */ 506 | for (;;) 507 | { 508 | num = apply_log(table, APPLY_COUNT); 509 | if (num > 0) 510 | continue; /* there might be still some tuples, repeat. */ 511 | 512 | /* old transactions still alive ? */ 513 | params[0] = vxid; 514 | res = execute(SQL_XID_ALIVE, 1, params); 515 | num = PQntuples(res); 516 | 517 | if (num > 0) 518 | { 519 | /* Wait for old transactions. 520 | * Only display the message below when the number of 521 | * transactions we are waiting on changes (presumably, 522 | * num_waiting should only go down), so as not to 523 | * be too noisy. 524 | */ 525 | if (num != num_waiting) 526 | { 527 | elog(NOTICE, "Waiting for %d transactions to finish. First PID: %s", num, PQgetvalue(res, 0, 0)); 528 | num_waiting = num; 529 | } 530 | 531 | PQclear(res); 532 | sleep(1); 533 | continue; 534 | } 535 | else 536 | { 537 | /* All old transactions are finished; 538 | * go to next step. */ 539 | PQclear(res); 540 | break; 541 | } 542 | } 543 | 544 | /* 545 | * 5. Swap. 546 | */ 547 | elog(DEBUG2, "---- swap ----"); 548 | lock_exclusive(utoa(table->target_oid, buffer), table->lock_table); 549 | apply_log(table, 0); 550 | params[0] = utoa(table->target_oid, buffer); 551 | command("SELECT reorg.reorg_swap($1)", 1, params); 552 | command("COMMIT", 0, NULL); 553 | 554 | /* 555 | * 6. Drop. 556 | */ 557 | elog(DEBUG2, "---- drop ----"); 558 | 559 | command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); 560 | params[0] = utoa(table->target_oid, buffer); 561 | command("SELECT reorg.reorg_drop($1)", 1, params); 562 | command("COMMIT", 0, NULL); 563 | 564 | pgut_atexit_pop(&reorg_cleanup, (void *) table); 565 | free(vxid); 566 | 567 | /* 568 | * 7. Analyze. 569 | * Note that cleanup hook has been already uninstalled here because analyze 570 | * is not an important operation; No clean up even if failed. 571 | */ 572 | if (analyze) 573 | { 574 | elog(DEBUG2, "---- analyze ----"); 575 | 576 | command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); 577 | printfStringInfo(&sql, "ANALYZE %s", table->target_name); 578 | command(sql.data, 0, NULL); 579 | command("COMMIT", 0, NULL); 580 | } 581 | 582 | termStringInfo(&sql); 583 | } 584 | 585 | /* 586 | * Try acquire a table lock but avoid long time locks when conflict. 587 | */ 588 | static void 589 | lock_exclusive(const char *relid, const char *lock_query) 590 | { 591 | time_t start = time(NULL); 592 | int i; 593 | 594 | for (i = 1; ; i++) 595 | { 596 | time_t duration; 597 | char sql[1024]; 598 | PGresult *res; 599 | int wait_msec; 600 | 601 | command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL); 602 | 603 | duration = time(NULL) - start; 604 | if (duration > wait_timeout) 605 | { 606 | const char *cancel_query; 607 | if (PQserverVersion(connection) >= 80400 && 608 | duration > wait_timeout * 2) 609 | { 610 | elog(WARNING, "terminating conflicted backends"); 611 | cancel_query = 612 | "SELECT pg_terminate_backend(pid) FROM pg_locks" 613 | " WHERE locktype = 'relation'" 614 | " AND relation = $1 AND pid <> pg_backend_pid()"; 615 | } 616 | else 617 | { 618 | elog(WARNING, "canceling conflicted backends"); 619 | cancel_query = 620 | "SELECT pg_cancel_backend(pid) FROM pg_locks" 621 | " WHERE locktype = 'relation'" 622 | " AND relation = $1 AND pid <> pg_backend_pid()"; 623 | } 624 | 625 | command(cancel_query, 1, &relid); 626 | } 627 | 628 | /* wait for a while to lock the table. */ 629 | wait_msec = Min(1000, i * 100); 630 | snprintf(sql, lengthof(sql), "SET LOCAL statement_timeout = %d", wait_msec); 631 | command(sql, 0, NULL); 632 | 633 | res = execute_elevel(lock_query, 0, NULL, DEBUG2); 634 | if (PQresultStatus(res) == PGRES_COMMAND_OK) 635 | { 636 | PQclear(res); 637 | break; 638 | } 639 | else if (sqlstate_equals(res, SQLSTATE_QUERY_CANCELED)) 640 | { 641 | /* retry if lock conflicted */ 642 | PQclear(res); 643 | command("ROLLBACK", 0, NULL); 644 | continue; 645 | } 646 | else 647 | { 648 | /* exit otherwise */ 649 | printf("%s", PQerrorMessage(connection)); 650 | PQclear(res); 651 | exit(1); 652 | } 653 | } 654 | 655 | command("RESET statement_timeout", 0, NULL); 656 | } 657 | 658 | /* 659 | * The userdata pointing a table being re-organized. We need to cleanup temp 660 | * objects before the program exits. 661 | */ 662 | static void 663 | reorg_cleanup(bool fatal, void *userdata) 664 | { 665 | const reorg_table *table = (const reorg_table *) userdata; 666 | 667 | if (fatal) 668 | { 669 | fprintf(stderr, "!!!FATAL ERROR!!! Please refer to the manual.\n\n"); 670 | } 671 | else 672 | { 673 | char buffer[12]; 674 | const char *params[1]; 675 | 676 | /* Rollback current transaction */ 677 | if (connection) 678 | command("ROLLBACK", 0, NULL); 679 | 680 | /* Try reconnection if not available. */ 681 | if (PQstatus(connection) != CONNECTION_OK) 682 | reconnect(ERROR); 683 | 684 | /* do cleanup */ 685 | params[0] = utoa(table->target_oid, buffer); 686 | command("SELECT reorg.reorg_drop($1)", 1, params); 687 | } 688 | } 689 | 690 | void 691 | pgut_help(bool details) 692 | { 693 | printf("%s re-organizes a PostgreSQL database.\n\n", PROGRAM_NAME); 694 | printf("Usage:\n"); 695 | printf(" %s [OPTION]... [DBNAME]\n", PROGRAM_NAME); 696 | 697 | if (!details) 698 | return; 699 | 700 | printf("Options:\n"); 701 | printf(" -a, --all reorg all databases\n"); 702 | printf(" -n, --no-order do vacuum full instead of cluster\n"); 703 | printf(" -o, --order-by=columns order by columns instead of cluster keys\n"); 704 | printf(" -t, --table=TABLE reorg specific table only\n"); 705 | printf(" -T, --wait-timeout=secs timeout to cancel other backends on conflict\n"); 706 | printf(" -Z, --no-analyze don't analyze at end\n"); 707 | } 708 | -------------------------------------------------------------------------------- /bin/pgut/pgut-fe.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * pgut-fe.c 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | *------------------------------------------------------------------------- 7 | */ 8 | 9 | #define FRONTEND 10 | #include "pgut-fe.h" 11 | 12 | #ifdef HAVE_GETOPT_H 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | char *dbname = NULL; 19 | char *host = NULL; 20 | char *port = NULL; 21 | char *username = NULL; 22 | char *password = NULL; 23 | YesNo prompt_password = DEFAULT; 24 | 25 | PGconn *connection = NULL; 26 | 27 | static bool parse_pair(const char buffer[], char key[], char value[]); 28 | static char *get_username(void); 29 | 30 | /* 31 | * the result is also available with the global variable 'connection'. 32 | */ 33 | void 34 | reconnect(int elevel) 35 | { 36 | StringInfoData buf; 37 | char *new_password; 38 | 39 | disconnect(); 40 | initStringInfo(&buf); 41 | if (dbname && dbname[0]) 42 | appendStringInfo(&buf, "dbname=%s ", dbname); 43 | if (host && host[0]) 44 | appendStringInfo(&buf, "host=%s ", host); 45 | if (port && port[0]) 46 | appendStringInfo(&buf, "port=%s ", port); 47 | if (username && username[0]) 48 | appendStringInfo(&buf, "user=%s ", username); 49 | if (password && password[0]) 50 | appendStringInfo(&buf, "password=%s ", password); 51 | 52 | connection = pgut_connect(buf.data, prompt_password, elevel); 53 | 54 | /* update password */ 55 | if (connection) 56 | { 57 | new_password = PQpass(connection); 58 | if (new_password && new_password[0] && 59 | (password == NULL || strcmp(new_password, password) != 0)) 60 | { 61 | free(password); 62 | password = pgut_strdup(new_password); 63 | } 64 | } 65 | 66 | termStringInfo(&buf); 67 | } 68 | 69 | void 70 | disconnect(void) 71 | { 72 | if (connection) 73 | { 74 | pgut_disconnect(connection); 75 | connection = NULL; 76 | } 77 | } 78 | 79 | static void 80 | option_from_env(pgut_option options[]) 81 | { 82 | size_t i; 83 | 84 | for (i = 0; options && options[i].type; i++) 85 | { 86 | pgut_option *opt = &options[i]; 87 | char name[256]; 88 | size_t j; 89 | const char *s; 90 | const char *value; 91 | 92 | if (opt->source > SOURCE_ENV || 93 | opt->allowed == SOURCE_DEFAULT || opt->allowed > SOURCE_ENV) 94 | continue; 95 | 96 | for (s = opt->lname, j = 0; *s && j < lengthof(name) - 1; s++, j++) 97 | { 98 | if (strchr("-_ ", *s)) 99 | name[j] = '_'; /* - to _ */ 100 | else 101 | name[j] = toupper(*s); 102 | } 103 | name[j] = '\0'; 104 | 105 | if ((value = getenv(name)) != NULL) 106 | pgut_setopt(opt, value, SOURCE_ENV); 107 | } 108 | } 109 | 110 | /* compare two strings ignore cases and ignore -_ */ 111 | bool 112 | pgut_keyeq(const char *lhs, const char *rhs) 113 | { 114 | for (; *lhs && *rhs; lhs++, rhs++) 115 | { 116 | if (strchr("-_ ", *lhs)) 117 | { 118 | if (!strchr("-_ ", *rhs)) 119 | return false; 120 | } 121 | else if (ToLower(*lhs) != ToLower(*rhs)) 122 | return false; 123 | } 124 | 125 | return *lhs == '\0' && *rhs == '\0'; 126 | } 127 | 128 | void 129 | pgut_setopt(pgut_option *opt, const char *optarg, pgut_optsrc src) 130 | { 131 | const char *message; 132 | 133 | if (opt == NULL) 134 | { 135 | fprintf(stderr, "Try \"%s --help\" for more information.\n", PROGRAM_NAME); 136 | exit(EINVAL); 137 | } 138 | 139 | if (opt->source > src) 140 | { 141 | /* high prior value has been set already. */ 142 | return; 143 | } 144 | else if (src >= SOURCE_CMDLINE && opt->source >= src) 145 | { 146 | /* duplicated option in command line */ 147 | message = "specified only once"; 148 | } 149 | else 150 | { 151 | /* can be overwritten if non-command line source */ 152 | opt->source = src; 153 | 154 | switch (opt->type) 155 | { 156 | case 'b': 157 | case 'B': 158 | if (optarg == NULL) 159 | { 160 | *((bool *) opt->var) = (opt->type == 'b'); 161 | return; 162 | } 163 | else if (parse_bool(optarg, (bool *) opt->var)) 164 | { 165 | return; 166 | } 167 | message = "a boolean"; 168 | break; 169 | case 'f': 170 | ((pgut_optfn) opt->var)(opt, optarg); 171 | return; 172 | case 'i': 173 | if (parse_int32(optarg, opt->var)) 174 | return; 175 | message = "a 32bit signed integer"; 176 | break; 177 | case 'u': 178 | if (parse_uint32(optarg, opt->var)) 179 | return; 180 | message = "a 32bit unsigned integer"; 181 | break; 182 | case 'I': 183 | if (parse_int64(optarg, opt->var)) 184 | return; 185 | message = "a 64bit signed integer"; 186 | break; 187 | case 'U': 188 | if (parse_uint64(optarg, opt->var)) 189 | return; 190 | message = "a 64bit unsigned integer"; 191 | break; 192 | case 's': 193 | if (opt->source != SOURCE_DEFAULT) 194 | free(*(char **) opt->var); 195 | *(char **) opt->var = pgut_strdup(optarg); 196 | return; 197 | case 't': 198 | if (parse_time(optarg, opt->var)) 199 | return; 200 | message = "a time"; 201 | break; 202 | case 'y': 203 | case 'Y': 204 | if (optarg == NULL) 205 | { 206 | *(YesNo *) opt->var = (opt->type == 'y' ? YES : NO); 207 | return; 208 | } 209 | else 210 | { 211 | bool value; 212 | if (parse_bool(optarg, &value)) 213 | { 214 | *(YesNo *) opt->var = (value ? YES : NO); 215 | return; 216 | } 217 | } 218 | message = "a boolean"; 219 | break; 220 | default: 221 | ereport(ERROR, 222 | (errcode(EINVAL), 223 | errmsg("invalid option type: %c", opt->type))); 224 | return; /* keep compiler quiet */ 225 | } 226 | } 227 | 228 | if (isprint(opt->sname)) 229 | ereport(ERROR, 230 | (errcode(EINVAL), 231 | errmsg("option -%c, --%s should be %s: '%s'", 232 | opt->sname, opt->lname, message, optarg))); 233 | else 234 | ereport(ERROR, 235 | (errcode(EINVAL), 236 | errmsg("option --%s should be %s: '%s'", 237 | opt->lname, message, optarg))); 238 | } 239 | 240 | /* 241 | * Get configuration from configuration file. 242 | */ 243 | void 244 | pgut_readopt(const char *path, pgut_option options[], int elevel) 245 | { 246 | FILE *fp; 247 | char buf[1024]; 248 | char key[1024]; 249 | char value[1024]; 250 | 251 | if (!options) 252 | return; 253 | 254 | if ((fp = pgut_fopen(path, "Rt")) == NULL) 255 | return; 256 | 257 | while (fgets(buf, lengthof(buf), fp)) 258 | { 259 | size_t i; 260 | 261 | for (i = strlen(buf); i > 0 && IsSpace(buf[i - 1]); i--) 262 | buf[i - 1] = '\0'; 263 | 264 | if (parse_pair(buf, key, value)) 265 | { 266 | for (i = 0; options[i].type; i++) 267 | { 268 | pgut_option *opt = &options[i]; 269 | 270 | if (pgut_keyeq(key, opt->lname)) 271 | { 272 | if (opt->allowed == SOURCE_DEFAULT || 273 | opt->allowed > SOURCE_FILE) 274 | elog(elevel, "option %s cannot specified in file", opt->lname); 275 | else if (opt->source <= SOURCE_FILE) 276 | pgut_setopt(opt, value, SOURCE_FILE); 277 | break; 278 | } 279 | } 280 | if (!options[i].type) 281 | elog(elevel, "invalid option \"%s\"", key); 282 | } 283 | } 284 | 285 | fclose(fp); 286 | } 287 | 288 | static const char * 289 | skip_space(const char *str, const char *line) 290 | { 291 | while (IsSpace(*str)) { str++; } 292 | return str; 293 | } 294 | 295 | static const char * 296 | get_next_token(const char *src, char *dst, const char *line) 297 | { 298 | const char *s; 299 | size_t i; 300 | size_t j; 301 | 302 | if ((s = skip_space(src, line)) == NULL) 303 | return NULL; 304 | 305 | /* parse quoted string */ 306 | if (*s == '\'') 307 | { 308 | s++; 309 | for (i = 0, j = 0; s[i] != '\0'; i++) 310 | { 311 | if (s[i] == '\\') 312 | { 313 | i++; 314 | switch (s[i]) 315 | { 316 | case 'b': 317 | dst[j] = '\b'; 318 | break; 319 | case 'f': 320 | dst[j] = '\f'; 321 | break; 322 | case 'n': 323 | dst[j] = '\n'; 324 | break; 325 | case 'r': 326 | dst[j] = '\r'; 327 | break; 328 | case 't': 329 | dst[j] = '\t'; 330 | break; 331 | case '0': 332 | case '1': 333 | case '2': 334 | case '3': 335 | case '4': 336 | case '5': 337 | case '6': 338 | case '7': 339 | { 340 | int k; 341 | long octVal = 0; 342 | 343 | for (k = 0; 344 | s[i + k] >= '0' && s[i + k] <= '7' && k < 3; 345 | k++) 346 | octVal = (octVal << 3) + (s[i + k] - '0'); 347 | i += k - 1; 348 | dst[j] = ((char) octVal); 349 | } 350 | break; 351 | default: 352 | dst[j] = s[i]; 353 | break; 354 | } 355 | } 356 | else if (s[i] == '\'') 357 | { 358 | i++; 359 | /* doubled quote becomes just one quote */ 360 | if (s[i] == '\'') 361 | dst[j] = s[i]; 362 | else 363 | break; 364 | } 365 | else 366 | dst[j] = s[i]; 367 | j++; 368 | } 369 | } 370 | else 371 | { 372 | i = j = strcspn(s, "# \n\r\t\v"); 373 | memcpy(dst, s, j); 374 | } 375 | 376 | dst[j] = '\0'; 377 | return s + i; 378 | } 379 | 380 | static bool 381 | parse_pair(const char buffer[], char key[], char value[]) 382 | { 383 | const char *start; 384 | const char *end; 385 | 386 | key[0] = value[0] = '\0'; 387 | 388 | /* 389 | * parse key 390 | */ 391 | start = buffer; 392 | if ((start = skip_space(start, buffer)) == NULL) 393 | return false; 394 | 395 | end = start + strcspn(start, "=# \n\r\t\v"); 396 | 397 | /* skip blank buffer */ 398 | if (end - start <= 0) 399 | { 400 | if (*start == '=') 401 | elog(WARNING, "syntax error in \"%s\"", buffer); 402 | return false; 403 | } 404 | 405 | /* key found */ 406 | strncpy(key, start, end - start); 407 | key[end - start] = '\0'; 408 | 409 | /* find key and value split char */ 410 | if ((start = skip_space(end, buffer)) == NULL) 411 | return false; 412 | 413 | if (*start != '=') 414 | { 415 | elog(WARNING, "syntax error in \"%s\"", buffer); 416 | return false; 417 | } 418 | 419 | start++; 420 | 421 | /* 422 | * parse value 423 | */ 424 | if ((end = get_next_token(start, value, buffer)) == NULL) 425 | return false; 426 | 427 | if ((start = skip_space(end, buffer)) == NULL) 428 | return false; 429 | 430 | if (*start != '\0' && *start != '#') 431 | { 432 | elog(WARNING, "syntax error in \"%s\"", buffer); 433 | return false; 434 | } 435 | 436 | return true; 437 | } 438 | 439 | /* 440 | * execute - Execute a SQL and return the result. 441 | */ 442 | PGresult * 443 | execute(const char *query, int nParams, const char **params) 444 | { 445 | return pgut_execute(connection, query, nParams, params); 446 | } 447 | 448 | PGresult * 449 | execute_elevel(const char *query, int nParams, const char **params, int elevel) 450 | { 451 | return pgut_execute_elevel(connection, query, nParams, params, elevel); 452 | } 453 | 454 | /* 455 | * command - Execute a SQL and discard the result. 456 | */ 457 | ExecStatusType 458 | command(const char *query, int nParams, const char **params) 459 | { 460 | return pgut_command(connection, query, nParams, params); 461 | } 462 | 463 | static void 464 | set_elevel(pgut_option *opt, const char *arg) 465 | { 466 | pgut_log_level = parse_elevel(arg); 467 | } 468 | 469 | static pgut_option default_options[] = 470 | { 471 | { 'b', 'e', "echo" , &pgut_echo }, 472 | { 'f', 'E', "elevel" , set_elevel }, 473 | { 's', 'd', "dbname" , &dbname }, 474 | { 's', 'h', "host" , &host }, 475 | { 's', 'p', "port" , &port }, 476 | { 's', 'U', "username" , &username }, 477 | { 'Y', 'w', "no-password" , &prompt_password }, 478 | { 'y', 'W', "password" , &prompt_password }, 479 | { 0 } 480 | }; 481 | 482 | static size_t 483 | option_length(const pgut_option opts[]) 484 | { 485 | size_t len; 486 | for (len = 0; opts && opts[len].type; len++) { } 487 | return len; 488 | } 489 | 490 | static pgut_option * 491 | option_find(int c, pgut_option opts1[], pgut_option opts2[]) 492 | { 493 | size_t i; 494 | 495 | for (i = 0; opts1 && opts1[i].type; i++) 496 | if (opts1[i].sname == c) 497 | return &opts1[i]; 498 | for (i = 0; opts2 && opts2[i].type; i++) 499 | if (opts2[i].sname == c) 500 | return &opts2[i]; 501 | 502 | return NULL; /* not found */ 503 | } 504 | 505 | /* 506 | * Returns the current user name. 507 | */ 508 | static char * 509 | get_username(void) 510 | { 511 | char *ret; 512 | 513 | #ifndef WIN32 514 | struct passwd *pw; 515 | 516 | pw = getpwuid(geteuid()); 517 | ret = (pw ? pw->pw_name : NULL); 518 | #else 519 | static char username[128]; /* remains after function execute */ 520 | DWORD len = sizeof(username) - 1; 521 | 522 | if (GetUserNameA(username, &len)) 523 | ret = username; 524 | else 525 | { 526 | _dosmaperr(GetLastError()); 527 | ret = NULL; 528 | } 529 | #endif 530 | 531 | if (ret == NULL) 532 | ereport(ERROR, 533 | (errcode_errno(), 534 | errmsg("could not get current user name: "))); 535 | return ret; 536 | } 537 | 538 | static int 539 | option_has_arg(char type) 540 | { 541 | switch (type) 542 | { 543 | case 'b': 544 | case 'B': 545 | case 'y': 546 | case 'Y': 547 | return no_argument; 548 | default: 549 | return required_argument; 550 | } 551 | } 552 | 553 | static void 554 | option_copy(struct option dst[], const pgut_option opts[], size_t len) 555 | { 556 | size_t i; 557 | 558 | for (i = 0; i < len; i++) 559 | { 560 | dst[i].name = opts[i].lname; 561 | dst[i].has_arg = option_has_arg(opts[i].type); 562 | dst[i].flag = NULL; 563 | dst[i].val = opts[i].sname; 564 | } 565 | } 566 | 567 | static struct option * 568 | option_merge(const pgut_option opts1[], const pgut_option opts2[]) 569 | { 570 | struct option *result; 571 | size_t len1 = option_length(opts1); 572 | size_t len2 = option_length(opts2); 573 | size_t n = len1 + len2; 574 | 575 | result = pgut_newarray(struct option, n + 1); 576 | option_copy(result, opts1, len1); 577 | option_copy(result + len1, opts2, len2); 578 | memset(&result[n], 0, sizeof(pgut_option)); 579 | 580 | return result; 581 | } 582 | 583 | static char * 584 | longopts_to_optstring(const struct option opts[]) 585 | { 586 | size_t len; 587 | char *result; 588 | char *s; 589 | 590 | for (len = 0; opts[len].name; len++) { } 591 | result = pgut_malloc(len * 2 + 1); 592 | 593 | s = result; 594 | for (len = 0; opts[len].name; len++) 595 | { 596 | if (!isprint(opts[len].val)) 597 | continue; 598 | *s++ = opts[len].val; 599 | if (opts[len].has_arg != no_argument) 600 | *s++ = ':'; 601 | } 602 | *s = '\0'; 603 | 604 | return result; 605 | } 606 | 607 | int 608 | pgut_getopt(int argc, char **argv, pgut_option options[]) 609 | { 610 | int c; 611 | int optindex = 0; 612 | char *optstring; 613 | struct option *longopts; 614 | pgut_option *opt; 615 | 616 | pgut_init(argc, argv); 617 | 618 | /* Help message and version are handled at first. */ 619 | if (argc > 1) 620 | { 621 | if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) 622 | { 623 | help(true); 624 | exit(1); 625 | } 626 | if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) 627 | { 628 | printf("%s %s\n", PROGRAM_NAME, PROGRAM_VERSION); 629 | exit(1); 630 | } 631 | if (strcmp(argv[1], "--configuration") == 0) 632 | { 633 | printf("%s\n", PG_VERSION_STR); 634 | exit(0); 635 | } 636 | } 637 | 638 | /* Merge default and user options. */ 639 | longopts = option_merge(default_options, options); 640 | optstring = longopts_to_optstring(longopts); 641 | 642 | /* Assign named options */ 643 | while ((c = getopt_long(argc, argv, optstring, longopts, &optindex)) != -1) 644 | { 645 | opt = option_find(c, default_options, options); 646 | pgut_setopt(opt, optarg, SOURCE_CMDLINE); 647 | } 648 | 649 | /* Read environment variables */ 650 | option_from_env(options); 651 | (void) (dbname || 652 | (dbname = getenv("PGDATABASE")) || 653 | (dbname = getenv("PGUSER")) || 654 | (dbname = get_username())); 655 | 656 | return optind; 657 | } 658 | 659 | void 660 | help(bool details) 661 | { 662 | pgut_help(details); 663 | 664 | if (details) 665 | { 666 | printf("\nConnection options:\n"); 667 | printf(" -d, --dbname=DBNAME database to connect\n"); 668 | printf(" -h, --host=HOSTNAME database server host or socket directory\n"); 669 | printf(" -p, --port=PORT database server port\n"); 670 | printf(" -U, --username=USERNAME user name to connect as\n"); 671 | printf(" -w, --no-password never prompt for password\n"); 672 | printf(" -W, --password force password prompt\n"); 673 | } 674 | 675 | printf("\nGeneric options:\n"); 676 | if (details) 677 | { 678 | printf(" -e, --echo echo queries\n"); 679 | printf(" -E, --elevel=LEVEL set output message level\n"); 680 | } 681 | printf(" --help show this help, then exit\n"); 682 | printf(" --version output version information, then exit\n"); 683 | 684 | if (details && (PROGRAM_URL || PROGRAM_EMAIL)) 685 | { 686 | printf("\n"); 687 | if (PROGRAM_URL) 688 | printf("Read the website for details. <%s>\n", PROGRAM_URL); 689 | if (PROGRAM_EMAIL) 690 | printf("Report bugs to <%s>.\n", PROGRAM_EMAIL); 691 | } 692 | } 693 | -------------------------------------------------------------------------------- /bin/pgut/pgut-fe.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * pgut-fe.h 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | *------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef PGUT_FE_H 10 | #define PGUT_FE_H 11 | 12 | #include "pgut.h" 13 | 14 | typedef enum pgut_optsrc 15 | { 16 | SOURCE_DEFAULT, 17 | SOURCE_ENV, 18 | SOURCE_FILE, 19 | SOURCE_CMDLINE, 20 | SOURCE_CONST 21 | } pgut_optsrc; 22 | 23 | /* 24 | * type: 25 | * b: bool (true) 26 | * B: bool (false) 27 | * f: pgut_optfn 28 | * i: 32bit signed integer 29 | * u: 32bit unsigned integer 30 | * I: 64bit signed integer 31 | * U: 64bit unsigned integer 32 | * s: string 33 | * t: time_t 34 | * y: YesNo (YES) 35 | * Y: YesNo (NO) 36 | */ 37 | typedef struct pgut_option 38 | { 39 | char type; 40 | char sname; /* short name */ 41 | const char *lname; /* long name */ 42 | void *var; /* pointer to variable */ 43 | pgut_optsrc allowed; /* allowed source */ 44 | pgut_optsrc source; /* actual source */ 45 | } pgut_option; 46 | 47 | typedef void (*pgut_optfn) (pgut_option *opt, const char *arg); 48 | 49 | 50 | extern char *dbname; 51 | extern char *host; 52 | extern char *port; 53 | extern char *username; 54 | extern char *password; 55 | extern YesNo prompt_password; 56 | 57 | extern PGconn *connection; 58 | 59 | extern void pgut_help(bool details); 60 | extern void help(bool details); 61 | 62 | extern void disconnect(void); 63 | extern void reconnect(int elevel); 64 | extern PGresult *execute(const char *query, int nParams, const char **params); 65 | extern PGresult *execute_elevel(const char *query, int nParams, const char **params, int elevel); 66 | extern ExecStatusType command(const char *query, int nParams, const char **params); 67 | 68 | extern int pgut_getopt(int argc, char **argv, pgut_option options[]); 69 | extern void pgut_readopt(const char *path, pgut_option options[], int elevel); 70 | extern void pgut_setopt(pgut_option *opt, const char *optarg, pgut_optsrc src); 71 | extern bool pgut_keyeq(const char *lhs, const char *rhs); 72 | 73 | #endif /* PGUT_FE_H */ 74 | -------------------------------------------------------------------------------- /bin/pgut/pgut.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * pgut.h 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | *------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef PGUT_H 10 | #define PGUT_H 11 | 12 | #include "c.h" 13 | #include 14 | 15 | #ifndef WIN32 16 | #include 17 | #include 18 | #endif 19 | 20 | #include "libpq-fe.h" 21 | #include "pqexpbuffer.h" 22 | #include "utils/elog.h" 23 | 24 | #define INFINITE_STR "INFINITE" 25 | 26 | typedef enum YesNo 27 | { 28 | DEFAULT, 29 | NO, 30 | YES 31 | } YesNo; 32 | 33 | typedef void (*pgut_atexit_callback)(bool fatal, void *userdata); 34 | 35 | /* 36 | * pgut client variables and functions 37 | */ 38 | extern const char *PROGRAM_NAME; 39 | extern const char *PROGRAM_VERSION; 40 | extern const char *PROGRAM_URL; 41 | extern const char *PROGRAM_EMAIL; 42 | 43 | /* 44 | * pgut framework variables and functions 45 | */ 46 | extern bool interrupted; 47 | extern int pgut_log_level; 48 | extern int pgut_abort_level; 49 | extern bool pgut_echo; 50 | 51 | extern void pgut_init(int argc, char **argv); 52 | extern void pgut_atexit_push(pgut_atexit_callback callback, void *userdata); 53 | extern void pgut_atexit_pop(pgut_atexit_callback callback, void *userdata); 54 | extern void pgut_putenv(const char *key, const char *value); 55 | 56 | /* 57 | * Database connections 58 | */ 59 | extern PGconn *pgut_connect(const char *info, YesNo prompt, int elevel); 60 | extern void pgut_disconnect(PGconn *conn); 61 | extern void pgut_disconnect_all(void); 62 | extern PGresult *pgut_execute(PGconn* conn, const char *query, int nParams, const char **params); 63 | PGresult *pgut_execute_elevel(PGconn* conn, const char *query, int nParams, const char **params, int elevel); 64 | extern ExecStatusType pgut_command(PGconn* conn, const char *query, int nParams, const char **params); 65 | extern bool pgut_commit(PGconn *conn); 66 | extern void pgut_rollback(PGconn *conn); 67 | extern bool pgut_send(PGconn* conn, const char *query, int nParams, const char **params); 68 | extern int pgut_wait(int num, PGconn *connections[], struct timeval *timeout); 69 | 70 | /* 71 | * memory allocators 72 | */ 73 | extern void *pgut_malloc(size_t size); 74 | extern void *pgut_realloc(void *p, size_t size); 75 | extern char *pgut_strdup(const char *str); 76 | extern char *strdup_with_len(const char *str, size_t len); 77 | extern char *strdup_trim(const char *str); 78 | 79 | #define pgut_new(type) ((type *) pgut_malloc(sizeof(type))) 80 | #define pgut_newarray(type, n) ((type *) pgut_malloc(sizeof(type) * (n))) 81 | #define pgut_newvar(type, m, n) ((type *) pgut_malloc(offsetof(type, m) + (n))) 82 | 83 | /* 84 | * file operations 85 | */ 86 | extern FILE *pgut_fopen(const char *path, const char *mode); 87 | extern bool pgut_mkdir(const char *path); 88 | 89 | /* 90 | * elog 91 | */ 92 | #define E_PG_CONNECT (-1) /* PostgreSQL connection error */ 93 | #define E_PG_COMMAND (-2) /* PostgreSQL query or command error */ 94 | 95 | #undef elog 96 | #undef ereport 97 | #define ereport(elevel, rest) \ 98 | (pgut_errstart(elevel) ? (pgut_errfinish rest) : (void) 0) 99 | 100 | extern void elog(int elevel, const char *fmt, ...) 101 | __attribute__((format(printf, 2, 3))); 102 | extern const char *format_elevel(int elevel); 103 | extern int parse_elevel(const char *value); 104 | extern int errcode_errno(void); 105 | extern bool log_required(int elevel, int log_min_level); 106 | extern bool pgut_errstart(int elevel); 107 | extern void pgut_errfinish(int dummy, ...); 108 | extern void pgut_error(int elevel, int code, const char *msg, const char *detail); 109 | 110 | /* 111 | * CHECK_FOR_INTERRUPTS 112 | */ 113 | #undef CHECK_FOR_INTERRUPTS 114 | extern void CHECK_FOR_INTERRUPTS(void); 115 | 116 | /* 117 | * Assert 118 | */ 119 | #undef Assert 120 | #undef AssertArg 121 | #undef AssertMacro 122 | 123 | #ifdef USE_ASSERT_CHECKING 124 | #define Assert(x) assert(x) 125 | #define AssertArg(x) assert(x) 126 | #define AssertMacro(x) assert(x) 127 | #else 128 | #define Assert(x) ((void) 0) 129 | #define AssertArg(x) ((void) 0) 130 | #define AssertMacro(x) ((void) 0) 131 | #endif 132 | 133 | /* 134 | * StringInfo and string operations 135 | */ 136 | #define STRINGINFO_H 137 | 138 | #define StringInfoData PQExpBufferData 139 | #define StringInfo PQExpBuffer 140 | #define makeStringInfo createPQExpBuffer 141 | #define initStringInfo initPQExpBuffer 142 | #define freeStringInfo destroyPQExpBuffer 143 | #define termStringInfo termPQExpBuffer 144 | #define resetStringInfo resetPQExpBuffer 145 | #define enlargeStringInfo enlargePQExpBuffer 146 | #define printfStringInfo printfPQExpBuffer /* reset + append */ 147 | #define appendStringInfo appendPQExpBuffer 148 | #define appendStringInfoString appendPQExpBufferStr 149 | #define appendStringInfoChar appendPQExpBufferChar 150 | #define appendBinaryStringInfo appendBinaryPQExpBuffer 151 | 152 | extern bool appendStringInfoVA(StringInfo str, const char *fmt, va_list args) 153 | __attribute__((format(printf, 2, 0))); 154 | extern int appendStringInfoFile(StringInfo str, FILE *fp); 155 | extern int appendStringInfoFd(StringInfo str, int fd); 156 | 157 | extern bool parse_bool(const char *value, bool *result); 158 | extern bool parse_bool_with_len(const char *value, size_t len, bool *result); 159 | extern bool parse_int32(const char *value, int32 *result); 160 | extern bool parse_uint32(const char *value, uint32 *result); 161 | extern bool parse_int64(const char *value, int64 *result); 162 | extern bool parse_uint64(const char *value, uint64 *result); 163 | extern bool parse_time(const char *value, time_t *time); 164 | 165 | #define IsSpace(c) (isspace((unsigned char)(c))) 166 | #define IsAlpha(c) (isalpha((unsigned char)(c))) 167 | #define IsAlnum(c) (isalnum((unsigned char)(c))) 168 | #define IsIdentHead(c) (IsAlpha(c) || (c) == '_') 169 | #define IsIdentBody(c) (IsAlnum(c) || (c) == '_') 170 | #define ToLower(c) (tolower((unsigned char)(c))) 171 | #define ToUpper(c) (toupper((unsigned char)(c))) 172 | 173 | /* 174 | * socket operations 175 | */ 176 | extern int wait_for_socket(int sock, struct timeval *timeout); 177 | extern int wait_for_sockets(int nfds, fd_set *fds, struct timeval *timeout); 178 | 179 | /* 180 | * import from postgres.h and catalog/genbki.h in 8.4 181 | */ 182 | #if PG_VERSION_NUM < 80400 183 | 184 | typedef unsigned long Datum; 185 | typedef struct MemoryContextData *MemoryContext; 186 | 187 | #define CATALOG(name,oid) typedef struct CppConcat(FormData_,name) 188 | #define BKI_BOOTSTRAP 189 | #define BKI_SHARED_RELATION 190 | #define BKI_WITHOUT_OIDS 191 | #define DATA(x) extern int no_such_variable 192 | #define DESCR(x) extern int no_such_variable 193 | #define SHDESCR(x) extern int no_such_variable 194 | typedef int aclitem; 195 | 196 | #endif 197 | 198 | #ifdef WIN32 199 | extern int sleep(unsigned int seconds); 200 | extern int usleep(unsigned int usec); 201 | #endif 202 | 203 | #endif /* PGUT_H */ 204 | -------------------------------------------------------------------------------- /bin/sql/init-extension.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | \set ECHO none 3 | CREATE EXTENSION pg_reorg; 4 | \set ECHO all 5 | RESET client_min_messages; 6 | -------------------------------------------------------------------------------- /bin/sql/init-legacy.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | \set ECHO none 3 | \i ../lib/pg_reorg.sql 4 | \set ECHO all 5 | RESET client_min_messages; 6 | -------------------------------------------------------------------------------- /bin/sql/reorg.sql: -------------------------------------------------------------------------------- 1 | SET client_min_messages = warning; 2 | -- 3 | -- create table. 4 | -- 5 | CREATE TABLE tbl_cluster ( 6 | col1 int, 7 | "time" timestamp, 8 | ","")" text, 9 | PRIMARY KEY (","")", col1) WITH (fillfactor = 75) 10 | ) WITH (fillfactor = 70); 11 | 12 | CREATE INDEX ","") cluster" ON tbl_cluster ("time", length(","")"), ","")" text_pattern_ops) WITH (fillfactor = 75); 13 | ALTER TABLE tbl_cluster CLUSTER ON ","") cluster"; 14 | 15 | CREATE TABLE tbl_only_pkey ( 16 | col1 int PRIMARY KEY, 17 | ","")" text 18 | ); 19 | 20 | CREATE TABLE tbl_only_ckey ( 21 | col1 int, 22 | col2 timestamp, 23 | ","")" text 24 | ) WITH (fillfactor = 70); 25 | 26 | CREATE INDEX cidx_only_ckey ON tbl_only_ckey (col2, ","")"); 27 | ALTER TABLE tbl_only_ckey CLUSTER ON cidx_only_ckey; 28 | 29 | CREATE TABLE tbl_gistkey ( 30 | id integer PRIMARY KEY, 31 | c circle 32 | ); 33 | 34 | CREATE INDEX cidx_circle ON tbl_gistkey USING gist (c); 35 | ALTER TABLE tbl_gistkey CLUSTER ON cidx_circle; 36 | 37 | CREATE TABLE tbl_with_dropped_column ( 38 | d1 text, 39 | c1 text, 40 | id integer PRIMARY KEY, 41 | d2 text, 42 | c2 text, 43 | d3 text 44 | ); 45 | ALTER INDEX tbl_with_dropped_column_pkey SET (fillfactor = 75); 46 | ALTER TABLE tbl_with_dropped_column CLUSTER ON tbl_with_dropped_column_pkey; 47 | CREATE INDEX idx_c1c2 ON tbl_with_dropped_column (c1, c2) WITH (fillfactor = 75); 48 | CREATE INDEX idx_c2c1 ON tbl_with_dropped_column (c2, c1); 49 | 50 | CREATE TABLE tbl_with_dropped_toast ( 51 | i integer, 52 | j integer, 53 | t text, 54 | PRIMARY KEY (i, j) 55 | ); 56 | ALTER TABLE tbl_with_dropped_toast CLUSTER ON tbl_with_dropped_toast_pkey; 57 | 58 | CREATE TABLE tbl_badindex ( 59 | id integer PRIMARY KEY, 60 | n integer 61 | ); 62 | 63 | CREATE TABLE tbl_idxopts ( 64 | i integer PRIMARY KEY, 65 | t text 66 | ); 67 | CREATE INDEX idxopts_t ON tbl_idxopts (t DESC NULLS LAST) WHERE (t != 'aaa'); 68 | 69 | -- 70 | -- insert data 71 | -- 72 | 73 | INSERT INTO tbl_cluster VALUES(1, '2008-12-31 10:00:00', 'admin'); 74 | INSERT INTO tbl_cluster VALUES(2, '2008-01-01 00:00:00', 'king'); 75 | INSERT INTO tbl_cluster VALUES(3, '2008-03-04 12:00:00', 'joker'); 76 | INSERT INTO tbl_cluster VALUES(4, '2008-03-05 15:00:00', 'queen'); 77 | INSERT INTO tbl_cluster VALUES(5, '2008-01-01 00:30:00', sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text); 78 | 79 | INSERT INTO tbl_only_pkey VALUES(1, 'abc'); 80 | INSERT INTO tbl_only_pkey VALUES(2, 'def'); 81 | 82 | INSERT INTO tbl_only_ckey VALUES(1, '2008-01-01 00:00:00', 'abc'); 83 | INSERT INTO tbl_only_ckey VALUES(2, '2008-02-01 00:00:00', 'def'); 84 | 85 | INSERT INTO tbl_gistkey VALUES(1, '<(1,2),3>'); 86 | INSERT INTO tbl_gistkey VALUES(2, '<(4,5),6>'); 87 | 88 | INSERT INTO tbl_with_dropped_column VALUES('d1', 'c1', 2, 'd2', 'c2', 'd3'); 89 | INSERT INTO tbl_with_dropped_column VALUES('d1', 'c1', 1, 'd2', 'c2', 'd3'); 90 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d1; 91 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d2; 92 | ALTER TABLE tbl_with_dropped_column DROP COLUMN d3; 93 | ALTER TABLE tbl_with_dropped_column ADD COLUMN c3 text; 94 | CREATE VIEW view_for_dropped_column AS 95 | SELECT * FROM tbl_with_dropped_column; 96 | 97 | INSERT INTO tbl_with_dropped_toast VALUES(1, 10, 'abc'); 98 | INSERT INTO tbl_with_dropped_toast VALUES(2, 20, sqrt(2::numeric(1000,999))::text || sqrt(3::numeric(1000,999))::text); 99 | ALTER TABLE tbl_with_dropped_toast DROP COLUMN t; 100 | 101 | INSERT INTO tbl_badindex VALUES(1, 10); 102 | INSERT INTO tbl_badindex VALUES(2, 10); 103 | 104 | -- This will fail. Silence the message as it's different across PG versions. 105 | SET client_min_messages = fatal; 106 | CREATE UNIQUE INDEX CONCURRENTLY idx_badindex_n ON tbl_badindex (n); 107 | SET client_min_messages = warning; 108 | 109 | INSERT INTO tbl_idxopts VALUES (0, 'abc'), (1, 'aaa'), (2, NULL), (3, 'bbb'); 110 | 111 | -- 112 | -- before 113 | -- 114 | 115 | SELECT * FROM tbl_with_dropped_column; 116 | SELECT * FROM view_for_dropped_column; 117 | SELECT * FROM tbl_with_dropped_toast; 118 | 119 | -- 120 | -- do reorg 121 | -- 122 | 123 | \! pg_reorg --dbname=contrib_regression --no-order 124 | \! pg_reorg --dbname=contrib_regression 125 | \! pg_reorg --dbname=contrib_regression --table=tbl_cluster 126 | 127 | -- 128 | -- after 129 | -- 130 | 131 | \d tbl_cluster 132 | \d tbl_gistkey 133 | \d tbl_only_ckey 134 | \d tbl_only_pkey 135 | \d tbl_with_dropped_column 136 | \d tbl_with_dropped_toast 137 | \d tbl_idxopts 138 | 139 | SELECT col1, to_char("time", 'YYYY-MM-DD HH24:MI:SS'), ","")" FROM tbl_cluster; 140 | SELECT * FROM tbl_only_ckey ORDER BY 1; 141 | SELECT * FROM tbl_only_pkey ORDER BY 1; 142 | SELECT * FROM tbl_gistkey ORDER BY 1; 143 | 144 | SET enable_seqscan = on; 145 | SET enable_indexscan = off; 146 | SELECT * FROM tbl_with_dropped_column; 147 | SELECT * FROM view_for_dropped_column; 148 | SELECT * FROM tbl_with_dropped_toast; 149 | SET enable_seqscan = off; 150 | SET enable_indexscan = on; 151 | SELECT * FROM tbl_with_dropped_column; 152 | SELECT * FROM view_for_dropped_column; 153 | SELECT * FROM tbl_with_dropped_toast; 154 | RESET enable_seqscan; 155 | RESET enable_indexscan; 156 | 157 | -- 158 | -- check broken links or orphan toast relations 159 | -- 160 | SELECT oid, relname 161 | FROM pg_class 162 | WHERE relkind = 't' 163 | AND oid NOT IN (SELECT reltoastrelid FROM pg_class WHERE relkind = 'r'); 164 | 165 | SELECT oid, relname 166 | FROM pg_class 167 | WHERE relkind = 'r' 168 | AND reltoastrelid <> 0 169 | AND reltoastrelid NOT IN (SELECT oid FROM pg_class WHERE relkind = 't'); 170 | 171 | -- 172 | -- NOT NULL UNIQUE 173 | -- 174 | CREATE TABLE tbl_nn (col1 int NOT NULL, col2 int NOT NULL); 175 | CREATE TABLE tbl_uk (col1 int NOT NULL, col2 int , UNIQUE(col1, col2)); 176 | CREATE TABLE tbl_nn_uk (col1 int NOT NULL, col2 int NOT NULL, UNIQUE(col1, col2)); 177 | CREATE TABLE tbl_pk_uk (col1 int NOT NULL, col2 int NOT NULL, PRIMARY KEY(col1, col2), UNIQUE(col2, col1)); 178 | CREATE TABLE tbl_nn_puk (col1 int NOT NULL, col2 int NOT NULL); 179 | CREATE UNIQUE INDEX tbl_nn_puk_pcol1_idx ON tbl_nn_puk(col1) WHERE col1 < 10; 180 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn 181 | -- => ERROR 182 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_uk 183 | -- => ERROR 184 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_uk 185 | -- => OK 186 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_pk_uk 187 | -- => OK 188 | \! pg_reorg --dbname=contrib_regression --no-order --table=tbl_nn_puk 189 | -- => ERROR 190 | -------------------------------------------------------------------------------- /doc/index-ja.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | pg_reorg: Project Home Page 12 | 13 | 14 | 15 |
16 |
17 |

pg_reorg ホームページへようこそ

18 |
19 |
20 | 21 |

このプロジェクトでは pg_reorgpg_batch の2つのツールを頒布しています。

22 | 23 |

24 | pg_reorg は PostgreSQL のテーブルを再編成するシェルコマンドです。 25 | 共有ロックや排他ロックを取得しないため、再編成中であっても行の参照や更新を行うことができます。 26 | このモジュールは CLUSTER や VACUUM FULL コマンドのより良い代替になります。 27 |

28 | 29 |

30 | pg_batch は PostgreSQL のためのSQLジョブ実行プログラムです。 31 | ジョブ一覧生成するスクリプトを SQL として外部から与え、その出力 SQL をジョブとしてシリアルまたはパラレルに実行します。 32 | VACUUM を行うスクリプトが付属しており、"より良い vacuumdb" として利用できます。 33 |

34 | 35 |

この pg_reorg プロジェクトは PostgreSQL コミュニティによる pgFoundry の中のプロジェクトです。

36 | 41 | 44 |
45 | 46 |

ドキュメント

47 | 48 | 52 | 53 |

実行時間

54 |

55 | pg_reorg とclusterdb の比較に示します。 56 | 断片化のないソートされた状態 (not fragmented) では clusterdb のほうが高速ですが、完全に断片化した状態 (fully fragmented) では pg_reorg が大幅に高速です。 57 | 一般的に、再編成は断片化が進行した状態で実施されることを考えると、pg_reorg は clusterdb よりも実行時間が短いと言えます。 58 |

59 | 60 |
61 |
62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 113 | 114 | 115 | 116 | 117 | 118 |
測定環境
大項目小項目環境
ハードウェアCPU2 × Xeon 5160 3.00GHz (Dual core)
メモリ2GB
ストレージUltra320 SCSI, 15000rpm (220GB)
ソフトウェアOSRHEL 5.2 (64bit) 2.6.18-92.el5
DBPostgreSQL 8.3.3
pg_reorg1.0.0
clusterdbclusterdb (PostgreSQL) 8.3.3
データスキーマ
CREATE TABLE tbl (
106 |  id bigserial PRIMARY KEY,
107 |  seqkey timestamp NOT NULL,
108 |  rndkey timestamp NOT NULL,
109 |  filler char(75) NOT NULL
110 | );
111 | CREATE INDEX idx_seq ON tbl (seqkey);
112 | CREATE INDEX idx_rnd ON tbl (rndkey);
件数1650万件 (約2GB)
119 | 120 |
121 | 122 | 123 |
124 | 128 | 129 | 133 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | pg_reorg: Project Home Page 12 | 13 | 14 | 15 |
16 |
17 |

Welcome to the pg_reorg Project Home Page

18 |
19 |
20 | 21 |

22 | This project provides two tools for PostgreSQL; pg_reorg and pg_batch. 23 |

24 | 25 |

26 | pg_reorg can re-organize tables on a postgres database without any locks so that you can retrieve or update rows in tables being reorganized. 27 | The module is developed to be a better alternative of CLUSTER and VACUUM FULL. 28 |

29 | 30 |

31 | pg_batch is a SQL job executor program for PostgreSQL. 32 | It generates job list from an external SQL script file, and execute the jobs in serial or parallel. 33 | It can be used as "a better vacuumdb" with the attached script to run VACUUM. 34 |

35 | 36 |

37 | The pg_reorg project is a PostgreSQL Community project that is a part of the pgFoundry. 38 |

39 |

40 | The pgFoundry page for the project is at http://pgfoundry.org/projects/reorg, 41 | where you can find downloads, documentation, bug reports, mailing lists, and a whole lot more. 42 |

43 | 46 |
47 | 48 |

Documentation

49 | 50 | 54 | 55 |

Execution time

56 |

57 | Here is a comparison between pg_reorg and clusterdb. 58 | Clusterdb is faster on not fragmented conditions, but pg_reorg is faster on fully fragmented conditions. 59 | Since reorganization is needed only if tables are fragmented, pg_reorg should be faster than clusterdb. 60 |

61 | 62 |
63 |
64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 115 | 116 | 117 | 118 | 119 | 120 |
Configuration
CategoryItemDetails
HardwareCPU2 * Xeon 5160 3.00GHz (Dual core)
Memory2GB
StorageUltra320 SCSI, 15000rpm (220GB)
SoftwareOSRHEL 5.2 (64bit) 2.6.18-92.el5
DBPostgreSQL 8.3.3
pg_reorg1.0.0
clusterdbclusterdb (PostgreSQL) 8.3.3
DataScheme
CREATE TABLE tbl (
108 |  id bigserial PRIMARY KEY,
109 |  seqkey timestamp NOT NULL,
110 |  rndkey timestamp NOT NULL,
111 |  filler char(75) NOT NULL
112 | );
113 | CREATE INDEX idx_seq ON tbl (seqkey);
114 | CREATE INDEX idx_rnd ON tbl (rndkey);
Rows16.5 M rows (2GB)
121 | 122 |
123 | 124 |
125 | 129 | 130 | 134 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /doc/pg_reorg-ja.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pg_reorg 5 | 6 | 7 | 8 | 9 | 10 | 11 |

pg_reorg 1.1.7

12 | 16 |
17 | 18 | 34 | 35 |

名前

36 | pg_reorg -- PostgreSQLデータベース内のテーブルに対して、参照/更新処理をブロックせずに再編成を行います。 37 | 38 |

概要

39 |

40 | pg_reorg [OPTIONS] 41 |

42 | 43 |

オプション OPTIONS には以下を指定できます。 44 | 詳細はオプションを参照してください。

45 |
    46 |
  • 固有オプション
      47 |
    • -a, --all : 全てのデータベースに対して実行します
    • 48 |
    • -o [--order-by] columns [,...]
    • 49 |
    • -n [--no-order]
    • 50 |
    • -t [--table] table
    • 51 |
    • -T [--wait-timeout] seconds
    • 52 |
    • -Z [--no-analyze]
    • 53 |
  • 54 |
  • 接続オプション
      55 |
    • -d, --dbname=DBNAME : 接続するデータベース
    • 56 |
    • -h, --host=HOSTNAME : データベースサーバホスト、またはソケットディレクトリ
    • 57 |
    • -p, --port=PORT : データベースサーバのポート
    • 58 |
    • -U, --username=USERNAME : このユーザとして接続します
    • 59 |
    • -w, --no-password : パスワードの入力を促しません
    • 60 |
    • -W, --password : パスワード入力を強制します
    • 61 |
  • 62 |
  • 一般オプション
      63 |
    • -e, --echo : サーバに送信するSQLを表示します
    • 64 |
    • -E, --elevel=LEVEL : ログ出力レベルを設定します
    • 65 |
    • --help : ヘルプを表示し、終了します
    • 66 |
    • --version : バージョン情報を出力し、終了します
    • 67 |
  • 68 |
69 | 70 |

説明

71 |

pg_reorg は、PostgreSQLデータベース内のテーブルを再編成(行の並び替え)するユーティリティです。 72 | clusterdb と異なり、参照/更新処理をブロックしません。 73 | 再編成の方式として、以下のいずれか1つを選択できます。

74 |
    75 |
  • オンライン CLUSTER (cluster index順に行を並び替える)
  • 76 |
  • ユーザの指定した順に行を並び替える
  • 77 |
  • オンライン VACUUM FULL (行の詰め合わせを行う)
  • 78 |
79 |

このユーティリティを使用するためには、以下のことに注意をしてください。

80 |
    81 |
  • このユーティリティは、スーパーユーザのみが実行することができます。
  • 82 |
  • 対象のテーブルはPRIMARY KEYを持っている必要があります。
  • 83 |
84 | 85 |

86 |

testというデータベースをオンライン CLUSTER するには、下記のコマンドを実行します。

87 |
$ pg_reorg test
88 |

testという名前のデータベースのfooという1つのテーブルに対してオンライン VACUUM FULL を行うには、下記のコマンドを実行します。

89 |
$ pg_reorg --no-order --table foo -d test

90 |

91 | 92 |

オプション

93 |

pg_reorg では、下記のコマンドライン引数を指定できます。

94 | 95 |

固有オプション

96 |

pg_reorg を実行する対象と並び替えの基準を指定するパラメータです。 97 | 何も指定されていない場合は、cluster index順にオンライン CLUSTER を行います。 98 | この2つを同時に指定することはできません。 99 |

100 | 101 |
102 |
-n
--no-order
103 |
オンライン VACUUM FULL の処理を行います。
104 | 105 |
-o columns [,...]
106 | --order-by columns [,...]
107 |
指定したカラムをキーにオンライン CLUSTER を行います。
108 | 109 |
110 | -t table
111 | --table=table 112 |
113 |
オンライン CLUSTER 、または、オンライン VACUUM FULL を行うテーブルを指定します。 114 | このオプションが指定されていない場合は、対象となったデータベースに存在する全ての対象テーブルに対して処理を行います。 115 |
116 | 117 |
118 | -T seconds
119 | --wait-timeout=seconds 120 |
121 |
122 | 再編成完了直前に一瞬だけ排他ロックを取得しますが、この排他ロックが取得できるまで待機する秒数を指定します。 123 | この秒数が経過してもロックが取得できない場合には、対象のテーブルにアクセスしている他の全てのクエリを取り消します。 124 | また、サーバのバージョンが 8.4 またはそれ以降の場合には、指定した秒数の2倍経過してもロックを取得できない場合には、強制的に切断します。 125 | デフォルトは60秒です。 126 |
127 | 128 |
-Z
--no-analyze
129 |
再編成後に ANALYZE を行いません。 130 | このオプションが指定されていない場合は、再編成後に ANALYZE します。
131 | 132 |
133 | 134 |

接続オプション

135 |

136 | PostgreSQLに接続するためのパラメータです。 137 | --allと--dbnameまたは--tableを同時に指定することはできません。 138 |

139 | 140 |
141 |
-a
--all
142 |
対象となる全てのデータベースに対してオンライン CLUSTER、または、オンラインVACUUM FULLを行います。
143 | 144 |
145 | -d DBNAME
146 | --dbname=DBNAME 147 |
148 |
オンライン CLUSTER、または、オンライン VACUUM FULL を行うデータベース名を指定します。 149 | データベース名が指定されておらず、-a(または--all)も指定されていない場合、 150 | データベース名はPGDATABASE環境変数から読み取られます。 151 | この変数も設定されていない場合は、接続時に指定したユーザ名が使用されます。
152 | 153 |
-h HOSTNAME
154 | --host=HOSTNAME
155 |
サーバが稼働しているマシンのホスト名を指定します。ホスト名がスラッシュから始まる場合、Unixドメインソケット用のディレクトリとして使用されます。
156 | 157 |
-p PORT
158 | --port=PORT
159 |
サーバが接続を監視するTCPポートもしくはUnixドメインソケットファイルの拡張子を指定します。
160 | 161 |
-U USERNAME
162 | --username=USERNAME
163 |
接続するユーザ名を指定します。
164 | 165 |
-w
166 | --no-password
167 |
168 | パスワードの入力を促しません。 169 | サーバがパスワード認証を必要とし、かつ、.pgpassファイルなどの他の方法が利用できない場合、接続試行は失敗します。 170 | バッチジョブやパスワードを入力するユーザが存在しない場合にこのオプションは有用かもしれません。 171 |
172 | 173 |
-W
174 | --password
175 |
データベースに接続する前に、強制的にパスワード入力を促します。
176 |
177 | サーバがパスワード認証を要求する場合 自動的にパスワード入力を促しますので、これが重要になることはありません。 178 | しかし、サーバにパスワードが必要かどうかを判断するための接続試行を無駄に行います。 179 | こうした余計な接続試行を防ぐために -W の入力が有意となる場合もあります。 180 |
181 |
182 | 183 |

一般オプション

184 |
185 |
-e
--echo
186 |
サーバに送信するSQLを表示します。
187 |
-E
--elevel
188 |
ログ出力レベルを設定します。 189 | DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, PANIC から選択します。 190 | デフォルトは INFO です。
191 |
--help
192 |
使用方法について表示します。
193 |
--version
194 |
バージョン情報を表示します。
195 |
196 | 197 |

環境変数

198 |
199 |
200 | PGDATABASE
201 | PGHOST
202 | PGPORT
203 | PGUSER 204 |
205 |
デフォルトの接続パラメータです。
206 |
207 | 208 |

209 | また、このユーティリティは、他のほとんどの PostgreSQL ユーティリティと同様、libpq でサポートされる環境変数を使用します。詳細については、環境変数の項目を参照してください。 210 |

211 | 212 |

トラブルシューティング

213 |

pg_reorg の実行に失敗した場合にエラーが表示されます。 214 | 想像されるエラー原因と対処を示します。

215 |

致命的なエラーで終了した場合、手動によるクリーンアップを行う必要があります。 216 | クリーンアップは、エラーが発生したデータベースに対して、$PGHOME/share/contrib/uninstall_pg_reorg.sql を実行し、その後、$PGHOME/share/contrib/pg_reorg.sql を実行します。

217 | 218 |
219 |
pg_reorg : reorg database "template1" ... skipped
220 |
--allオプションを指定した際に、pg_reorg がインストールされていないデータベースに対して表示されます。
221 |
pg_reorg スキーマのインストールを行ってください。
222 | 223 |
ERROR: pg_reorg is not installed
224 |
--dbnameで指定したデータベースにpg_reorg がインストールされていません。
225 |
pg_reorg のインストールを行ってください。
226 | 227 |
ERROR: relation "table" has no primary key
228 |
指定したテーブルにPRIMARY KEYが存在していません。
229 |
対象のテーブルにPRIMARY KEYの作成を行ってください。(ALTER TABLE ADD PRIMARY KEY)
230 | 231 |
ERROR: relation "table" has no cluster key
232 |
指定したテーブルに CLUSTER KEYが存在していません。
233 |
対象のテーブルに CLUSTER KEYの作成を行ってください。(ALTER TABLE CLUSTER)
234 | 235 |
pg_reorg : query failed: ERROR: column "col" does not exist
236 |
--order-by で指定したカラムが対象のテーブルに存在していません。
237 |
対象のテーブルに存在するカラムを指定してください。
238 | 239 |
ERROR: permission denied for schema reorg
240 |
操作を行おうとした対象に権限がありません。
241 |
スーパーユーザで操作を行ってください。
242 | 243 |
pg_reorg : query failed: ERROR: trigger "z_reorg_trigger" for relation "tbl" already exists
244 |
操作を行おうとした対象にpg_reorg が処理のために作成するトリガと同名のものが存在しています。
245 |
トリガの改名か削除を行ってください。
246 | 247 |
pg_reorg : trigger conflicted for tbl
248 |
操作を行おうとした対象にpg_reorg が処理のために作成するトリガより後に実行されるトリガが存在しています。
249 |
トリガの改名か削除を行ってください。
250 |
251 | 252 |

使用上の注意と制約

253 |

pg_reorg を使用する際には、以下の制約があります。以下の制約に関する操作を行った場合の動作は保証されません。注意してください。

254 | 255 |

一時テーブルへの操作

256 |

pg_reorg では、一時テーブルは操作の対象外です。

257 | 258 |

GiSTインデックスの使用

259 |

インデックス種別がGiSTとなっているインデックスがクラスタインデックスとなっている 260 | テーブルはpg_reorg コマンドを使用して操作を行うことはできません。 261 | これは、GiSTインデックスのソート順序は一意ではないため、ORDER BYによる 262 | ソートが行えないためです。

263 | 264 |

DDLコマンドの発行

265 |

266 | pg_reorg の実行中には、VACUUM と ANALYZE 以外 のDDL操作は行わないでください。 267 | 多くの場合、pg_reorg は失敗しロールバックされます。 268 | しかし、以下の操作ではデータが破損するため、非常に危険です。 269 |

270 | 271 |
272 |
TRUNCATE
273 |
削除した行が pg_reorg 実行後には復元しています。操作結果が消失します。
274 | 275 |
CREATE INDEX
276 |
スワップされない索引が残る可能性があります。データの不整合が生じます。
277 | 278 |
ALTER TABLE ... ADD COLUMN
279 |
追加された値が全てNULLに置換されてしまう可能性があります。データが消失します。
280 | 281 |
ALTER TABLE ... ALTER COLUMN TYPE
282 |
実行するとスキーマで定義された型と実際の格納状態に齟齬をきたします。データの不整合が生じます。
283 | 284 |
ALTER TABLE ... SET TABLESPACE
285 |
pg_reorg 実行後にrelfilenodeとの不整合が起こるため、対象のテーブルに対する参照/更新操作時にエラーが発生します。
286 |
287 | 288 |

詳細

289 |

pg_reorg は reorg スキーマに作業用テーブルを作成し、そこでデータの並び替えを行います。 290 | 最後にシステムカタログを直接書き換えることで、元のテーブルと名前を交換しています。

291 | 292 |

インストール方法

293 |

294 | UNIX や Linux では、make を実行すると自動的に pgxs を使ってビルドできます。 295 | 前もって PostgreSQL 開発用パッケージ (postgresql-devel 等) をインストールし、pg_config にパスを通してください。 296 |

297 |
$ cd pg_reorg
298 | $ make
299 | $ su
300 | $ make install
301 |

302 | Windows では Microsoft Visual C++ 2010 でビルドできます。 303 | msvc フォルダ内にプロジェクトファイルがあります。 304 |

305 | 306 |

その後、データベースに関数を登録します。

307 |
$ pg_ctl start
308 | $ psql -f $PGSHARE/contrib/pg_reorg.sql -d your_database
309 | 310 |

(注意: CREATE EXTENSION はまだサポートしていません。)

311 | 312 |

動作環境

313 |
314 |
PostgreSQLバージョン
315 |
PostgreSQL 8.2, 8.3, 8.4, 9.0, 9.1, 9.2
316 |
OS
317 |
RHEL 5.2, Windows XP SP3
318 |
ディスク容量
319 |
処理対象のテーブル、インデックスサイズの2倍以上のディスク空き容量 (対象が1GBならば、さらに追加で2GB)
320 |
321 | 322 |

更新履歴

323 |
    324 |
  • 1.1.7 (2011-08-07)
      325 |
    • バグ修正: DROPされた列を持つテーブルを再編成した場合に、そのテーブルを使用するビューや関数が破損する可能性があった。
    • 326 |
    • PostgreSQL 9.1, 9.2dev のサポート (EXTENSION はまだ)
    • 327 |
  • 328 |
329 | 330 |

関連項目

331 | clusterdb, 332 | vacuumdb 333 | 334 |
335 | 339 | 343 | 344 | 348 | 353 | 354 | 355 | -------------------------------------------------------------------------------- /doc/pg_reorg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pg_reorg 5 | 6 | 7 | 8 | 9 | 10 | 11 |

pg_reorg 1.1.7

12 | 16 |
17 | 18 |
19 |
    20 |
  1. Name
  2. 21 |
  3. Synopsis
  4. 22 |
  5. Description
  6. 23 |
  7. Examples
  8. 24 |
  9. Options
  10. 25 |
  11. Environment
  12. 26 |
  13. Restrictions
  14. 27 |
  15. Details
  16. 28 |
  17. Installations
  18. 29 |
  19. Requirements
  20. 30 |
  21. Releases
  22. 31 |
  23. See Also
  24. 32 |
33 |
34 | 35 |

Name

36 | pg_reorg -- Reorganize tables in PostgreSQL databases without any locks. 37 | 38 |

Synopsis

39 |

40 | pg_reorg [OPTIONS] 41 |

42 | 43 |

The following options can be specified in OPTIONS. 44 | See also "Options" for details.

45 |
    46 |
  • Reorg Options
      47 |
    • -a, --all : reorganize all databases
    • 48 |
    • -o [--order-by] columns [,...]
    • 49 |
    • -n [--no-order]
    • 50 |
    • -t [--table] table
    • 51 |
    • -T [--wait-timeout] seconds
    • 52 |
    • -Z [--no-analyze]
    • 53 |
  • 54 |
  • Connection Options
      55 |
    • -d, --dbname=DBNAME : database to connect
    • 56 |
    • -h, --host=HOSTNAME : database server host or socket directory
    • 57 |
    • -p, --port=PORT : database server port
    • 58 |
    • -U, --username=USERNAME : user name to connect as
    • 59 |
    • -w, --no-password : never prompt for password
    • 60 |
    • -W, --password : force password prompt
    • 61 |
  • 62 |
  • Generic Options
      63 |
    • -e, --echo : echo queries
    • 64 |
    • -E, --elevel=LEVEL : set output message level
    • 65 |
    • --help : show the help, then exit
    • 66 |
    • --version : output version information, then exit
    • 67 |
  • 68 |
69 | 70 |

Description

71 |

pg_reorg is an utility program to reorganize tables in PostgreSQL databases. 72 | Unlike clusterdb, it doesn't block any selections and updates during reorganization. 73 | You can choose one of the following methods to reorganize.

74 |
    75 |
  • Online CLUSTER (ordered by cluster index)
  • 76 |
  • Ordered by specified columns
  • 77 |
  • Online VACUUM FULL (packing rows only)
  • 78 |
79 |

NOTICE:

80 |
    81 |
  • Only superusers can use the utility.
  • 82 |
  • Target table must have PRIMARY KEY.
  • 83 |
84 | 85 |

Examples

86 |

Execute the following command to perform an online CLUSTER of all tables in test database.

87 |
$ pg_reorg test
88 |

Execute the following command to perform an online VACUUM FULL to foo table in test database.

89 |
$ pg_reorg --no-order --table foo -d test

90 |

91 | 92 |

Options

93 |

pg_reorg has the following command line options:

94 | 95 |

Reorg Options

96 |

Options to order rows. 97 | If not specified, pg_reorg performs an online CLUSTER using cluster indexes. 98 | Only one option can be specified. 99 | 100 | You may also specify target tables or databases. 101 |

102 | 103 |
104 |
-n
--no-order
105 |
Do online VACUUM FULL.
106 | 107 |
-o columns [,...]
108 | --order-by=columns [,...]
109 |
Do online CLUSTER ordered by specified columns.
110 | 111 |
112 | -t table
113 | --table=table 114 |
115 |
Reorganize table only. If you don't specify this option, all tables in specified databases are reorganized.
116 | 117 |
118 | -T seconds
119 | --wait-timeout=seconds 120 |
121 |
122 | pg_reorg needs to take an exclusive lock at the end of the reorganization. 123 | This setting controls how long it wait for acquiring the lock in seconds. 124 | If the lock cannot be taken even after the duration, pg_reorg forces to cancel conflicted queries. 125 | Also, if the server version is 8.4 or newer, pg_reorg forces to disconnect conflicted backends after twice time passed. 126 | The default is 60 seconds. 127 |
128 | 129 |
-Z
--no-analyze
130 |
Disable ANALYZE after the reorganization. 131 | If not specified, run ANALYZE after the reorganization.
132 | 133 |
134 | 135 |

Connection Options

136 |

137 | Options to connect to servers. 138 | You cannot use --all and --dbname or --table together. 139 |

140 | 141 |
142 |
-a
--all
143 |
Reorganize all databases.
144 | 145 |
146 | -d dbname
147 | --dbname dbname 148 |
149 |
Specifies the name of the database to be reorganized. If this is not specified and -a (or --all) is not used, the database name is read from the environment variable PGDATABASE. If that is not set, the user name specified for the connection is used.
150 | 151 |
-h host
152 | --host host
153 |
Specifies the host name of the machine on which the server is running. If the value begins with a slash, it is used as the directory for the Unix domain socket.
154 | 155 |
-p port
156 | --port port
157 |
Specifies the TCP port or local Unix domain socket file extension on which the server is listening for connections.
158 | 159 |
-U username
160 | --username username
161 |
User name to connect as.
162 | 163 |
-w
164 | --no-password
165 |
166 | Never issue a password prompt. 167 | If the server requires password authentication and a password is not available by other means such as a .pgpass file, the connection attempt will fail. 168 | This option can be useful in batch jobs and scripts where no user is present to enter a password. 169 |
170 | 171 |
-W
172 | --password
173 |
Force the program to prompt for a password before connecting to a database.
174 |
This option is never essential, since the program will automatically prompt for a password if the server demands password authentication. However, pg_reorg will waste a connection attempt finding out that the server wants a password. In some cases it is worth typing -W to avoid the extra connection attempt.
175 |
176 | 177 |

Generic Options

178 |
179 |
-e
--echo
180 |
Echo commands sent to server.
181 |
-E
--elevel
182 |
Choose the output message level from DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. 183 | The default is INFO.
184 |
--help
185 |
Show usage of the program.
186 |
--version
187 |
Show the version number of the program.
188 |
189 | 190 |

Environment

191 |
192 |
193 | PGDATABASE
194 | PGHOST
195 | PGPORT
196 | PGUSER 197 |
198 |
Default connection parameters
199 |
200 |

This utility, like most other PostgreSQL utilities, also uses the environment variables supported by libpq (see Environment Variables).

201 | 202 |

Diagnostics

203 |

Error messages are reported when pg_reorg fails. 204 | The following list shows the cause of errors.

205 |

You need to cleanup by hand after fatal errors. 206 | To cleanup, execute $PGHOME/share/contrib/uninstall_pg_reorg.sql to the database where the error occured and then execute $PGHOME/share/contrib/pg_reorg.sql. (Do uninstall and reinstall.)

207 | 208 |
209 |
pg_reorg : reorg database "template1" ... skipped
210 |
pg_reorg is not installed in the database when --all option is specified.
211 |
Do register pg_reorg to the database.
212 | 213 |
ERROR: pg_reorg is not installed
214 |
pg_reorg is not installed in the database specified by --dbname.
215 |
Do register pg_reorg to the database.
216 | 217 |
ERROR: relation "table" has no primary key
218 |
The target table doesn't have PRIMARY KEY.
219 |
Define PRIMARY KEY to the table. (ALTER TABLE ADD PRIMARY KEY)
220 | 221 |
ERROR: relation "table" has no cluster key
222 |
The target table doesn't have CLUSTER KEY.
223 |
Define CLUSTER KEY to the table. (ALTER TABLE CLUSTER)
224 | 225 |
pg_reorg : query failed: ERROR: column "col" does not exist
226 |
The target table doesn't have columns specified by --order-by option.
227 |
Specify existing columns.
228 | 229 |
ERROR: permission denied for schema reorg
230 |
Permission error.
231 |
pg_reorg must be executed by superusers.
232 | 233 |
pg_reorg : query failed: ERROR: trigger "z_reorg_trigger" for relation "tbl" already exists
234 |
The target table already has a trigger named "z_reorg_trigger".
235 |
Delete or rename the trigger.
236 | 237 |
pg_reorg : trigger conflicted for tbl
238 |
The target table already has a trigger which follows by "z_reorg_trigger" in alphabetical order.
239 |
Delete or rename the trigger.
240 |
241 | 242 |

Restrictions

243 |

pg_reorg has the following restrictions. 244 | Be careful to avoid data corruptions.

245 | 246 |

Temp tables

247 |

pg_reorg cannot reorganize temp tables.

248 | 249 |

GiST indexes

250 |

pg_reorg cannot reorganize tables using GiST indexes.

251 | 252 |

DDL commands

253 |

You cannot do DDL commands except VACUUM and ANALYZE during pg_reorg. 254 | In many cases pg_reorg will fail and rollback collectly, but there are some cases which may result in data-corruption .

255 | 256 |
257 |
TRUNCATE
258 |
TRUNCATE is lost. Deleted rows still exist after pg_reorg.
259 | 260 |
CREATE INDEX
261 |
It causes index corruptions.
262 | 263 |
ALTER TABLE ... ADD COLUMN
264 |
It causes lost of data. Newly added columns are initialized with NULLs.
265 | 266 |
ALTER TABLE ... ALTER COLUMN TYPE
267 |
It causes data corruptions.
268 | 269 |
ALTER TABLE ... SET TABLESPACE
270 |
It causes data corruptions by wrong relfilenode.
271 |
272 | 273 |

Details

274 |

pg_reorg creates a work table in the reorg schema and sorts the rows in this table. 275 | Then, it updates the system catalogs directly to swap the work table and the original one.

276 | 277 |

Installations

278 |

279 | pg_reorg can be built with "make" on UNIX or Linux. 280 | pgxs build framework is used automatically. 281 | Before building, you might need to install postgres packages for developer (postgresql-devel, etc.) 282 | and add pg_config to your $PATH. 283 |

284 |
$ cd pg_reorg
285 | $ make
286 | $ su
287 | $ make install
288 |

289 | You can also use Microsoft Visual C++ 2010 to build the program on Windows. 290 | There are project files in the msvc folder. 291 |

292 | 293 |

Start PostgreSQL and execute the script to register functions to your database.

294 |
$ pg_ctl start
295 | $ psql -f $PGSHARE/contrib/pg_reorg.sql -d your_database
296 | 297 |

(NOTE: CREATE EXTENSION is not supported yet.)

298 | 299 |

Requirements

300 |
301 |
PostgreSQL versions
302 |
PostgreSQL 8.2, 8.3, 8.4, 9.0, 9.1, 9.2
303 |
OS
RHEL 5.2, Windows XP SP3
304 |
Disks
Requires free disk space twice as large as the target 305 | table(s) and indexes. For example, if the total size of the tables and 306 | indexes to be reorganized is 1GB, an additional 2GB of disk space is 307 | required.
308 |
309 | 310 |

Releases

311 |
    312 |
  • 1.1.7 (2011-08-07)
      313 |
    • Bugfix: VIEWs and FUNCTIONs could be corrupted that used a reorganized table which has a dropped column.
    • 314 |
    • Supports PostgreSQL 9.1 and 9.2dev. (but EXTENSION is not yet)
    • 315 |
  • 316 |
317 | 318 |

See Also

319 | clusterdb, 320 | vacuumdb 321 | 322 |
323 | 327 | 328 |
329 | 333 |
334 | 335 | 339 | 344 | 345 | 346 | -------------------------------------------------------------------------------- /doc/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 3 | Lucida Grande, Verdana, Arial, Helvetica, 4 | 'メイリオ', 5 | 'Meiryo', 6 | 'ヒラギノ角ゴ Pro W3', 7 | 'Hiragino Kaku Gothic Pro', 8 | 'Osaka', 9 | 'MS Pゴシック', 10 | sans-serif; 11 | color: #202020; 12 | } 13 | 14 | /* give the rule a bit of extra space (above and below), since its being used to divide 15 | sections on some pages (project summary) */ 16 | HR { margin: 5px 0px 5px 0px } 17 | 18 | 19 | h2, h3, h4, h5, h6 { 20 | color: Black; 21 | background: none; 22 | padding-top: 0.5em; 23 | padding-bottom: 0.17em; 24 | border-bottom: 1px solid #aaaaaa; 25 | } 26 | H1 { font-size: x-large; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 27 | H2 { font-size: large; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 28 | H3 { padding-left: 1em; font-size: medium; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 29 | H4 { padding-left: 2em; font-size: small; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 30 | H5 { padding-left: 3em; font-size: x-small; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 31 | H6 { padding-left: 4em; font-size: xx-small; font-family: Lucida Grande,verdana,arial,helvetica,sans-serif; } 32 | 33 | pre { 34 | font-family: courier,sans-serif; 35 | background-color: #FBFBFD; 36 | border: 1px dashed #7E7ECB; 37 | color: black; 38 | line-height: 1.1em; padding: 0.5em; 39 | overflow: auto; 40 | } 41 | 42 | li { 43 | line-height: 1.4em; 44 | } 45 | 46 | table { 47 | background: #f9f9f9; 48 | border: 1px solid #aaa; 49 | border-collapse: collapse; 50 | } 51 | 52 | th, td { 53 | border: 1px solid #aaa; 54 | padding: 0.2em; 55 | } 56 | 57 | thead th { 58 | background: #f2f2f2; 59 | text-align: center; 60 | } 61 | 62 | tbody th { 63 | background: #f2f2f2; 64 | text-align: left; 65 | } 66 | 67 | div.index { 68 | float:right; 69 | border:thin solid black; 70 | background-color: white; 71 | padding-top: 0.2em; 72 | padding-bottom: 0.2em; 73 | padding-left: 1em; 74 | padding-right: 1em; 75 | margin-left: 0.5em; 76 | } 77 | 78 | p.footer { 79 | text-align: right; 80 | font-size: small; 81 | } 82 | 83 | span.param { 84 | color: #0000cd; 85 | } 86 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /pg_reorg.sql 3 | /pg_reorg--[0-9.]*.sql 4 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # pg_reorg: lib/Makefile 3 | # 4 | # Portions Copyright (c) 2008-2012, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | # Portions Copyright (c) 2011, Itagaki Takahiro 6 | # 7 | MODULE_big = pg_reorg 8 | OBJS = reorg.o pgut/pgut-be.o pgut/pgut-spi.o 9 | 10 | EXTENSION = pg_reorg 11 | 12 | # The version of the extension, read from the .control file. 13 | # Note that it doesn't need to be the same of the library version: it should 14 | # be increased only when the sql changes. 15 | EXTVER = $(shell grep -e '^default_version' $(EXTENSION).control \ 16 | | sed -e "s/[^']*'\([^']*\)'.*/\1/") 17 | 18 | #supports both EXTENSION (for >=9.1) and without_EXTENSION (for $@; \ 46 | sed 's,MODULE_PATHNAME,$$libdir/$(MODULE_big),g' $< >> $@; \ 47 | echo "\nCOMMIT;" >> $@; 48 | 49 | pg_reorg--$(EXTVER).sql: pg_reorg.sql.in 50 | echo '\echo Use "CREATE EXTENSION pg_reorg" to load this file. \quit' > $@; \ 51 | cat $< >> $@; 52 | -------------------------------------------------------------------------------- /lib/pg_reorg.control: -------------------------------------------------------------------------------- 1 | # pg_reorg extension 2 | comment = 're-organizes a PostgreSQL database' 3 | default_version = '1.2dev0' 4 | module_pathname = '$libdir/pg_reorg' 5 | relocatable = false 6 | -------------------------------------------------------------------------------- /lib/pg_reorg.sql.in: -------------------------------------------------------------------------------- 1 | /* 2 | * pg_reorg: lib/pg_reorg.sql.in 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | */ 7 | 8 | CREATE SCHEMA reorg; 9 | 10 | CREATE FUNCTION reorg.version() RETURNS text AS 11 | 'MODULE_PATHNAME', 'reorg_version' 12 | LANGUAGE C IMMUTABLE STRICT; 13 | 14 | CREATE AGGREGATE reorg.array_accum ( 15 | sfunc = array_append, 16 | basetype = anyelement, 17 | stype = anyarray, 18 | initcond = '{}' 19 | ); 20 | 21 | CREATE FUNCTION reorg.oid2text(oid) RETURNS text AS 22 | $$ 23 | SELECT textin(regclassout($1)); 24 | $$ 25 | LANGUAGE sql STABLE STRICT; 26 | 27 | CREATE FUNCTION reorg.get_index_columns(oid, text) RETURNS text AS 28 | $$ 29 | SELECT array_to_string(reorg.array_accum(quote_ident(attname)), $2) 30 | FROM pg_attribute, 31 | (SELECT indrelid, 32 | indkey, 33 | generate_series(0, indnatts-1) AS i 34 | FROM pg_index 35 | WHERE indexrelid = $1 36 | ) AS keys 37 | WHERE attrelid = indrelid 38 | AND attnum = indkey[i]; 39 | $$ 40 | LANGUAGE sql STABLE STRICT; 41 | 42 | CREATE FUNCTION reorg.get_index_keys(oid, oid) RETURNS text AS 43 | 'MODULE_PATHNAME', 'reorg_get_index_keys' 44 | LANGUAGE C STABLE STRICT; 45 | 46 | CREATE FUNCTION reorg.get_create_index_type(oid, name) RETURNS text AS 47 | $$ 48 | SELECT 'CREATE TYPE ' || $2 || ' AS (' || 49 | array_to_string(reorg.array_accum(quote_ident(attname) || ' ' || 50 | pg_catalog.format_type(atttypid, atttypmod)), ', ') || ')' 51 | FROM pg_attribute, 52 | (SELECT indrelid, 53 | indkey, 54 | generate_series(0, indnatts-1) AS i 55 | FROM pg_index 56 | WHERE indexrelid = $1 57 | ) AS keys 58 | WHERE attrelid = indrelid 59 | AND attnum = indkey[i]; 60 | $$ 61 | LANGUAGE sql STABLE STRICT; 62 | 63 | CREATE FUNCTION reorg.get_create_trigger(relid oid, pkid oid) 64 | RETURNS text AS 65 | $$ 66 | SELECT 'CREATE TRIGGER z_reorg_trigger' || 67 | ' BEFORE INSERT OR DELETE OR UPDATE ON ' || reorg.oid2text($1) || 68 | ' FOR EACH ROW EXECUTE PROCEDURE reorg.reorg_trigger(' || 69 | '''INSERT INTO reorg.log_' || $1 || '(pk, row) VALUES(' || 70 | ' CASE WHEN $1 IS NULL THEN NULL ELSE (ROW($1.' || 71 | reorg.get_index_columns($2, ', $1.') || ')::reorg.pk_' || 72 | $1 || ') END, $2)'')'; 73 | $$ 74 | LANGUAGE sql STABLE STRICT; 75 | 76 | CREATE FUNCTION reorg.get_enable_trigger(relid oid) 77 | RETURNS text AS 78 | $$ 79 | SELECT 'ALTER TABLE ' || reorg.oid2text($1) || 80 | ' ENABLE ALWAYS TRIGGER z_reorg_trigger'; 81 | $$ 82 | LANGUAGE sql STABLE STRICT; 83 | 84 | CREATE FUNCTION reorg.get_assign(oid, text) RETURNS text AS 85 | $$ 86 | SELECT '(' || array_to_string(reorg.array_accum(quote_ident(attname)), ', ') || 87 | ') = (' || $2 || '.' || 88 | array_to_string(reorg.array_accum(quote_ident(attname)), ', ' || $2 || '.') || ')' 89 | FROM (SELECT attname FROM pg_attribute 90 | WHERE attrelid = $1 AND attnum > 0 AND NOT attisdropped 91 | ORDER BY attnum) tmp; 92 | $$ 93 | LANGUAGE sql STABLE STRICT; 94 | 95 | CREATE FUNCTION reorg.get_compare_pkey(oid, text) 96 | RETURNS text AS 97 | $$ 98 | SELECT '(' || array_to_string(reorg.array_accum(quote_ident(attname)), ', ') || 99 | ') = (' || $2 || '.' || 100 | array_to_string(reorg.array_accum(quote_ident(attname)), ', ' || $2 || '.') || ')' 101 | FROM pg_attribute, 102 | (SELECT indrelid, 103 | indkey, 104 | generate_series(0, indnatts-1) AS i 105 | FROM pg_index 106 | WHERE indexrelid = $1 107 | ) AS keys 108 | WHERE attrelid = indrelid 109 | AND attnum = indkey[i]; 110 | $$ 111 | LANGUAGE sql STABLE STRICT; 112 | 113 | -- Get a column list for SELECT all columns including dropped ones. 114 | -- We use NULLs of integer types for dropped columns (types are not important). 115 | CREATE FUNCTION reorg.get_columns_for_create_as(oid) 116 | RETURNS text AS 117 | $$ 118 | SELECT array_to_string(reorg.array_accum(c), ',') FROM (SELECT 119 | CASE WHEN attisdropped 120 | THEN 'NULL::integer AS ' || quote_ident(attname) 121 | ELSE quote_ident(attname) 122 | END AS c 123 | FROM pg_attribute 124 | WHERE attrelid = $1 AND attnum > 0 ORDER BY attnum 125 | ) AS COL 126 | $$ 127 | LANGUAGE sql STABLE STRICT; 128 | 129 | -- Get a SQL text to DROP dropped columns for the table, 130 | -- or NULL if it has no dropped columns. 131 | CREATE FUNCTION reorg.get_drop_columns(oid, text) 132 | RETURNS text AS 133 | $$ 134 | SELECT 135 | 'ALTER TABLE ' || $2 || ' ' || array_to_string(dropped_columns, ', ') 136 | FROM ( 137 | SELECT 138 | reorg.array_accum('DROP COLUMN ' || quote_ident(attname)) AS dropped_columns 139 | FROM ( 140 | SELECT * FROM pg_attribute 141 | WHERE attrelid = $1 AND attnum > 0 AND attisdropped 142 | ORDER BY attnum 143 | ) T 144 | ) T 145 | WHERE 146 | array_upper(dropped_columns, 1) > 0 147 | $$ 148 | LANGUAGE sql STABLE STRICT; 149 | 150 | -- includes not only PRIMARY KEYS but also UNIQUE NOT NULL keys 151 | CREATE VIEW reorg.primary_keys AS 152 | SELECT indrelid, (reorg.array_accum(indexrelid))[1] AS indexrelid 153 | FROM (SELECT indrelid, indexrelid FROM pg_index 154 | WHERE indisunique 155 | AND indisvalid 156 | AND indpred IS NULL 157 | AND 0 <> ALL(indkey) 158 | AND NOT EXISTS( 159 | SELECT 1 FROM pg_attribute 160 | WHERE attrelid = indrelid 161 | AND attnum = ANY(indkey) 162 | AND NOT attnotnull) 163 | ORDER BY indrelid, indisprimary DESC, indnatts, indkey) tmp 164 | GROUP BY indrelid; 165 | 166 | CREATE VIEW reorg.tables AS 167 | SELECT R.oid::regclass AS relname, 168 | R.oid AS relid, 169 | R.reltoastrelid AS reltoastrelid, 170 | CASE WHEN R.reltoastrelid = 0 THEN 0 ELSE (SELECT reltoastidxid FROM pg_class WHERE oid = R.reltoastrelid) END AS reltoastidxid, 171 | PK.indexrelid AS pkid, 172 | CK.indexrelid AS ckid, 173 | reorg.get_create_index_type(PK.indexrelid, 'reorg.pk_' || R.oid) AS create_pktype, 174 | 'CREATE TABLE reorg.log_' || R.oid || ' (id bigserial PRIMARY KEY, pk reorg.pk_' || R.oid || ', row ' || reorg.oid2text(R.oid) || ')' AS create_log, 175 | reorg.get_create_trigger(R.oid, PK.indexrelid) AS create_trigger, 176 | reorg.get_enable_trigger(R.oid) as enable_trigger, 177 | '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, 178 | reorg.get_drop_columns(R.oid, 'reorg.table_' || R.oid) AS drop_columns, 179 | 'DELETE FROM reorg.log_' || R.oid AS delete_log, 180 | 'LOCK TABLE ' || reorg.oid2text(R.oid) || ' IN ACCESS EXCLUSIVE MODE' AS lock_table, 181 | reorg.get_index_keys(CK.indexrelid, R.oid) AS ckey, 182 | 'SELECT * FROM reorg.log_' || R.oid || ' ORDER BY id LIMIT $1' AS sql_peek, 183 | 'INSERT INTO reorg.table_' || R.oid || ' VALUES ($1.*)' AS sql_insert, 184 | 'DELETE FROM reorg.table_' || R.oid || ' WHERE ' || reorg.get_compare_pkey(PK.indexrelid, '$1') AS sql_delete, 185 | 'UPDATE reorg.table_' || R.oid || ' SET ' || reorg.get_assign(R.oid, '$2') || ' WHERE ' || reorg.get_compare_pkey(PK.indexrelid, '$1') AS sql_update, 186 | 'DELETE FROM reorg.log_' || R.oid || ' WHERE id <= $1' AS sql_pop 187 | FROM pg_class R 188 | LEFT JOIN pg_class T ON R.reltoastrelid = T.oid 189 | LEFT JOIN reorg.primary_keys PK 190 | ON R.oid = PK.indrelid 191 | LEFT JOIN (SELECT CKI.* FROM pg_index CKI, pg_class CKT 192 | WHERE CKI.indisvalid 193 | AND CKI.indexrelid = CKT.oid 194 | AND CKI.indisclustered 195 | AND CKT.relam = 403) CK 196 | ON R.oid = CK.indrelid 197 | LEFT JOIN pg_namespace N ON N.oid = R.relnamespace 198 | LEFT JOIN pg_tablespace S ON S.oid = R.reltablespace 199 | WHERE R.relkind = 'r' 200 | AND N.nspname NOT IN ('pg_catalog', 'information_schema') 201 | AND N.nspname NOT LIKE E'pg\\_temp\\_%'; 202 | 203 | CREATE FUNCTION reorg.reorg_indexdef(oid, oid) RETURNS text AS 204 | 'MODULE_PATHNAME', 'reorg_indexdef' 205 | LANGUAGE C STABLE STRICT; 206 | 207 | CREATE FUNCTION reorg.reorg_trigger() RETURNS trigger AS 208 | 'MODULE_PATHNAME', 'reorg_trigger' 209 | LANGUAGE C VOLATILE STRICT SECURITY DEFINER; 210 | 211 | CREATE FUNCTION reorg.conflicted_triggers(oid) RETURNS SETOF name AS 212 | $$ 213 | SELECT tgname FROM pg_trigger 214 | WHERE tgrelid = $1 AND tgname >= 'z_reorg_trigger' 215 | $$ 216 | LANGUAGE sql STABLE STRICT; 217 | 218 | CREATE FUNCTION reorg.disable_autovacuum(regclass) RETURNS void AS 219 | 'MODULE_PATHNAME', 'reorg_disable_autovacuum' 220 | LANGUAGE C VOLATILE STRICT; 221 | 222 | CREATE FUNCTION reorg.reorg_apply( 223 | sql_peek cstring, 224 | sql_insert cstring, 225 | sql_delete cstring, 226 | sql_update cstring, 227 | sql_pop cstring, 228 | count integer) 229 | RETURNS integer AS 230 | 'MODULE_PATHNAME', 'reorg_apply' 231 | LANGUAGE C VOLATILE; 232 | 233 | CREATE FUNCTION reorg.reorg_swap(oid) RETURNS void AS 234 | 'MODULE_PATHNAME', 'reorg_swap' 235 | LANGUAGE C VOLATILE STRICT; 236 | 237 | CREATE FUNCTION reorg.reorg_drop(oid) RETURNS void AS 238 | 'MODULE_PATHNAME', 'reorg_drop' 239 | LANGUAGE C VOLATILE STRICT; 240 | -------------------------------------------------------------------------------- /lib/pgut/pgut-be.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * pgut-be.c 4 | * 5 | * Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 6 | * 7 | *------------------------------------------------------------------------- 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "access/heapam.h" 12 | #include "pgut-be.h" 13 | 14 | #if PG_VERSION_NUM < 80400 15 | 16 | char * 17 | text_to_cstring(const text *t) 18 | { 19 | text *tunpacked = pg_detoast_datum_packed((struct varlena *) t); 20 | int len = VARSIZE_ANY_EXHDR(tunpacked); 21 | char *result; 22 | 23 | result = (char *) palloc(len + 1); 24 | memcpy(result, VARDATA_ANY(tunpacked), len); 25 | result[len] = '\0'; 26 | 27 | if (tunpacked != t) 28 | pfree(tunpacked); 29 | 30 | return result; 31 | } 32 | 33 | text * 34 | cstring_to_text(const char *s) 35 | { 36 | int len = strlen(s); 37 | text *result = palloc(len + VARHDRSZ); 38 | 39 | SET_VARSIZE(result, len + VARHDRSZ); 40 | memcpy(VARDATA(result), s, len); 41 | 42 | return result; 43 | } 44 | 45 | void 46 | tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, 47 | Datum *values, bool *isnull) 48 | { 49 | tuplestore_puttuple(state, heap_form_tuple(tdesc, values, isnull)); 50 | } 51 | 52 | Datum 53 | ExecFetchSlotTupleDatum(TupleTableSlot *slot) 54 | { 55 | HeapTuple tup; 56 | HeapTupleHeader td; 57 | TupleDesc tupdesc; 58 | 59 | /* Make sure we can scribble on the slot contents ... */ 60 | tup = ExecMaterializeSlot(slot); 61 | /* ... and set up the composite-Datum header fields, in case not done */ 62 | td = tup->t_data; 63 | tupdesc = slot->tts_tupleDescriptor; 64 | HeapTupleHeaderSetDatumLength(td, tup->t_len); 65 | HeapTupleHeaderSetTypeId(td, tupdesc->tdtypeid); 66 | HeapTupleHeaderSetTypMod(td, tupdesc->tdtypmod); 67 | return PointerGetDatum(td); 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /lib/pgut/pgut-be.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * pgut-be.h 4 | * 5 | * Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 6 | * 7 | *------------------------------------------------------------------------- 8 | */ 9 | 10 | #ifndef PGUT_BE_H 11 | #define PGUT_BE_H 12 | 13 | #include "fmgr.h" 14 | #include "utils/tuplestore.h" 15 | 16 | #ifndef WIN32 17 | 18 | #define PGUT_EXPORT 19 | 20 | #else 21 | 22 | #define PGUT_EXPORT __declspec(dllexport) 23 | 24 | /* 25 | * PG_MODULE_MAGIC and PG_FUNCTION_INFO_V1 macros seems to be broken. 26 | * It uses PGDLLIMPORT, but those objects are not imported from postgres 27 | * and exported from the user module. So, it should be always dllexported. 28 | */ 29 | 30 | #undef PG_MODULE_MAGIC 31 | #define PG_MODULE_MAGIC \ 32 | extern PGUT_EXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ 33 | const Pg_magic_struct * \ 34 | PG_MAGIC_FUNCTION_NAME(void) \ 35 | { \ 36 | static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ 37 | return &Pg_magic_data; \ 38 | } \ 39 | extern int no_such_variable 40 | 41 | #undef PG_FUNCTION_INFO_V1 42 | #define PG_FUNCTION_INFO_V1(funcname) \ 43 | extern PGUT_EXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \ 44 | const Pg_finfo_record * \ 45 | CppConcat(pg_finfo_,funcname) (void) \ 46 | { \ 47 | static const Pg_finfo_record my_finfo = { 1 }; \ 48 | return &my_finfo; \ 49 | } \ 50 | extern int no_such_variable 51 | 52 | #endif 53 | 54 | 55 | #if PG_VERSION_NUM < 80400 56 | 57 | #define MAIN_FORKNUM 0 58 | #define HEAP_INSERT_SKIP_WAL 0x0001 59 | #define HEAP_INSERT_SKIP_FSM 0x0002 60 | 61 | #define relpath(rnode, forknum) relpath((rnode)) 62 | #define smgrimmedsync(reln, forknum) smgrimmedsync((reln)) 63 | #define smgrread(reln, forknum, blocknum, buffer) \ 64 | smgrread((reln), (blocknum), (buffer)) 65 | #define mdclose(reln, forknum) mdclose((reln)) 66 | #define heap_insert(relation, tup, cid, options, bistate) \ 67 | heap_insert((relation), (tup), (cid), true, true) 68 | #define GetBulkInsertState() (NULL) 69 | #define FreeBulkInsertState(bistate) ((void)0) 70 | #define FreeExprContext(econtext, isCommit) FreeExprContext((econtext)) 71 | #define pgstat_init_function_usage(fcinfo, fcu) ((void)0) 72 | #define pgstat_end_function_usage(fcu, finalize) ((void)0) 73 | #define makeRangeVar(schemaname, relname, location) \ 74 | makeRangeVar((schemaname), (relname)) 75 | #define tuplestore_gettupleslot(state, forward, copy, slot) \ 76 | tuplestore_gettupleslot(state, forward, slot) 77 | #define pgstat_track_activity_query_size PGBE_ACTIVITY_SIZE 78 | typedef void *BulkInsertState; 79 | 80 | #define DefineCustomBoolVariable(name, short_desc, long_desc, valueAddr, bootValue, context, flags, assign_hook, show_hook) \ 81 | do { \ 82 | *(valueAddr) = (bootValue); \ 83 | DefineCustomBoolVariable((name), (short_desc), (long_desc), (valueAddr), (context), (assign_hook), (show_hook)); \ 84 | } while(0) 85 | #define DefineCustomIntVariable(name, short_desc, long_desc, valueAddr, bootValue, minValue, maxValue, context, flags, assign_hook, show_hook) \ 86 | do { \ 87 | *(valueAddr) = (bootValue); \ 88 | DefineCustomIntVariable((name), (short_desc), (long_desc), (valueAddr), (minValue), (maxValue), (context), (assign_hook), (show_hook)); \ 89 | } while(0) 90 | #define DefineCustomRealVariable(name, short_desc, long_desc, valueAddr, bootValue, minValue, maxValue, context, flags, assign_hook, show_hook) \ 91 | do { \ 92 | *(valueAddr) = (bootValue); \ 93 | DefineCustomRealVariable((name), (short_desc), (long_desc), (valueAddr), (minValue), (maxValue), (context), (assign_hook), (show_hook)); \ 94 | } while(0) 95 | #define DefineCustomStringVariable(name, short_desc, long_desc, valueAddr, bootValue, context, flags, assign_hook, show_hook) \ 96 | do { \ 97 | *(valueAddr) = (char *) (bootValue); \ 98 | DefineCustomStringVariable((name), (short_desc), (long_desc), (valueAddr), (context), (assign_hook), (show_hook)); \ 99 | } while(0) 100 | 101 | struct config_enum_entry 102 | { 103 | const char *name; 104 | int val; 105 | bool hidden; 106 | }; 107 | 108 | extern char *text_to_cstring(const text *t); 109 | extern text *cstring_to_text(const char *s); 110 | extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, 111 | Datum *values, bool *isnull); 112 | extern Datum ExecFetchSlotTupleDatum(TupleTableSlot *slot); 113 | 114 | #define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s)) 115 | #define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d)) 116 | 117 | #endif 118 | 119 | #if PG_VERSION_NUM < 90000 120 | 121 | #define reindex_index(indexId, skip_constraint_checks) \ 122 | reindex_index((indexId)) 123 | #define func_signature_string(funcname, nargs, argnames, argtypes) \ 124 | func_signature_string((funcname), (nargs), (argtypes)) 125 | 126 | #endif 127 | 128 | #if PG_VERSION_NUM < 90200 129 | 130 | #define RangeVarGetRelid(relation, lockmode, missing_ok, nowait) \ 131 | RangeVarGetRelid((relation), (missing_ok)) 132 | 133 | #endif 134 | 135 | #if PG_VERSION_NUM < 90100 136 | 137 | #define ATExecChangeOwner(relationOid, newOwnerId, recursing, lockmode) \ 138 | ATExecChangeOwner((relationOid), (newOwnerId), (recursing)) 139 | #define deleteDependencyRecordsFor(classId, objectId, skipExtensionDeps) \ 140 | deleteDependencyRecordsFor((classId), (objectId)) 141 | #define PG_GET_COLLATION() (InvalidOid) 142 | 143 | #endif 144 | 145 | #if PG_VERSION_NUM < 90000 146 | #define RelationSetNewRelfilenode(rel, xid) \ 147 | setNewRelfilenode((rel), (xid)) 148 | #endif 149 | 150 | #if PG_VERSION_NUM < 80400 151 | #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ 152 | FuncnameGetCandidates((names), (nargs)) 153 | #elif PG_VERSION_NUM < 90000 154 | #define FuncnameGetCandidates(names, nargs, argnames, variadic, defaults) \ 155 | FuncnameGetCandidates((names), (nargs), (variadic), (defaults)) 156 | #endif 157 | 158 | #if PG_VERSION_NUM < 90000 159 | #define GetConfigOption(name, missing_ok, restrict_superuser) \ 160 | GetConfigOption((name)) 161 | #elif PG_VERSION_NUM < 90200 162 | #define GetConfigOption(name, missing_ok, restrict_superuser) \ 163 | GetConfigOption((name), (restrict_superuser)) 164 | #endif 165 | 166 | #endif /* PGUT_BE_H */ 167 | -------------------------------------------------------------------------------- /lib/pgut/pgut-spi.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * pgut-spi.c 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | *------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "postgres.h" 10 | #include "pgut-spi.h" 11 | #include "lib/stringinfo.h" 12 | 13 | #define EXEC_FAILED(ret, expected) \ 14 | (((expected) > 0 && (ret) != (expected)) || (ret) < 0) 15 | 16 | static void 17 | appendStringInfoVA_s(StringInfo str, const char *fmt, va_list args) 18 | __attribute__((format(printf, 2, 0))); 19 | 20 | static void 21 | termStringInfo(StringInfo str) 22 | { 23 | if (str && str->data) 24 | pfree(str->data); 25 | } 26 | 27 | /* appendStringInfoVA + automatic buffer extension */ 28 | static void 29 | appendStringInfoVA_s(StringInfo str, const char *fmt, va_list args) 30 | { 31 | while (!appendStringInfoVA(str, fmt, args)) 32 | { 33 | /* Double the buffer size and try again. */ 34 | enlargeStringInfo(str, str->maxlen); 35 | } 36 | } 37 | 38 | /* simple execute */ 39 | void 40 | execute(int expected, const char *sql) 41 | { 42 | int ret = SPI_execute(sql, false, 0); 43 | if EXEC_FAILED(ret, expected) 44 | elog(ERROR, "query failed: (sql=%s, code=%d, expected=%d)", sql, ret, expected); 45 | } 46 | 47 | /* execute prepared plan */ 48 | void 49 | execute_plan(int expected, SPIPlanPtr plan, Datum *values, const char *nulls) 50 | { 51 | int ret = SPI_execute_plan(plan, values, nulls, false, 0); 52 | if EXEC_FAILED(ret, expected) 53 | elog(ERROR, "query failed: (code=%d, expected=%d)", ret, expected); 54 | } 55 | 56 | /* execute sql with format */ 57 | void 58 | execute_with_format(int expected, const char *format, ...) 59 | { 60 | va_list ap; 61 | StringInfoData sql; 62 | int ret; 63 | 64 | initStringInfo(&sql); 65 | va_start(ap, format); 66 | appendStringInfoVA_s(&sql, format, ap); 67 | va_end(ap); 68 | 69 | if (strlen(sql.data) == 0) 70 | elog(WARNING, "execute_with_format(%s)", format); 71 | ret = SPI_exec(sql.data, 0); 72 | if EXEC_FAILED(ret, expected) 73 | elog(ERROR, "query failed: (sql=%s, code=%d, expected=%d)", sql.data, ret, expected); 74 | 75 | termStringInfo(&sql); 76 | } 77 | 78 | void 79 | execute_with_args(int expected, const char *src, int nargs, Oid argtypes[], Datum values[], const bool nulls[]) 80 | { 81 | int ret; 82 | int i; 83 | char c_nulls[FUNC_MAX_ARGS]; 84 | 85 | for (i = 0; i < nargs; i++) 86 | c_nulls[i] = (nulls[i] ? 'n' : ' '); 87 | 88 | ret = SPI_execute_with_args(src, nargs, argtypes, values, c_nulls, false, 0); 89 | if EXEC_FAILED(ret, expected) 90 | elog(ERROR, "query failed: (sql=%s, code=%d, expected=%d)", src, ret, expected); 91 | } 92 | 93 | void 94 | execute_with_format_args(int expected, const char *format, int nargs, Oid argtypes[], Datum values[], const bool nulls[], ...) 95 | { 96 | va_list ap; 97 | StringInfoData sql; 98 | 99 | initStringInfo(&sql); 100 | va_start(ap, nulls); 101 | appendStringInfoVA_s(&sql, format, ap); 102 | va_end(ap); 103 | 104 | execute_with_args(expected, sql.data, nargs, argtypes, values, nulls); 105 | 106 | termStringInfo(&sql); 107 | } 108 | 109 | 110 | #if PG_VERSION_NUM < 80400 111 | 112 | int 113 | SPI_execute_with_args(const char *src, 114 | int nargs, Oid *argtypes, 115 | Datum *values, const char *nulls, 116 | bool read_only, long tcount) 117 | { 118 | SPIPlanPtr plan; 119 | int ret; 120 | 121 | plan = SPI_prepare(src, nargs, argtypes); 122 | if (plan == NULL) 123 | return SPI_result; 124 | ret = SPI_execute_plan(plan, values, nulls, read_only, tcount); 125 | SPI_freeplan(plan); 126 | return ret; 127 | } 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /lib/pgut/pgut-spi.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * pgut-spi.h 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | *------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef PGUT_SPI_H 10 | #define PGUT_SPI_H 11 | 12 | #include "executor/spi.h" 13 | 14 | #if PG_VERSION_NUM < 80400 15 | 16 | extern int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, 17 | Datum *values, const char *nulls, bool read_only, long tcount); 18 | 19 | #endif 20 | 21 | extern void execute(int expected, const char *sql); 22 | extern void execute_plan(int expected, SPIPlanPtr plan, Datum *values, const char *nulls); 23 | extern void execute_with_format(int expected, const char *format, ...) 24 | __attribute__((format(printf, 2, 3))); 25 | extern void execute_with_args(int expected, const char *src, int nargs, Oid argtypes[], Datum values[], const bool nulls[]); 26 | extern void execute_with_format_args(int expected, const char *format, int nargs, Oid argtypes[], Datum values[], const bool nulls[], ...) 27 | __attribute__((format(printf, 2, 7))); 28 | 29 | #endif /* PGUT_SPI_H */ 30 | -------------------------------------------------------------------------------- /lib/uninstall_pg_reorg.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * pg_reorg: lib/uninstall_reorg.sql 3 | * 4 | * Portions Copyright (c) 2008-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION 5 | * Portions Copyright (c) 2011, Itagaki Takahiro 6 | */ 7 | 8 | DROP SCHEMA IF EXISTS reorg CASCADE; 9 | -------------------------------------------------------------------------------- /msvc/bin.2010.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 8.3 6 | Win32 7 | 8 | 9 | 8.3 10 | x64 11 | 12 | 13 | 8.4 14 | Win32 15 | 16 | 17 | 8.4 18 | x64 19 | 20 | 21 | 9.0 22 | Win32 23 | 24 | 25 | 9.0 26 | x64 27 | 28 | 29 | 30 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2} 31 | bin 32 | Win32Proj 33 | 34 | 35 | 36 | Application 37 | Unicode 38 | true 39 | Windows7.1SDK 40 | 41 | 42 | Application 43 | Unicode 44 | true 45 | Windows7.1SDK 46 | 47 | 48 | Application 49 | Unicode 50 | true 51 | Windows7.1SDK 52 | 53 | 54 | Application 55 | Unicode 56 | true 57 | Windows7.1SDK 58 | 59 | 60 | Application 61 | Unicode 62 | true 63 | Windows7.1SDK 64 | 65 | 66 | Application 67 | Unicode 68 | true 69 | Windows7.1SDK 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | <_ProjectFileVersion>10.0.30319.1 95 | $(SolutionDir)/bin/x86/$(Configuration)/bin/ 96 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/bin/ 97 | $(SolutionDir)/bin/x86/$(Configuration)/bin/ 98 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/bin/ 99 | $(SolutionDir)/bin/x86/$(Configuration)/bin/ 100 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/bin/ 101 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 102 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 103 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 104 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 105 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 106 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 107 | false 108 | false 109 | false 110 | false 111 | false 112 | false 113 | C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server;C:\Program Files %28x86%29\PostgreSQL\9.0\include;C:\Program Files (x86)\PostgreSQL\9.0\include\internal;$(IncludePath) 114 | C:\Program Files\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files\PostgreSQL\9.0\include\server\port\win32;C:\Program Files\PostgreSQL\9.0\include\server;C:\Program Files\PostgreSQL\9.0\include;C:\Program Files\PostgreSQL\9.0\include\internal;$(IncludePath) 115 | C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;C:\Program Files (x86)\PostgreSQL\8.4\include\internal;$(IncludePath) 116 | C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;C:\Program Files (x86)\PostgreSQL\8.4\include\internal;$(IncludePath) 117 | C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server;C:\Program Files %28x86%29\PostgreSQL\8.3\include;C:\Program Files (x86)\PostgreSQL\8.3\include\internal;$(IncludePath) 118 | C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;C:\Program Files (x86)\PostgreSQL\8.4\include\internal;$(IncludePath) 119 | C:\Program Files %28x86%29\PostgreSQL\9.0\lib;$(LibraryPath) 120 | C:\Program Files\PostgreSQL\9.0\lib;$(LibraryPath) 121 | C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) 122 | C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) 123 | C:\Program Files %28x86%29\PostgreSQL\8.3\lib;$(LibraryPath) 124 | C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) 125 | pg_reorg 126 | pg_reorg 127 | pg_reorg 128 | pg_reorg 129 | pg_reorg 130 | pg_reorg 131 | 132 | 133 | 134 | ../include;%(AdditionalIncludeDirectories) 135 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 136 | 137 | 138 | MultiThreadedDLL 139 | 140 | 141 | Level3 142 | false 143 | 144 | 145 | CompileAsC 146 | 4005;4996;4018;%(DisableSpecificWarnings) 147 | 148 | 149 | advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl-8.lib 150 | $(OutDir)/$(TargetFileName) 151 | false 152 | Console 153 | true 154 | true 155 | MachineX86 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | ../include;%(AdditionalIncludeDirectories) 165 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 166 | 167 | 168 | MultiThreadedDLL 169 | 170 | 171 | Level3 172 | false 173 | 174 | 175 | CompileAsC 176 | 4005;4996;4018;%(DisableSpecificWarnings) 177 | 178 | 179 | advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl.lib 180 | $(OutDir)/$(TargetFileName) 181 | false 182 | Console 183 | true 184 | true 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | ../include;%(AdditionalIncludeDirectories) 194 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 195 | 196 | 197 | MultiThreadedDLL 198 | 199 | 200 | Level3 201 | false 202 | 203 | 204 | CompileAsC 205 | 4005;4996;4018;%(DisableSpecificWarnings) 206 | 207 | 208 | advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl-8.lib 209 | $(OutDir)/$(TargetFileName) 210 | false 211 | Console 212 | true 213 | true 214 | MachineX86 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | ../include;%(AdditionalIncludeDirectories) 224 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 225 | 226 | 227 | MultiThreadedDLL 228 | 229 | 230 | Level3 231 | false 232 | 233 | 234 | CompileAsC 235 | 4005;4996;4018;%(DisableSpecificWarnings) 236 | 237 | 238 | kernel32.lib;advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl-8.lib 239 | $(OutDir)/$(TargetFileName) 240 | false 241 | Console 242 | true 243 | true 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | ../include;%(AdditionalIncludeDirectories) 253 | _USE_32BIT_TIME_T;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 254 | 255 | 256 | MultiThreadedDLL 257 | 258 | 259 | Level3 260 | false 261 | 262 | 263 | CompileAsC 264 | 4005;4996;4018;%(DisableSpecificWarnings) 265 | 266 | 267 | advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl-8.lib 268 | $(OutDir)/$(TargetFileName) 269 | false 270 | Console 271 | true 272 | true 273 | MachineX86 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | ../include;%(AdditionalIncludeDirectories) 283 | _USE_32BIT_TIME_T;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 284 | 285 | 286 | MultiThreadedDLL 287 | 288 | 289 | Level3 290 | false 291 | 292 | 293 | CompileAsC 294 | 4005;4996;4018;%(DisableSpecificWarnings) 295 | 296 | 297 | kernel32.lib;advapi32.lib;ws2_32.lib;libpq.lib;libpgport.lib;libintl-8.lib 298 | $(OutDir)/$(TargetFileName) 299 | false 300 | Console 301 | true 302 | true 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /msvc/bin.2010.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {5f942836-8862-4aa3-8573-a6b80a4fbe4f} 14 | 15 | 16 | {e0adaf77-900d-4307-9a5f-6be049d0d93b} 17 | 18 | 19 | {5cf8792b-6351-4f2c-88db-784d7d8a425c} 20 | 21 | 22 | {6a46f2b1-6c15-44c2-bf14-500562f0fc30} 23 | 24 | 25 | 26 | 27 | doc 28 | 29 | 30 | doc 31 | 32 | 33 | doc 34 | 35 | 36 | doc 37 | 38 | 39 | doc 40 | 41 | 42 | doc 43 | 44 | 45 | 46 | regress\expected 47 | 48 | 49 | regress\expected 50 | 51 | 52 | regress\sql 53 | 54 | 55 | regress\sql 56 | 57 | 58 | doc 59 | 60 | 61 | 62 | 63 | 64 | src 65 | 66 | 67 | src 68 | 69 | 70 | src 71 | 72 | 73 | 74 | 75 | include 76 | 77 | 78 | include 79 | 80 | 81 | -------------------------------------------------------------------------------- /msvc/bin.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 96 | 99 | 100 | 101 | 102 | 103 | 104 | 109 | 112 | 113 | 116 | 117 | 120 | 121 | 122 | 127 | 130 | 131 | 134 | 135 | 136 | 139 | 142 | 143 | 146 | 147 | 150 | 151 | 154 | 155 | 156 | 159 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /msvc/lib.2010.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 8.3 6 | Win32 7 | 8 | 9 | 8.3 10 | x64 11 | 12 | 13 | 8.4 14 | Win32 15 | 16 | 17 | 8.4 18 | x64 19 | 20 | 21 | 9.0 22 | Win32 23 | 24 | 25 | 9.0 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2} 45 | lib 46 | Win32Proj 47 | 48 | 49 | 50 | DynamicLibrary 51 | Unicode 52 | true 53 | Windows7.1SDK 54 | 55 | 56 | DynamicLibrary 57 | Unicode 58 | true 59 | Windows7.1SDK 60 | 61 | 62 | DynamicLibrary 63 | Unicode 64 | true 65 | Windows7.1SDK 66 | 67 | 68 | DynamicLibrary 69 | Unicode 70 | true 71 | Windows7.1SDK 72 | 73 | 74 | DynamicLibrary 75 | Unicode 76 | true 77 | Windows7.1SDK 78 | 79 | 80 | DynamicLibrary 81 | Unicode 82 | true 83 | Windows7.1SDK 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | <_ProjectFileVersion>10.0.30319.1 109 | $(SolutionDir)/bin/x86/$(Configuration)/lib/ 110 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ 111 | $(SolutionDir)/bin/x86/$(Configuration)/lib/ 112 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ 113 | $(SolutionDir)/bin/x86/$(Configuration)/lib/ 114 | $(SolutionDir)/bin/$(Platform)/$(Configuration)/lib/ 115 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 116 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 117 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 118 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 119 | $(SolutionDir)/obj/x86/$(Configuration)/$(ProjectName)/ 120 | $(SolutionDir)/obj/$(Platform)/$(Configuration)/$(ProjectName)/ 121 | false 122 | false 123 | false 124 | false 125 | false 126 | false 127 | C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\9.0\include\server;C:\Program Files %28x86%29\PostgreSQL\9.0\include;$(IncludePath) 128 | C:\Program Files\PostgreSQL\9.0\include\server\port\win32_msvc;C:\Program Files\PostgreSQL\9.0\include\server\port\win32;C:\Program Files\PostgreSQL\9.0\include\server;C:\Program Files\PostgreSQL\9.0\include;$(IncludePath) 129 | C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;$(IncludePath) 130 | C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.4\include\server;C:\Program Files %28x86%29\PostgreSQL\8.4\include;$(IncludePath) 131 | C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server;C:\Program Files %28x86%29\PostgreSQL\8.3\include;$(IncludePath) 132 | C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32_msvc;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server\port\win32;C:\Program Files %28x86%29\PostgreSQL\8.3\include\server;C:\Program Files %28x86%29\PostgreSQL\8.3\include;$(IncludePath) 133 | C:\Program Files %28x86%29\PostgreSQL\9.0\lib;$(LibraryPath) 134 | C:\Program Files\PostgreSQL\9.0\lib;$(LibraryPath) 135 | C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) 136 | C:\Program Files %28x86%29\PostgreSQL\8.4\lib;$(LibraryPath) 137 | C:\Program Files %28x86%29\PostgreSQL\8.3\lib;$(LibraryPath) 138 | C:\Program Files %28x86%29\PostgreSQL\8.3\lib;$(LibraryPath) 139 | pg_reorg 140 | pg_reorg 141 | pg_reorg 142 | pg_reorg 143 | pg_reorg 144 | pg_reorg 145 | 146 | 147 | 148 | ../include;%(AdditionalIncludeDirectories) 149 | WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 150 | 151 | 152 | MultiThreadedDLL 153 | 154 | 155 | Level3 156 | false 157 | 158 | 159 | CompileAsC 160 | 4005;4996;4018;%(DisableSpecificWarnings) 161 | 162 | 163 | postgres.lib 164 | $(OutDir)/$(TargetFileName) 165 | false 166 | Console 167 | true 168 | true 169 | MachineX86 170 | 171 | 172 | 173 | 174 | ../include;%(AdditionalIncludeDirectories) 175 | WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 176 | 177 | 178 | MultiThreadedDLL 179 | 180 | 181 | Level3 182 | false 183 | 184 | 185 | CompileAsC 186 | 4005;4996;4018;%(DisableSpecificWarnings) 187 | 188 | 189 | postgres.lib 190 | $(OutDir)/$(TargetFileName) 191 | false 192 | Console 193 | true 194 | true 195 | 196 | 197 | 198 | 199 | ../include;%(AdditionalIncludeDirectories) 200 | WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 201 | 202 | 203 | MultiThreadedDLL 204 | 205 | 206 | Level3 207 | false 208 | 209 | 210 | CompileAsC 211 | 4005;4996;4018;%(DisableSpecificWarnings) 212 | 213 | 214 | postgres.lib 215 | $(OutDir)/$(TargetFileName) 216 | false 217 | Console 218 | true 219 | true 220 | MachineX86 221 | 222 | 223 | 224 | 225 | ../include;%(AdditionalIncludeDirectories) 226 | WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 227 | 228 | 229 | MultiThreadedDLL 230 | 231 | 232 | Level3 233 | false 234 | 235 | 236 | CompileAsC 237 | 4005;4996;4018;%(DisableSpecificWarnings) 238 | 239 | 240 | postgres.lib 241 | $(OutDir)/$(TargetFileName) 242 | false 243 | Console 244 | true 245 | true 246 | 247 | 248 | 249 | 250 | ../include;%(AdditionalIncludeDirectories) 251 | _USE_32BIT_TIME_T;WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 252 | 253 | 254 | MultiThreadedDLL 255 | 256 | 257 | Level3 258 | false 259 | 260 | 261 | CompileAsC 262 | 4005;4996;4018;%(DisableSpecificWarnings) 263 | 264 | 265 | postgres.lib 266 | $(OutDir)/$(TargetFileName) 267 | false 268 | Console 269 | true 270 | true 271 | MachineX86 272 | 273 | 274 | 275 | 276 | ../include;%(AdditionalIncludeDirectories) 277 | _USE_32BIT_TIME_T;WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 278 | 279 | 280 | MultiThreadedDLL 281 | 282 | 283 | Level3 284 | false 285 | 286 | 287 | CompileAsC 288 | 4005;4996;4018;%(DisableSpecificWarnings) 289 | 290 | 291 | postgres.lib 292 | $(OutDir)/$(TargetFileName) 293 | false 294 | Console 295 | true 296 | true 297 | 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /msvc/lib.2010.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | src 24 | 25 | 26 | src 27 | 28 | 29 | 30 | 31 | include 32 | 33 | 34 | include 35 | 36 | 37 | -------------------------------------------------------------------------------- /msvc/lib.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 75 | 78 | 81 | 84 | 87 | 90 | 93 | 96 | 99 | 100 | 101 | 102 | 103 | 104 | 109 | 112 | 113 | 116 | 117 | 120 | 121 | 122 | 127 | 130 | 131 | 134 | 135 | 136 | 139 | 140 | 143 | 144 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /msvc/pg_reorg.2010.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin.2010", "bin.2010.vcxproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib.2010", "lib.2010.vcxproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | 8.3|Win32 = 8.3|Win32 11 | 8.3|x64 = 8.3|x64 12 | 8.4|Win32 = 8.4|Win32 13 | 8.4|x64 = 8.4|x64 14 | 9.0|Win32 = 9.0|Win32 15 | 9.0|x64 = 9.0|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.3|Win32.ActiveCfg = 8.3|Win32 19 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.3|Win32.Build.0 = 8.3|Win32 20 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.3|x64.ActiveCfg = 8.3|x64 21 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.3|x64.Build.0 = 8.3|x64 22 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.4|Win32.ActiveCfg = 8.4|Win32 23 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.4|Win32.Build.0 = 8.4|Win32 24 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.4|x64.ActiveCfg = 8.4|x64 25 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.8.4|x64.Build.0 = 8.4|x64 26 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.9.0|Win32.ActiveCfg = 9.0|Win32 27 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.9.0|Win32.Build.0 = 9.0|Win32 28 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.9.0|x64.ActiveCfg = 9.0|x64 29 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.9.0|x64.Build.0 = 9.0|x64 30 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|Win32.ActiveCfg = 8.3|Win32 31 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|Win32.Build.0 = 8.3|Win32 32 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|x64.ActiveCfg = 8.3|x64 33 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.3|x64.Build.0 = 8.3|x64 34 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|Win32.ActiveCfg = 8.4|Win32 35 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|Win32.Build.0 = 8.4|Win32 36 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|x64.ActiveCfg = 8.4|x64 37 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.8.4|x64.Build.0 = 8.4|x64 38 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|Win32.ActiveCfg = 9.0|Win32 39 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|Win32.Build.0 = 9.0|Win32 40 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|x64.ActiveCfg = 9.0|x64 41 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.9.0|x64.Build.0 = 9.0|x64 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /msvc/pg_reorg.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual C++ Express 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin", "bin.vcproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib", "lib.vcproj", "{B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|Win32 = Release|Win32 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.Release|Win32.ActiveCfg = Release|Win32 14 | {B6B37F22-9E44-4240-AAA0-650D4AC2C1E2}.Release|Win32.Build.0 = Release|Win32 15 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.Release|Win32.ActiveCfg = Release|Win32 16 | {B6B37F22-9E44-4240-AAA0-650D4AC2C2E2}.Release|Win32.Build.0 = Release|Win32 17 | EndGlobalSection 18 | GlobalSection(SolutionProperties) = preSolution 19 | HideSolutionNode = FALSE 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /msvc/readme.txt: -------------------------------------------------------------------------------- 1 | How to build with Microsoft Visual C++ Express 2005 2 | 3 | You might need: 4 | 1. Register PostgreSQL directory to your environment. 5 | 2. Resolve redefinitions of ERROR macro. 6 | 7 | ---- 8 | 1. Register PostgreSQL directory to your environment. 9 | 10 | The directory configuration options are found in: 11 | Tool > Option > Projects and Solutions > VC++ directory 12 | 13 | You might need to add the following directories: 14 | into "include files" 15 | - C:\Program Files\PostgreSQL\8.4\include 16 | - C:\Program Files\PostgreSQL\8.4\include\internal 17 | - C:\Program Files\PostgreSQL\8.4\include\server 18 | - C:\Program Files\PostgreSQL\8.4\include\server\port\win32 19 | - C:\Program Files\PostgreSQL\8.4\include\server\port\win32_msvc 20 | into "library files" 21 | - C:\Program Files\PostgreSQL\8.4\lib 22 | 23 | ---- 24 | 2. Resolve redefinitions of ERROR macro. 25 | 26 | It might be a bad manner, but I'll recommend to modify your wingdi.h. 27 | 28 | --- wingdi.h 2008-01-18 22:17:42.000000000 +0900 29 | +++ wingdi.fixed.h 2010-03-03 09:51:43.015625000 +0900 30 | @@ -101,11 +101,10 @@ 31 | #endif // (_WIN32_WINNT >= _WIN32_WINNT_WINXP) 32 | 33 | /* Region Flags */ 34 | -#define ERROR 0 35 | +#define RGN_ERROR 0 36 | #define NULLREGION 1 37 | #define SIMPLEREGION 2 38 | #define COMPLEXREGION 3 39 | -#define RGN_ERROR ERROR 40 | 41 | /* CombineRgn() Styles */ 42 | #define RGN_AND 1 43 | --------------------------------------------------------------------------------