web-dev-qa-db-ja.com

PostgreSQLを9.4から12にアップグレードする際のOIDの排除

現在、本番環境でPostgreSQL 9.4を実行していますが、サーバーでOSのアップグレードを行っている最中なので、PostgreSQLのバージョンを最新(12)にアップグレードして、潜在的に利用可能な新機能のいくつかを利用する。ただし、さまざまなデータベースのテーブルのいくつかはかなり前に作成されました(2008年より前のように、少なくとも一部のケースでは2000年より前の可能性があります)。これらのデータベースには、OID(定義ではWITH OIDS=TRUE)を使用する多くのテーブルが含まれています。

さらに、コードベースの大部分を検索して、テーブル内のOID列への参照を探し、いくつかのインスタンスを見つけました。=を明示的に呼び出すクエリがあります。 OID列。幸いにも、これらのケースの多くはtooなく、それらの大部分はシステムテーブルを参照しています。 (つまり、SELECT oid FROM pg_namespace...FROM pg_class)。

プロセスのこの時点で、9.4データベースからダンプされたデータに対してpg_upgradeを実行すると、データベースにOIDがなくなるまで続行されないことが明記されています。過去数回のリリースで徐々に段階的に廃止されており、12では基本的に重要ではなくなっていることを理解していますが、pg_upgradeからの提案はOID列を削除することです先に進む前に、ほとんど関係のないコラムでは「やり過ぎ」だと思います。

この時点で-そして私はまだこれまでずっと考えていなかったことをすぐに認めます-影響を受けるテーブル定義のWITH OIDSスイッチをFALSEアップグレードを続行できるようにするには?これが反転しても、既存のOID列はデータベース構造の一部のままになりますか?(私はそう思うと思いますが、自動アップグレードによっていくつか面白いことができます)?

理想的な状況では、最終的にデータベースからOIDを完全に削除したいと思います。ただし、1人のIT部門であるため、後の評価のために「リストに載る」必要があります。とりあえず、最新のPostgreSQLバージョンでデータベースを稼働させたいのですが、すぐに操作に影響を与えることなくそうする機会があります。

2
G_Hosa_Phat

テーブルのoidsがコードで参照されている場合、単純にそれらを取り除くことはできません。おそらく古いコードは自動生成された識別子としてoidに依存しています。これらの列に主キーまたは他のインデックスはありますか?

アップグレードでoidsを保持する方法は次のとおりです。

  • アップグレード前の古いデータベース:

    ALTER TABLE has_oids ADD newoid bigint NOT NULL;
    UPDATE has_oids SET newoid = oid;
    ALTER TABLE has_oids SET WITHOUT OIDS;
    
  • アップグレード後、新しいデータベースで:

    ALTER TABLE has_oids RENAME newoid TO oid;
    CREATE SEQUENCE has_oids_oid_seq OWNED BY has_oids.oid;
    ALTER TABLE has_oids ALTER oid SET DEFAULT nextval('has_oids_oid_seq');
    SELECT setval('has_oids_oid_seq', ???);
    

ここに、 ???は、テーブルに存在する最高のoidよりも大きい数値です。

また、oid列のインデックスまたは制約にも注意する必要があります。

1
Laurenz Albe

@LaurenzAlbeの回答からの提案を使用して、psqlコマンドライン(_pg_dump_および_pg_restore_を含む)を使用してデータベースに必要なすべての変更を行うバッチファイルを作成しました。また、プロセスの各ステップをテキストファイルに記録し、問題が発生した場合は個別のエラーログファイルを作成します。何かが失敗した場合は、現在のデータベースを更新前の状態に復元するように求められます(推奨されます)。

その答えが私の最終的な解決策の基礎を形成したので、私はそれを答えとして受け入れました。この回答は、既存のOIDが原因でPostgreSQL v12へのアップグレードで問題が発生している他のすべての人に役立つことを期待して、私が思いついたものを示すために提供します。

ここにはいくつかの注意点と「落とし穴」がありますが、このスクリプトを使用して、データベース内の_WITH OIDS=TRUE_フラグが設定されたすべてのテーブルを更新し、PostgreSQLバージョン9.4からバージョン12への移行を完了しました。

ノート

  1. このバッチファイルは、以前のバージョンのPostgreSQLから新しいバージョン12のインスタンスにデータを移行するために_pg_upgrade_をすでに使用しており、OIDを使用する既存のテーブルが原因でアップグレードが失敗したことを前提としています。この場合、_pg_upgrade_は_tables_with_oids.txt_という名前のテキストファイルを生成しているはずです。すべての変更を「自動的に」行うには、バッチファイルがこのファイルにアクセスできる必要があります。
  2. また、@ LaurenzAlbeで提案されている既存のOID値を使用する代わりに、_1_で各「新しいOID」列のシーケンスを開始することにしました。特定のOID値を明示的に参照していて何も見つからなかったものがないかどうかを確認するために、コードとデータベースを徹底的に調べました。私が見つけたのは、OIDへの参照呼び出しを行ってテーブルから他の値を取得することだけだったので、呼び出しを行い、各テーブルのOID。を再起動することにしました。
    • 注意してください:これはデータベースに問題を引き起こす可能性がありますORアプリケーションどちらかで何かが特定のレコードに関連付けられた特定の値を探している場合。
    • 既存のOID値を使用する場合(@LaurenzAlbeで推奨)、異なる方法でいくつかのことを行う必要があります。つまり、古いOID列からデータが入力されるまで、新しいOID列に_NOT NULL_制約が設定されるのを待つ必要があります。また、_NOT NULL_制約を追加する前に、nextval()のデフォルト値を設定して、すべてのレコードにこの列が入力されていることを確認することもできます。
  3. このバッチファイルは、アップグレード前とアップグレード後の一部を実行するのではなく、1回の実行ですべてを実行します。使用するPostgreSQLのインスタンスがいくつかあったので、1つのテストデータベースですべての「問題」テーブルを変換し、pg_restoreを使用して新しいPostgreSQL 12データベースインスタンスに取り込む前にそのデータをダンプすることができました。
  4. このバッチファイルDOES NOT更新されたデータをデータベースからダンプするか、新しいv12サーバーにインポートします。私はまだそのステップを最終的に制御したいと思っていましたが、これを行う_:FINALIZE_セクションに数行を追加することはそれほど難しくないはずです。

バッチファイル

このバッチファイルは、_tables_with_oids.txt_によって生成された_pg_upgrade_ファイルを1行ずつ読み取り、次のことを行います。

データベース

  1. 見つかったデータベースごとに(ファイル内で_Database:_で始まる行として識別されます)、問題が発生した場合に備えて、データベース全体の「バックアップ」ダンプファイルが作成されます。
  2. 元のoidに依存しているビューがいくつかあり、その列を削除できない場合があります。スクリプトは依存関係を照会し、見つかった定義をダンプしてから、依存ビューを削除します。
  3. 次のデータベースに移動すると、前のデータベースからダンプまたはドロップされたビューが復元されます。

テーブル

  1. 各テーブル(で始まらない行が_Database:_で始まる行)では、スキーマとテーブル名が分割されます。
  2. 次に、スクリプトは現在のテーブルの所有者を取得して、新しいシーケンスに適用します(シーケンスは、新しい列でデフォルト値として使用されるために、テーブルと同じ所有者でなければなりません)
  3. テーブルにすべてのトリガーが無効になり、テーブルに変更が加えられたときにトリガーが発火するのを防ぎます(そしてlotに加えられた変更が行われます)。
  4. 現在のスキーマとテーブル名を使用して新しいシーケンスを作成し、(うまくいけば)一意のシーケンス名を_<schema>_<table>_oid_seq_の形式で生成します
  5. シーケンスの所有者をテーブルと同じに設定します(#2を参照)
  6. シーケンス上の適切なユーザー/グループに必要な権限を付与します。
    • このバッチファイルを使用する場合は、必要なアクセス許可とそのアクセス許可をだれが必要とするかを決定する必要があります。
  7. テーブルに新しい列(newoid)を作成します。
  8. シーケンスを使用して新しいレコードの値を自動インクリメントするようにnewoid列の定義を変更します(これに関する上記の私のメモを参照してください)
  9. テーブルの定義を_WITHOUT OIDS_(に変更します。これにより、既存のoid列が自動的に削除されます)。
  10. #7で作成した新しい列の名前をoidに変更します。
  11. #4で作成した新しいシーケンスを、新しく作成したoid列に関連付けます。これは、新しいoid列が将来データベースから削除された場合(すべての参照を根絶する方法がわかった)、新しく作成したシーケンスも削除する必要があります。
  12. テーブルのすべてのトリガーを再度有効にします。

コード(最終的に)

さて、これで説明はすべて終了しました。バッチファイル用に作成したコードは次のとおりです。お役に立てれば幸いです。私はバッチファイル自体をかなり徹底的に文書化しようとしました。個々の環境に対して明示的に定義する必要がある値は、コード内の山括弧とすべて大文字で識別されます_<YOUR SETTING HERE>_

_@ECHO OFF
CLS

:: --------------------------------------------------------------------
:: SETLOCAL to ensure that all variables are cleared from memory at the
:: end of the batch file's execution
:: --------------------------------------------------------------------
SETLOCAL EnableDelayedExpansion

SET "startTime=%time: =0%"

:: --------------------------------------------------------------------
:: >>>>>>> MAKE SURE TO SET THESE ACCORDING TO YOUR ENVIRONMENT <<<<<<<
:: PostgreSQL Variables
:: --------------------------------------------------------------------
SET PGPASSWORD=<SUPERUSER/ADMINISTRATIVE PASSWORD>
SET PGSQLHost=<HOSTNAME OF SERVER RUNNING THE "OLD" DATA>
SET PGSQLBin=<PATH TO THE POSTGRESQL bin DIRECTORY FOR THE "OLD" INSTANCE>
SET BackupPath=<PATH WHERE YOU WANT TO STORE BACKUPS AND LOGS>\%PGSQLHost%

:: CHECK FOR/CREATE THE BACKUP/LOG DIRECTORY
IF NOT EXIST %BackupPath%\ (
    MD %BackupPath%\
)

FOR /f "tokens=*" %%a in ('powershell get-date -format "{yyyyMMdd}"') DO SET CURRDATE=%%a

SET TEMPLOG="%BackupPath%\pgsql%CURRDATE%.tmp"
SET ERRORLOG="%BackupPath%\pgsql_12_update_errors_%CURRDATE%.log"
SET SUCCESSLOG="%BackupPath%\pgsql_12_update_%CURRDATE%.log"

:: --------------------------------------------------------------------
:: THIS (PUSHD) IS USED TO AVOID UNC PATHS AS THE COMMAND Prompt CAN'T
:: USE THEM AS THE CURRENT DIRECTORY.
:: See https://docs.Microsoft.com/en-us/windows-server/administration/windows-commands/pushd
::     for more information on PUSHD/POPD
:: --------------------------------------------------------------------
PUSHD "%PGSQLBin%"
SET BinPath=%cd%
SET TableCount = 0

ECHO --------------------------------------------------------------------
ECHO   Update started at %startTime%
ECHO   Preparing list of PostgreSQL 9.4 tables to update...
ECHO --------------------------------------------------------------------
ECHO.

ECHO -------------------------------------------------------------------- > %SUCCESSLOG%
ECHO   Removing OID references to facilitate upgrade from PostgreSQL 9.4 >> %SUCCESSLOG%
ECHO     to PostgreSQL 12 >> %SUCCESSLOG%
ECHO. >> %SUCCESSLOG%
ECHO   See official release announcement for details >> %SUCCESSLOG%
ECHO     https://www.postgresql.org/docs/12/release-12.html >> %SUCCESSLOG%
ECHO. >> %SUCCESSLOG%
ECHO   PostgreSQL 9.4 update started at %startTime% >> %SUCCESSLOG%
ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
ECHO. >> %SUCCESSLOG%

:: READ THE tables_with_oids.txt FILE LINE-BY-LINE
FOR /f "eol=; tokens=1 delims=," %%T IN (%BackupPath%\tables_with_oids.txt) DO (
    SET oidbuffer=%%T

    :: --------------------------------------------------------------------
    :: LINES THAT DON'T BEGIN WITH `Database:` ARE THE INDIVIDUAL TABLES
    :: WHICH CONTAIN OID'S AND NEED TO BE UPDATED
    :: --------------------------------------------------------------------
    IF NOT !oidbuffer:~0^,9!==Database: (
        SET NameBuffer=%%T

        :: SPLIT THE SCHEMA AND TABLE NAMES FROM THE CURRENT LINE
        FOR /f "tokens=1,2 delims=." %%a IN ("!NameBuffer!") DO SET SchemaName=%%a&SET TableName=%%b

        IF NOT [!DBName!]==[] (
            IF NOT [!TableName!]==[] (
                CALL :TRIM TableName

                IF NOT [!SchemaName!]==[] (
                    CALL :TRIM SchemaName

                    ECHO Updating !SchemaName!.!TableName! in !DBName! on %PGSQLHost%
                    ECHO UPDATING !SchemaName!.!TableName! IN !DBName! ON %PGSQLHost% >> %SUCCESSLOG%


                    :: GET THE OWNER OF THE TABLE
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "SELECT tableowner FROM pg_tables WHERE schemaname = '!SchemaName!' AND tablename = '!TableName!';" > %BackupPath%\tblown.tmp

                    :: --------------------------------------------------------------------
                    :: CODE FROM STACKOVERFLOW FOR psql.exe ERROR HANDLING IN BATCH FILE
                    :: (USED REPEATEDLY)
                    :: https://stackoverflow.com/a/30775383/2569697
                    :: --------------------------------------------------------------------
                    IF NOT errorlevel 1 (
                        FOR /F "usebackq delims=" %%g IN (%BackupPath%\tblown.tmp) DO (
                            SET TABLEOWNER=%%g
                            ECHO - Table owner is %%g >> %SUCCESSLOG%
                        )
                    ) ELSE (
                        ECHO Error retrieving table owner from !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: DISABLE ALL TRIGGERS ON THE TABLE
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER TABLE \"!SchemaName!\".\"!TableName!\" DISABLE TRIGGER ALL;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - Triggers disabled >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error adding newoid column to !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: CREATE A NEW SEQUENCE TO BE USED FOR THE NEW oid COLUMN
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "CREATE SEQUENCE \"!SchemaName!\".!SchemaName!_!TableName!_oid_seq;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - New sequence created for `oid` column: `!SchemaName!_!TableName!_oid_seq` >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error creating oid sequence for !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: SET THE OWNER OF THE NEW SEQUENCE TO THE SAME AS THE TABLE (see above)
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER SEQUENCE \"!SchemaName!\".!SchemaName!_!TableName!_oid_seq OWNER TO \"!TABLEOWNER!\"" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - Ownership of `!SchemaName!_!TableName!_oid_seq` sequence set to !TABLEOWNER! >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error altering ownership of oid sequence for !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: GRANT USER/GROUP PERMISSIONS ON THE SEQUENCE
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "GRANT ALL ON SEQUENCE \"!SchemaName!\".!SchemaName!_!TableName!_oid_seq TO <USER/GROUP NAME>" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - Permissions granted on `!SchemaName!_!TableName!_oid_seq` sequence for users/groups >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error granting permissions on oid sequence for !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: CREATE THE newoid COLUMN IN TABLE
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER TABLE \"!SchemaName!\".\"!TableName!\" ADD newoid bigint NOT NULL DEFAULT nextval('\"!SchemaName!\".!SchemaName!_!TableName!_oid_seq');" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - `newoid` column created >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error adding newoid column to !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: REMOVE THE OID ASSOCIATION WITH THE TABLE - THIS ALSO REMOVES THE AUTO-CREATED oid COLUMN
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER TABLE \"!SchemaName!\".\"!TableName!\" SET WITHOUT OIDS;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - Table definition updated to remove OID association >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error altering table definition for !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: RENAME THE newoid COLUMN TO REPLACE THE ORIGINAL oid COLUMN
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER TABLE \"!SchemaName!\".\"!TableName!\" RENAME newoid TO oid;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - `newoid` column renamed to `oid` >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error renaming newoid column in !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: ASSOCIATE THE NEW SEQUENCE WITH THE NEW oid COLUMN
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER SEQUENCE \"!SchemaName!\".!SchemaName!_!TableName!_oid_seq OWNED BY \"!SchemaName!\".\"!TableName!\".oid;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - `!SchemaName!_!TableName!_oid_seq` sequence explicitly linked to `oid` column >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error altering column association of oid sequence for !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )

                    :: REENABLE ALL TRIGGERS ON THE TABLE
                    %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "ALTER TABLE \"!SchemaName!\".\"!TableName!\" ENABLE TRIGGER ALL;" > %TEMPLOG%

                    IF NOT errorlevel 1 (
                        ECHO - All triggers reenabled on !SchemaName!.!TableName! table >> %SUCCESSLOG%
                    ) ELSE (
                        ECHO Error reenabling triggers on !SchemaName!.!TableName!: %errorlevel% >> %ERRORLOG%
                        GOTO :ERRORHANDLER
                    )
                )

                SET /A TableCount=TableCount+1
                ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
                ECHO !DBName!.!SchemaName!.!TableName! on %PGSQLHost% >> %SUCCESSLOG%
                ECHO was updated successfully. >> %SUCCESSLOG%
                ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
                ECHO. >> %SUCCESSLOG%
            )
        )
    ) ELSE (
        :: --------------------------------------------------------------------
        :: THE `DBName` VARIABLE WON'T BE SET IF THIS IS THE FIRST LINE, BUT
        :: AFTER EACH DATABASE HAS BEEN UPDATED, WE NEED TO RESTORE ANY VIEWS
        :: THAT WE DUMPED FROM THE PREVIOUS DATABASE.
        :: --------------------------------------------------------------------
        IF NOT [!DBName!]==[] (
            FOR %%F IN (%BackupPath%\!DBName!\*.dmp) DO (
                %BinPath%\pg_restore -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> -d !DBName! "%BackupPath%\!DBName!\%%~nF.dmp"

                IF NOT errorlevel 1 (
                    ECHO - View restored to !DBName!.!SchemaName! from %%~nF.dmp >> %SUCCESSLOG%
                ) ELSE (
                    ECHO Error restoring view from %%~nF to !DBName!.!SchemaName!: %errorlevel% >> %ERRORLOG%
                    GOTO :ERRORHANDLER
                )
            )

        )

        SET DBName=%%T
        SET DBName=!DBName:Database: =!
        CALL :TRIM DBName

        ECHO --------------------------------------------------------------------
        ECHO   Backing up !DBName! database on %PGSQLHost%
        ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
        ECHO   BACKING UP `!DBName!` DATABASE ON %PGSQLHost% >> %SUCCESSLOG%

        :: CHECK FOR/CREATE THE BACKUP PATH
        IF NOT EXIST %BackupPath%\!DBName!\ (
            MD %BackupPath%\!DBName!\
        )

        :: DUMP THE CURRENT DATABASE AS A BACKUP IN CASE SOMETHING FAILS
        %BinPath%\pg_dump -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> -E UTF8 -Fc -f %BackupPath%\!DBName!\!DBName!.gz !DBName!

        :: CHECK FOR ANY VIEWS THAT ARE DEPENDENT ON EXISTING `oid` COLUMNS
        ECHO   Getting oid dependencies in !DBName! database
        ECHO   GETTING OID DEPENDENCIES IN `!DBName!` DATABASE >> %SUCCESSLOG%
        %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "SELECT n.nspname || '.' || c.relname AS table_name FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace) LEFT JOIN pg_catalog.pg_attribute a ON (c.oid = a.attrelid AND a.attnum > 0 AND NOT a.attisdropped) LEFT JOIN pg_catalog.pg_stat_all_tables s ON (c.oid = s.relid) WHERE c.relkind  = 'v' AND (pg_catalog.pg_get_viewdef(c.oid, true) ~* '.oid' OR pg_catalog.pg_get_viewdef(c.oid, true) ~* ',oid' OR pg_catalog.pg_get_viewdef(c.oid, true) ~* ' oid') AND n."nspname" NOT LIKE 'pg_%%' AND n."nspname" NOT LIKE 'information_%%' GROUP BY n.nspname, c.relowner, c.relkind, c.relname, s.n_live_tup, c.oid ORDER BY n.nspname, c.relname;" > %BackupPath%\!DBName!\!DBName!dep.txt

        :: DUMP ANY DEPENDENT VIEWS TO SEPARATE FILES FOR RESTORATION LATER
        FOR /F "usebackq delims=" %%V IN (%BackupPath%\!DBName!\!DBName!dep.txt) DO (
            SET ViewNameBuffer=%%V

            FOR /f "tokens=1,2 delims=." %%a IN ("!ViewNameBuffer!") DO SET ViewSchema=%%a&SET ViewName=%%b
            %BinPath%\pg_dump -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> -E UTF8 -s -t \"!ViewSchema!\".\"!ViewName!\" -Ft -f %BackupPath%\!DBName!\!DBName!_!ViewSchema!_!ViewName!_def.dmp !DBName!

            IF NOT errorlevel 1 (
                ECHO - Dumped definition for !ViewSchema!.!ViewName! >> %SUCCESSLOG%
            ) ELSE (
                ECHO Error dumping definition for `!ViewSchema!.!ViewName!` view: %errorlevel% >> %ERRORLOG%
                GOTO :ERRORHANDLER
            )

            :: DROP THE DEPENDENT VIEW
            %BinPath%\psql -qtAX -h %PGSQLHost% -p 5432 -d !DBName! -U <SUPERUSER/ADMINISTRATIVE USERNAME> -c "DROP VIEW \"!ViewSchema!\".\"!ViewName!\";" > %TEMPLOG%

            IF NOT errorlevel 1 (
                ECHO - Dropped !ViewSchema!.!ViewName! view >> %SUCCESSLOG%
            ) ELSE (
                ECHO Error dropping `!ViewSchema!.!ViewName!` view: %errorlevel% >> %ERRORLOG%
                GOTO :ERRORHANDLER
            )
        )

        ECHO   Updating tables in !DBName! database on %PGSQLHost%
        ECHO --------------------------------------------------------------------
        ECHO   UPDATING TABLES IN `!DBName!` DATABASE ON %PGSQLHost% >> %SUCCESSLOG%
        ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
    )
)

ECHO.
ECHO --------------------------------------------------------------------
ECHO   Cleaning up and finalizing the update
ECHO --------------------------------------------------------------------
GOTO :FINALIZE

:ERRORHANDLER
:: IF SOMETHING BREAKS, Prompt TO RESTORE THE DATABASE FROM THE BACKUP
(SET /P restore=Do you want to restore the !DBName! database on %PGSQLHost% from the backup? [Y/N]: )
:: --------------------------------------------------------------------
:: The /i switch allows the test to be case-insensitive (NT-based only)
:: --------------------------------------------------------------------
IF /i "%restore%"=="Y" GOTO RESTOREBACKUP
IF /i "%restore%"=="N" GOTO :FINALIZE
ECHO Invalid selection. Please type "Y" or "N".
ECHO.
GOTO :ERRORHANDLER

:RESTOREBACKUP
:: RESTORE THE DATABASE FROM THE BACKUP CREATED BEFORE CHANGES WERE MADE
ECHO Restoring !DBName!
%BinPath%\dropdb -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> !DBName!
%BinPath%\createdb -E UTF8 -T template0 -O Developers -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> !DBName!
%BinPath%\pg_restore -h %PGSQLHost% -p 5432 -U <SUPERUSER/ADMINISTRATIVE USERNAME> -d !DBName! "%BackupPath%\!DBName!\!DBName!.gz"
ECHO `!DBName!` on %PGSQLHost% restored from backup
ECHO `!DBName!` on %PGSQLHost% restored from backup >> %SUCCESSLOG%

:FINALIZE
:: RELEASE RESOURCES ALLOCATED BY PUSHD
POPD

SET "endTime=%time: =0%"

:: --------------------------------------------------------------------
:: CODE FROM STACKOVERFLOW FOR REPORTING ELAPSED TIME OF PROCESS
:: https://stackoverflow.com/a/9935540/2569697
:: --------------------------------------------------------------------
:: Get elapsed time:
:: --------------------------------------------------------------------
SET "end=!endTime:%time:~8,1%=%%100)*100+1!"  &  set "start=!startTime:%time:~8,1%=%%100)*100+1!"
SET /A "elap=((((10!end:%time:~2,1%=%%100)*60+1!%%100)-((((10!start:%time:~2,1%=%%100)*60+1!%%100)"

:: --------------------------------------------------------------------
:: Convert elapsed time to HH:MM:SS:CC format:
:: --------------------------------------------------------------------
SET /A "cc=elap%%100+100,elap/=100,ss=elap%%60+100,elap/=60,mm=elap%%60+100,hh=elap/60+100"

:: DISPLAY AND WRITE THE RESULTS OF THE UPDATE TO THE LOG FILE
ECHO.
ECHO --------------------------------------------------------------------
ECHO Update completed at %endTime%
ECHO --------------------------------------------------------------------
ECHO Elapsed Time:         %hh:~1%%time:~2,1%%mm:~1%%time:~2,1%%ss:~1%%time:~8,1%%cc:~1%
ECHO.
ECHO %TableCount% tables were updated on %PGSQLHost%.

ECHO. >> %SUCCESSLOG%
ECHO -------------------------------------------------------------------- >> %SUCCESSLOG%
ECHO Update completed at %endTime% >> %SUCCESSLOG%
ECHO --------------------------------------------------------------------
ECHO Elapsed Time:         %hh:~1%%time:~2,1%%mm:~1%%time:~2,1%%ss:~1%%time:~8,1%%cc:~1% >> %SUCCESSLOG%
ECHO. >> %SUCCESSLOG%
ECHO %TableCount% tables were successfully updated on %PGSQLHost%. >> %SUCCESSLOG%

:: DELETE THE TEMPORARY FILES USED
DEL /F /Q %TEMPLOG%
DEL /F /Q %BackupPath%\tblown.tmp
ENDLOCAL
GOTO :EOF

:: --------------------------------------------------------------------
:: CODE FROM STACKOVERFLOW FOR TRIMMING TRAILING/LEADING WHITESPACE
:: FROM A STRING VALUE
:: https://stackoverflow.com/a/19686956/2569697
:: --------------------------------------------------------------------

:TRIM
SETLOCAL EnableDelayedExpansion
CALL :TRIMSUB %%%1%%
ENDLOCAL & SET %1=%tempvar%
GOTO :EOF

:TRIMSUB
SET tempvar=%*
GOTO :EOF
_

これを書いているときに遭遇した特定の問題の解決策を見つけた場所を思い出すことができる場合に、クレジットを与えるために最善を尽くしました。私はそれらすべてを捕らえなかったと確信していますが、帰属のない貢献を認めた場合はご容赦ください。

0
G_Hosa_Phat