DDL replication
===============

DDLはデータ定義言語の略で、データベースオブジェクトを作成、変更、および削除するSQL言語のサブセットです。

操作の利便性と正確性を維持するために、
PGDはほとんどのDDLアクションをレプリケートしますが、次の例外を除きます。

-  一時的なまたはログに記録されていない関係

-  特定のDDLステートメントほとんどの場合、長時間実行

-  ロックコマンド ``LOCK``

-  テーブルメンテナンスコマンド ``VACUUM`` 、\ ``ANALYZE``
   、\ ``CLUSTER`` 、\ ``REINDEX``

-  オートバキュームのアクション

・操作コマンド ``CHECKPOINT`` 、\ ``ALTER SYSTEM``

-  データベースまたはテーブルスペースに関連するアクション

自動DDLレプリケーションにより、
DDL変更をすべてのノードに手動で配布し、一貫性を確認する必要がなく、特定のDDL変更が簡単になります。

デフォルトのレプリケーションセットでは、
DDLはデフォルトですべてのノードにレプリケートされます。
DDLをレプリケートするには、
DDLレプリケーションフィルタをレプリケーションセットに追加する必要があります。
 :ref:`DDLレプリケーションフィルタリング <DDLレプリケーションフィルタリング>`  を参照してください。

DDLレプリケーションに関して、
PGDはスタンドアロンのPostgreSQLとは大きく異なります。それを同じに扱うことは、PGDで最も一般的な問題です。

テーブルレプリケーションとの主な違いは、
DDLレプリケーションがDDLの結果ではなくステートメント自分自身をレプリケートすることです。これは、ほとんどの場合で非常にうまく機能しますが、
DDLをすべてのノードで同様に実行する必要があるという要件が導入されます。より微妙な点は、
DDLは、拡張機能ビルトインではなくによって導入されたデータ型を含む、すべてのデータ型固有のパラメーター設定に関して不変である必要があることです。たとえば、
DDLステートメントは、各ノードで使用されるデフォルトのエンコーディングで正しく実行される必要があります。

DDLレプリケーションオプション
-----------------------------

``bdr.ddl_replication``
パラメーターは、レプリケーション動作を指定します。

``bdr.ddl_replication = on`` はデフォルトであり、
DDLをデフォルトのレプリケーションセットにレプリケートします。デフォルトでは、すべてのノードを意味します。デフォルト以外のレプリケーションセットは、
 :ref:`DDL filter <Replication sets>` がない限りDDLをレプリケートしません

彼らのために定義されました。

ファンクション ``bdr.replicate_ddl_command()`` を使用して、
DDLを特定のレプリケーションセットにレプリケートすることもできます。これは、ノードがダウンしているときにDDLコマンドを実行する場合、またはサイト1のすべてのノードなど、ノードまたは担当セットのサブセットに存在するインデックスまたはパーティションを必要とする場合に役立ちます。

::

   SELECT bdr.replicate_ddl_command(
                   CREATE INDEX CONCURRENTLY ON foo (col7);,
                   ARRAY[site1],     -- the replication sets
                   on);              -- ddl_locking to apply

お勧めしませんが、 自動DDLレプリケーションをスキップし、
``bdr.ddl_replication``
構成パラメーターを使用して各ノードで手動で実行できます。

::

   SET bdr.ddl_replication = off;

設定すると、PGDは実行されたDDLコマンドのグローバルロックとレプリケーションの両方をスキップします。次に、すべてのノードでDDLを手動で実行する必要があります。

..  Warning::
   グローバルロックを使用せずに各ノードでDDLを手動で実行すると、競合するDDLまたはDMLが同時に実行される場合、PGDグループ全体のレプリケートが停止される場合があります。

``bdr.ddl_replication`` パラメーターは、
bdr_superuser、スーパーユーザー、または\ ``config``
ファイルでのみ設定できます。

PGDシステムでのDDLの実行
------------------------

PGDグループは、スタンドアロンのPostgreSQLサーバーと同じではありません。これは、集中ロックやトランザクションコーディネーターを使用しない非同期マルチマスターレプリケーションに基づいています。これは、
DDLの実行時に重要な意味を持ちます。

パラレルに実行されるDDLは、PGDで引き続き実行されます。
DDLの実行は、実行時に各ノードの並列オペレーションに影響を与えるパラメーターを尊重するため、ノード間の設定の違いに気づく場合があります。

競合するDDLの実行を防止します。そうしないと、
DDLレプリケーションでエラーが発生し、レプリケーションが停止します。

PGDは、これらの問題に対する3つのレベルの保護を提供します。

``ddl_locking = 'dml'``
は操作に最適なオプションであり、一度に1つのノードのみからDDLを実行する場合に使用できます。これはデフォルトではありませんが、
DDLを実行する場所を制御できる場合は、この設定を使用することをお勧めします。こうすることで、ノード間の競合が発生しないようにします。ノード内の競合はPostgreSQLによって既に処理されています。

``ddl_locking = on`` は最も厳密なオプションであり、
DDLが任意のノードから同時に実行される可能性があり、正確性を保証したい場合に最適です。

``ddl_locking = off``
は最も厳密でないオプションであり、一般的な使用は危険です。このオプションは、ロックを完全にスキップし、パフォーマンスのオーバーヘッドを回避するため、新しい空のデータベーススキーマを作成するときに役立つオプションです。

これらのオプションは、
bdr_superuser、スーパーユーザー、または\ ``config file``
でのみ設定できます。

``bdr.replicate_ddl_command``
を使用する場合、そのファンクションに渡されるDDLコマンドにのみ指定された\ ``bdr.ddl_locking``
設定を使用して、3番目の引数でこのパラメーターを直接設定できます。

DDLロックの詳細
---------------

2種類のロックは、PGDでレプリケートされたDDLの正しさを強制します。

最初の種類はグローバルDDLロックと呼ばれ、\ ``ddl_locking = on``
の場合にのみ使用されます。グローバルDDLロックは、各DDLステートメントの実行中にクラスターで他のDDLが実行されないようにします。これにより、一般的な場合に完全な正しさが保証されますが、多くの単純な場合には厳密すぎます。
PGDは、スキーマ変更が行われるトランザクションで初めてDDL操作のグローバルロックを取得します。これにより、クラスター内のDDL実行トランザクションが効果的にシリアル化されます。つまり、
DDLの実行中は、ノード上の他の接続は、別のテーブルに影響を与える場合でも、別のDDLコマンドを実行できません。

DDL操作のロックを取得するために、
DDLを実行するPGDノードはPGDグループ内の他のノードに接続し、
DDLを実行する排他的権限を付与するように求めます。ロック要求は通常のレプリケーションストリームによって送信され、ノードは同様にレプリケーションストリームによって応答します。したがって、ノードまたは少なくともノードの大部分が、レプリケーション遅延をほとんど発生せずに実行されることが重要です。そうしないと、ノードがDDLロックを取得するまでに時間がかかる場合があります。ノードの大部分が同意すると、
DDL実行が実行されます。

DDLロックの順序は、Raftプロトコルを使用して決定されます。
1つのノードで実行されたDDLステートメントは、他のすべてのノードで同じシーケンスで実行されます。

DDLを実行しているノードがクラスター内で実行された以前のすべてのDDLの効果を確認したことを確認するために、以前のDDLを実行したノードに追いつくまで待機します。現在のDDLを実行しているノードが、以前のDDLを実行したノードと比較してレプリケーションが遅れている場合、ロックの取得に時間がかかる場合があります。したがって、単一のノード、または他のノードで発生したレプリケーションの変更にほぼ追いついたノードからDDLを実行することをお勧めします。

2番目の種類は、グローバルDMLロックまたはリレーションDMLロックと呼ばれます。この種類のロックは、
``ddl_locking = on`` または\ ``ddl_locking = dml``
のいずれか、およびDDLステートメントによりフライト中のDMLステートメントが失敗する可能性がある場合に使用されます。これらの障害は、一意制約、チェック制約、NOT
NULL制約などの制約を追加または変更するときに発生する可能性があります。リレーションDMLロックは、一度に1つのリレーションにのみ影響します。リレーションDMLロックは、エラーでレプリケーションを停止する可能性のある変更がキューにあるときにDDLが実行されないことを保証します。

テーブルのグローバルDMLロックを取得するために、
DDLを実行するPGDノードはPGDグループ内の他のすべてのノードに接続し、書き込みに対してテーブルをロックするように依頼し、そのテーブルの保留中の変更がすべてドレインされるまで待機します。すべてのノードが完全に追いつくと、DMLロックの発信者は自由にテーブルのスキーマ変更を実行し、他のノードにレプリケートできます。

グローバルDMLロックは、各ノードのテーブルのEXCLUSIVE
LOCKを保持するため、実行中にそのテーブルに対するDML、他のDDL、VACUUM、およびindexコマンドをブロックします。これは、通常EXCLUSIVE
LOCK以上を使用しないコマンドにグローバルDMLロックが保持されている場合にも当てはまります。

保留中のDML操作がドレインされるまでに長い時間がかかる場合があり、レプリケーションが現在遅延している場合はさらに長くなります。これは、データの変更とは異なり、行表現とコンストレインに影響を与えるスキーマの変更が、構成されているすべてのノードに到達でき、現在の書き込みレートに適度に追随しているときにのみ実行できることを意味します。ノードがダウンしているときにこのようなDDLコマンドを実行する必要がある場合は、最初にダウンしたノードを構成から削除します。

DDLステートメントがレプリケートされない場合、グローバルロックは取得されません。

 :ref:`PGDシステムでのDDLの実行 <PGDシステムでのDDLの実行>` で説明しているように、ロック動作は\ ``bdr.ddl_locking``
パラメーターで指定されます。

-  ``ddl_locking = on``
   は、グローバルDDLロックを取得し、必要に応じてリレーションDMLロックを取得します。

-  ``ddl_locking = dml``
   は、グローバルDDLロックをスキップし、必要に応じてリレーションDMLロックを取得します。

-  ``ddl_locking = off``
   は、グローバルDDLロックとリレーションDMLロックの両方をスキップします。

一部のPGDファンクションはDDL変更を行います。これらのファンクションには、
DDLロック動作が適用されます。これについては、各ファンクションのドキュメントに記載されています。

したがって、 ``ddl_locking = dml``
は、競合するDDLが他のノードから実行されないことを保証できる場合にのみ安全です。この設定では、グローバルDDLロックのみを必要とするステートメントは、グローバルロックをまったく使用しません。

``ddl_locking = off`` は、
DDLが実行されるデータベースオブジェクトで競合するDDLと競合するDML操作がないことを保証できる場合にのみ安全です。ロックをオフにした後に問題が発生すると、データの進行中の変更が失われる可能性があります。ユーザーアプリケーションチームは、発生した問題を解決する必要があります。

場合によっては、同時に実行されるDDLを適切にシリアル化できる場合があります。これらのシリアル化障害が発生した場合、
DDLが再実行される場合があります。

DDLレプリケーションは、昇格するまでロジカルスタンバイノードでアクティブになりません。

一部のPGD管理機能はDDLのように動作します。つまり、グローバルロックを取得しようとし、
DDLレプリケーションがアクティブな場合、アクションがレプリケートされます。レプリケートファンクションの完全なリストは、
 :ref:`DDLのように動作するPGDファンクション <DDLのように動作するPGDファンクション>` にリストされています。

一時テーブルで実行されるDDLは、グローバルロックを必要としません。

現在のトランザクションで作成されたオブジェクトのALTERまたはDROPには、グローバルDMLロックは必要ありません。

グローバルDDLロックとグローバルDMLロックのモニタリングは
 :ref:`Monitoring <Monitoring>` に表示されます。

DDLのインパクトの最小化
-----------------------

あらゆるデータベースに対する適切な運用上のアドバイス。PGDではこれらの点がさらに重要になります。

-  DDLの影響を最小限にするには、
   DDLを実行するトランザクションを短くし、大量の行変更と組み合わせず、長時間実行される外部キーまたはその他の制約の再チェックを回避します。

-  ``ALTER TABLE`` の場合、 ``ADD CONSTRAINT``
   を単独で使用するのではなく、 ``ADD CONSTRAINT NOT VALID``
   を使用し、その後に\ ``VALIDATE CONSTRAINT``
   との別のトランザクションを使用します。 ``VALIDATE CONSTRAINT``
   は、すべてのノードで再生されるまで待機するため、確認の受信に顕著な遅延が発生します。

-  インデックスを作成するときは、可能な限り\ ``CONCURRENTLY``
   オプションを使用します。

長時間実行DDLを実行する別の方法は、
DDLレプリケーションを無効にして、各ノードで個別にDDLステートメントを実行することです。次の例に示すように、単一のSQLステートメントを使用してこれを行うことができます。グローバルロックルールは引き続き適用されるため、このタイプの使用法で自分自身をロックアウトしないように注意してください。これは回避策です。

.. code:: sql

   SELECT bdr.run_on_all_nodes($ddl$
           CREATE INDEX CONCURRENTLY index_a ON table_a(i);
   $ddl$);

``CREATE INDEX CONCURRENTLY``
はマルチトランザクションコマンドであるため、セッション全体でDDLレプリケーションを無効にする必要があることに注意して、
``bdr.run_on_all_nodes()``
テクニックを使用することをお勧めします。実行中の書き込みを防止するため、実稼働システムでは\ ``CREATE INDEX``
を避けてください。 ``REINDEX``
は、3.6までのバージョンでレプリケートされていますが、PGD
3.7以降ではレプリケートされません。 ``REINDEX``
は、AccessExclusiveLocksを保持するため、使用を避けてください。

代わりに、PG12+または2QPG11+で使用可能な\ ``REINDEX CONCURRENTLY``
または\ ``reindexdb --concurrently`` を使用します。

次のようなコマンドラインユーティリティを使用する場合、
DDLレプリケーションを無効にできます。

.. code:: sql

   $ export PGOPTIONS="-c bdr.ddl_replication=off"
   $ pg_restore --section=post-data

複数のDDLステートメントは、個々のステートメントとして起動されるよりも単一のトランザクションに束ねたほうがメリットがある場合があるため、
DDLロックは1回のみを取ります。テーブルレベルのロックが通常の操作を妨げる場合、これは望ましくない場合があります。

DDLがシステムを長時間保持している場合は、 psqlの **Control-C**
または\ ``pg_cancel_backend()``
を使用して、元のノードでDDLを安全にキャンセルできます。他のノードからDDLロックをキャンセルすることはできません。

オプションのグローバルロックタイムアウト設定を使用して、グローバルロックにかかる時間を制御できます。
``bdr.global_lock_timeout``
は、グローバルロックの取得がキャンセルされるまでの待機時間を制限します。
``bdr.global_lock_statement_timeout``
は、グローバルロックを保持するトランザクション内のステートメントの実行タイム長を制限し、
``bdr.global_lock_idle_timeout``
は、グローバルロックを保持するトランザクションの最大許可アイドル時間ステートメント間の時間を設定します。値をゼロに設定することにより、これらのタイムアウトをすべて無効にできます。

元のノードでDDL操作がコミットされると、キャンセルまたは中止することはできません。
PGDグループは、グローバルロックを確認した他のノードに正常に適用され、それらが再生を確認するまで待機する必要があります。このため、
DDLトランザクションは短くて速いままにしてください。

ダウンしたノードでのDDLの処理
-----------------------------

グローバルDDLロックを開始するノードがグローバルロックDDLまたはDMLを取得した後にダウンした場合、ロックはアクティブなままです。タイムアウトが設定されていても、グローバルロックはタイムアウトしません。ノードが復旧した場合、ノードは保持しているすべてのグローバルロックを解放します。

長時間または無期限にダウンしたままになる場合は、PGDグループからノードを削除してグローバルロックを解放します。これが、
bdr_superuserとして\ ``SET`` コマンドを使用して緊急DDLを実行し、
``bdr.ddl_locking`` 値を更新する理由の1つです。

グローバルロックを確認した後、それを取得するコマンドが実行される前に、他のノードのいずれかがダウンした場合、ノードがアップしているかのように、ロックを要求するそのコマンドの実行は続行されます。

前述のように、グローバルDDLロックはノードの大部分のみが応答する必要があるため、大部分が実行され到達可能である限り、クラスターの一部がダウンしている場合に機能します。ただし、クラスター全体が利用できない限りDMLロックは取得できません。

グローバルDDLまたはグローバルDMLロックでは、別のノードがダウンすると、コマンドは通常に続行され、ロックが解放されます。

ステートメント固有のDDLレプリケーションの問題
---------------------------------------------

すべてのコマンドを自動的に複製できるわけではありません。
``bdr.ddl_replication``
をオフにしてDDLレプリケーションをオフにしない限り、このようなコマンドは許可されません。

PGDは、データベースでアクティブなときに一部のDDLステートメントの実行を防止します。これにより、正しくレプリケートできないステートメント、またはレプリケーションがまだサポートされていないステートメントを禁止することにより、システムの一貫性が保護されます。

ステートメントがPGDで許可されない場合、多くの場合、同じことを行う別の方法を見つけることができます。たとえば、揮発性のデフォルト値を含む列を追加する\ ``ALTER TABLE``
は実行できません。しかし、一般的には、機能する一連の独立した\ ``ALTER TABLE``
および\ ``UPDATE`` ステートメントとして言い換えることができます。

通常、サポートされていないステートメントは実行されず、
``feature_not_supported`` SQLSTATE ``0A000`` エラーが発生します。

一時オブジェクトを参照または依存するDDLは、PGDでレプリケートできず、
DDLレプリケーションを有効にして実行するとエラーがスローされます。

PGD DDLコマンド処理マトリックス
-------------------------------

次の表では、許可されるユーティリティまたはDDLコマンド、レプリケートされるもの、およびレプリケート時に使用されるグローバルロックの種類について説明します。

``ALTER TABLE``
のようなより複雑なステートメントの場合、これらは実行されるサブコマンドによって異なる場合があります。このようなすべてのコマンドには、次の表の下に詳細な説明があります。

.. csv-table::
  :header: Command,Allowed,Replicated,Lock
  :widths: 15,5,5,10
  :align: left
  :class: longtable

  ALTER AGGREGATE,Y,Y,DDL
  ALTER CAST,Y,Y,DDL
  ALTER COLLATION,Y,Y,DDL
  ALTER CONVERSION,Y,Y,DDL
  ALTER DATABASE,Y,N,N
  ALTER DATABASE LINK,Y,Y,DDL
  ALTER DEFAULT PRIVILEGES,Y,Y,DDL
  ALTER DIRECTORY,Y,Y,DDL
  ALTER DOMAIN,Y,Y,DDL
  ALTER EVENT TRIGGER,Y,Y,DDL
  ALTER EXTENSION,Y,Y,DDL
  ALTER FOREIGN DATA WRAPPER,Y,Y,DDL
  ALTER FOREIGN TABLE,Y,Y,DDL
  ALTER FUNCTION,Y,Y,DDL
  ALTER INDEX,Y,Y,DDL
  ALTER LANGUAGE,Y,Y,DDL
  ALTER LARGE OBJECT,N,N,N
  ALTER MATERIALIZED VIEW,Y,N,N
  ALTER OPERATOR,Y,Y,DDL
  ALTER OPERATOR CLASS,Y,Y,DDL
  ALTER OPERATOR FAMILY,Y,Y,DDL
  ALTER PACKAGE,Y,Y,DDL
  ALTER POLICY,Y,Y,DDL
  ALTER PROCEDURE,Y,Y,DDL
  ALTER PROFILE,Y,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  ALTER PUBLICATION,Y,Y,DDL
  ALTER QUEUE,Y,Y,DDL
  ALTER QUEUE TABLE,Y,Y,DDL
  ALTER REDACTION POLICY,Y,Y,DDL
  ALTER RESOURCE GROUP,Y,N,N
  ALTER ROLE,Y,Y,DDL
  ALTER ROUTINE,Y,Y,DDL
  ALTER RULE,Y,Y,DDL
  ALTER SCHEMA,Y,Y,DDL
  ALTER SEQUENCE, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y,DML
  ALTER SERVER,Y,Y,DDL
  ALTER SESSION,Y,N,N
  ALTER STATISTICS,Y,Y,DDL
  ALTER SUBSCRIPTION,Y,Y,DDL
  ALTER SYNONYM,Y,Y,DDL
  ALTER SYSTEM,Y,N,N
  ALTER TABLE, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  ALTER TABLESPACE,Y,N,N
  ALTER TEXT SEARCH CONFIGURATION,Y,Y,DDL
  ALTER TEXT SEARCH DICTIONARY,Y,Y,DDL
  ALTER TEXT SEARCH PARSER,Y,Y,DDL
  ALTER TEXT SEARCH TEMPLATE,Y,Y,DDL
  ALTER TRIGGER,Y,Y,DDL
  ALTER TYPE,Y,Y,DDL
  ALTER USER MAPPING,Y,Y,DDL
  ALTER VIEW,Y,Y,DDL
  ANALYZE,Y,N,N
  BEGIN,Y,N,N
  CHECKPOINT,Y,N,N
  CLOSE,Y,N,N
  CLOSE CURSOR,Y,N,N
  CLOSE CURSOR ALL,Y,N,N
  CLUSTER,Y,N,N
  COMMENT,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,DDL
  COMMIT,Y,N,N
  COMMIT PREPARED,Y,N,N
  COPY,Y,N,N
  COPY FROM,Y,N,N
  CREATE ACCESS METHOD,Y,Y,DDL
  CREATE AGGREGATE,Y,Y,DDL
  CREATE CAST,Y,Y,DDL
  CREATE COLLATION,Y,Y,DDL
  CREATE CONSTRAINT,Y,Y,DDL
  CREATE CONVERSION,Y,Y,DDL
  CREATE DATABASE,Y,N,N
  CREATE DATABASE LINK,Y,Y,DDL
  CREATE DIRECTORY,Y,Y,DDL
  CREATE DOMAIN,Y,Y,DDL
  CREATE EVENT TRIGGER,Y,Y,DDL
  CREATE EXTENSION,Y,Y,DDL
  CREATE FOREIGN DATA WRAPPER,Y,Y,DDL
  CREATE FOREIGN TABLE,Y,Y,DDL
  CREATE FUNCTION,Y,Y,DDL
  CREATE INDEX,Y,Y,DML
  CREATE LANGUAGE,Y,Y,DDL
  CREATE MATERIALIZED VIEW,Y,N,N
  CREATE OPERATOR,Y,Y,DDL
  CREATE OPERATOR CLASS,Y,Y,DDL
  CREATE OPERATOR FAMILY,Y,Y,DDL
  CREATE PACKAGE,Y,Y,DDL
  CREATE PACKAGE BODY,Y,Y,DDL
  CREATE POLICY,Y,Y,DML
  CREATE PROCEDURE,Y,Y,DDL
  CREATE PROFILE,Y,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  CREATE PUBLICATION,Y,Y,DDL
  CREATE QUEUE,Y,Y,DDL
  CREATE QUEUE TABLE,Y,Y,DDL
  CREATE REDACTION POLICY,Y,Y,DDL
  CREATE RESOURCE GROUP,Y,N,N
  CREATE ROLE,Y,Y,DDL
  CREATE ROUTINE,Y,Y,DDL
  CREATE RULE,Y,Y,DDL
  CREATE SCHEMA,Y,Y,DDL
  CREATE SEQUENCE, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y,DDL
  CREATE SERVER,Y,Y,DDL
  CREATE STATISTICS,Y,Y,DDL
  CREATE SUBSCRIPTION,Y,Y,DDL
  CREATE SYNONYM,Y,Y,DDL
  CREATE TABLE, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y,DDL
  CREATE TABLE AS, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y,DDL
  CREATE TABLESPACE,Y,N,N
  CREATE TEXT SEARCH CONFIGURATION,Y,Y,DDL
  CREATE TEXT SEARCH DICTIONARY,Y,Y,DDL
  CREATE TEXT SEARCH PARSER,Y,Y,DDL
  CREATE TEXT SEARCH TEMPLATE,Y,Y,DDL
  CREATE TRANSFORM,Y,Y,DDL
  CREATE TRIGGER,Y,Y,DDL
  CREATE TYPE,Y,Y,DDL
  CREATE TYPE BODY,Y,Y,DDL
  CREATE USER MAPPING,Y,Y,DDL
  CREATE VIEW,Y,Y,DDL
  DEALLOCATE,Y,N,N
  DEALLOCATE ALL,Y,N,N
  DECLARE CURSOR,Y,N,N
  DISCARD,Y,N,N
  DISCARD ALL,Y,N,N
  DISCARD PLANS,Y,N,N
  DISCARD SEQUENCES,Y,N,N
  DISCARD TEMP,Y,N,N
  DO,Y,N,N
  DROP ACCESS METHOD,Y,Y,DDL
  DROP AGGREGATE,Y,Y,DDL
  DROP CAST,Y,Y,DDL
  DROP COLLATION,Y,Y,DDL
  DROP CONSTRAINT,Y,Y,DDL
  DROP CONVERSION,Y,Y,DDL
  DROP DATABASE,Y,N,N
  DROP DATABASE LINK,Y,Y,DDL
  DROP DIRECTORY,Y,Y,DDL
  DROP DOMAIN,Y,Y,DDL
  DROP EVENT TRIGGER,Y,Y,DDL
  DROP EXTENSION,Y,Y,DDL
  DROP FOREIGN DATA WRAPPER,Y,Y,DDL
  DROP FOREIGN TABLE,Y,Y,DDL
  DROP FUNCTION,Y,Y,DDL
  DROP INDEX,Y,Y,DDL
  DROP LANGUAGE,Y,Y,DDL
  DROP MATERIALIZED VIEW,Y,N,N
  DROP OPERATOR,Y,Y,DDL
  DROP OPERATOR CLASS,Y,Y,DDL
  DROP OPERATOR FAMILY,Y,Y,DDL
  DROP OWNED,Y,Y,DDL
  DROP PACKAGE,Y,Y,DDL
  DROP PACKAGE BODY,Y,Y,DDL
  DROP POLICY,Y,Y,DDL
  DROP PROCEDURE,Y,Y,DDL
  DROP PROFILE,Y,Y,DDL
  DROP PUBLICATION,Y,Y,DDL
  DROP QUEUE,Y,Y,DDL
  DROP QUEUE TABLE,Y,Y,DDL
  DROP REDACTION POLICY,Y,Y,DDL
  DROP RESOURCE GROUP,Y,N,N
  DROP ROLE,Y,Y,DDL
  DROP ROUTINE,Y,Y,DDL
  DROP RULE,Y,Y,DDL
  DROP SCHEMA,Y,Y,DDL
  DROP SEQUENCE,Y,Y,DDL
  DROP SERVER,Y,Y,DDL
  DROP STATISTICS,Y,Y,DDL
  DROP SUBSCRIPTION,Y,Y,DDL
  DROP SYNONYM,Y,Y,DDL
  DROP TABLE,Y,Y,DML
  DROP TABLESPACE,Y,N,N
  DROP TEXT SEARCH CONFIGURATION,Y,Y,DDL
  DROP TEXT SEARCH DICTIONARY,Y,Y,DDL
  DROP TEXT SEARCH PARSER,Y,Y,DDL
  DROP TEXT SEARCH TEMPLATE,Y,Y,DDL
  DROP TRANSFORM,Y,Y,DDL
  DROP TRIGGER,Y,Y,DDL
  DROP TYPE,Y,Y,DDL
  DROP TYPE BODY,Y,Y,DDL
  DROP USER MAPPING,Y,Y,DDL
  DROP VIEW,Y,Y,DDL
  EXECUTE,Y,N,N
  EXPLAIN,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` , :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  FETCH,Y,N,N
  GRANT,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,DDL
  GRANT ROLE,Y,Y,DDL
  IMPORT FOREIGN SCHEMA,Y,Y,DDL
  LISTEN,Y,N,N
  LOAD,Y,N,N
  LOAD ROW DATA,Y,Y,DDL
  LOCK TABLE,Y,N, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  MOVE,Y,N,N
  NOTIFY,Y,N,N
  PREPARE,Y,N,N
  PREPARE TRANSACTION,Y,N,N
  REASSIGN OWNED,Y,Y,DDL
  REFRESH MATERIALIZED VIEW,Y,N,N
  REINDEX,Y,N,N
  RELEASE,Y,N,N
  RESET,Y,N,N
  REVOKE,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,DDL
  REVOKE ROLE,Y,Y,DDL
  ROLLBACK,Y,N,N
  ROLLBACK PREPARED,Y,N,N
  SAVEPOINT,Y,N,N
  SECURITY LABEL,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,DDL
  SELECT INTO, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` ,Y,DDL
  SET,Y,N,N
  SET CONSTRAINTS,Y,N,N
  SHOW,Y,N,N
  START TRANSACTION,Y,N,N
  TRUNCATE TABLE,Y, :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` , :ref:`アーキテクチャの詳細<アーキテクチャの詳細>` 
  UNLISTEN,Y,N,N
  VACUUM,Y,N,N

ALTER SEQUENCE
^^^^^^^^^^^^^^

一般に\ ``ALTER SEQUENCE``
がサポートされていますが、グローバルシーケンスを使用する場合、一部のオプションは効果がありません。

``ALTER SEQUENCE ... RENAME``
は、gallocシーケンスのみでサポートされていません。
``ALTER SEQUENCE ... SET SCHEMA``
は、gallocシーケンスのみでサポートされていません。

ALTER TABLE
^^^^^^^^^^^

通常、 ``ALTER TABLE``
コマンドは許可されます。ただし、いくつかのサブコマンドはサポートされていません。

ALTER TABLEは許可されないコマンド
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``ALTER TABLE`` の一部のバリアントは、現在PGDノードで使用できません。

-  ``ADD COLUMN ... DEFAULT (non-immutable expression)``
   —これは、現在別のノードで別のデータになるため、許可されていません。推奨される回避策については、
   :ref:`列の追加 <列の追加>` を参照してください。

-  ``ADD CONSTRAINT ... EXCLUDE``
   —除外コンストレインは、現時点ではサポートされていません。除外コンストレインは非同期システムではあまり意味がなく、再生できない変更をもたらします。

-  ``ALTER TABLE ... SET WITH[OUT] OIDS`` — ``CREATE TABLE``
   と同じ理由でサポートされていません。

-  ``ALTER COLUMN ... SET STORAGE external``
   —列がテーブルのレプリカIDの列の1つである場合、拒否されます。

-  ``RENAME``
   —自動パーティション化されたテーブルの名前は変更できません。

-  ``SET SCHEMA``
   —自動パーティション化されたテーブルのスキーマは設定できません。

-  ``ALTER COLUMN ... TYPE``
   —コマンドによってテーブル全体が書き換えられる場合、列のタイプの変更はサポートされません。これは、変更がバイナリ強制可能でない場合に発生します。バイナリの強制変更は、一方通行のみが許可される場合があります。たとえば、\ ``VARCHAR(128)``
   から\ ``VARCHAR(256)``
   への変更はバイナリ強制可能であるため許可されますが、 ``VARCHAR(256)``
   から\ ``VARCHAR(128)``
   への変更はバイナリ強制可能ではないため、通常は許可されません。非レプリケートの\ ``ALTER COLUMN ... TYPE``
   は、列が新しいタイプに自動的にキャスト可能である場合に許可されます\ ``USING``
   句が含まれません。次に例を示します。テーブルリライトは、大規模なテーブルでAccessExclusiveLockを長期間保持するため、このようなコマンドは、いずれの場合も高可用データベースでは実行不可能である可能性があります。推奨される回避策については、
   :ref:`列のタイプの変更 <列のタイプの変更>` を参照してください。

-  ``ALTER TABLE ... ADD FOREIGN KEY``
   —現在のユーザーが参照されるテーブルを読み取る権限がない場合、または参照されるテーブルで現在のユーザーがバイパスできないRLS制限が有効になっている場合、サポートされません。

次の例は、 ``timestamp`` 型の定数値を\ ``timestamptz``
型の列に追加しようとするため、失敗します。 ``timestamp``
と\ ``timestamptz``
間のキャストは、セッションのタイムゾーンに依存するため、不変ではありません。

.. code:: sql

   ALTER TABLE foo
     ADD expiry_date timestamptz DEFAULT timestamp 2100-01-01 00:00:00 NOT NULL;

PGD 3.7.4以降、DMLロックを取得せずに、 ``CHECK`` や\ ``FOREIGN KEY``
制約などの特定のタイプの制約を追加できます。ただし、これには、最初に\ ``NOT VALID``
制約を作成し、次に ``ALTER TABLE ... VALIDATE CONSTRAINT``
コマンドを使用して別のトランザクションで制約を検証する2段階のプロセスが必要です。
 :ref:`コンストレインの追加 <コンストレインの追加>` を参照

詳細については、

ALTER TABLE ロック
^^^^^^^^^^^^^^^^^^

``ALTER TABLE`` の次のバリアントは、
DDLロックのみを取得し、DMLロックは取得しません。

-  ``ALTER TABLE ... ADD COLUMN ... (immutable) DEFAULT``

-  ``ALTER TABLE ... ALTER COLUMN ... SET DEFAULT expression``

-  ``ALTER TABLE ... ALTER COLUMN ... DROP DEFAULT``

-  ``ALTER TABLE ... ALTER COLUMN ... TYPE`` リライトが必要ない場合

-  ``ALTER TABLE ... ALTER COLUMN ... SET STATISTICS``

-  ``ALTER TABLE ... VALIDATE CONSTRAINT``

-  ``ALTER TABLE ... ATTACH PARTITION``

-  ``ALTER TABLE ... DETACH PARTITION``

-  ``ALTER TABLE ... ENABLE TRIGGER`` ``ENABLE REPLICA TRIGGER``
   は引き続きDMLロックを取得します

-  ``ALTER TABLE ... CLUSTER ON``

-  ``ALTER TABLE ... SET WITHOUT CLUSTER``

-  ``ALTER TABLE ... SET ( storage_parameter = value [, ... ] )``

-  ``ALTER TABLE ... RESET ( storage_parameter = [, ... ] )``

-  ``ALTER TABLE ... OWNER TO``

``ALTER TABLE``
の他のすべてのバリアントは、変更されるテーブルでDMLロックを取得します。
``ALTER TABLE`` の一部のバリアントには、以下に説明する制限があります。

ALTER TABLEの例
^^^^^^^^^^^^^^^

この次の例は、型の変更がバイナリ強制可能であるため、テーブルの書き換えが発生しないため、機能します。カタログのみの変更として実行されます。

.. code:: sql

   CREATE TABLE foo (id BIGINT PRIMARY KEY, description VARCHAR(20));
   ALTER TABLE foo ALTER COLUMN description TYPE VARCHAR(128);

ただし、 ``VARCHAR(128)`` から\ ``VARCHAR(20)``
への変更はバイナリ強制可能ではないため、コマンドを逆に変更することは不可能です。

.. code:: sql

   ALTER TABLE foo ALTER COLUMN description TYPE VARCHAR(20);

回避策については、 :ref:`制限されDDLの回避策 <制限されDDLの回避策>` を参照してください。

一般におよび非レプリケート環境で可能なさまざまなタイプの\ ``ALTER TABLE ... ALTER COLUMN TYPE``
ATCT操作のコンテキストを提供すると役立ちます。

一部のATCT操作は、基になる列タイプのメタデータのみを更新し、基になるテーブルデータの書き換えは必要ありません。これは通常、既存の列タイプとターゲットタイプがバイナリ強制可能な場合に当てはまります。例

.. code:: sql

   CREATE TABLE sample (col1 BIGINT PRIMARY KEY, col2 VARCHAR(128), col3 INT);
   ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR(256);

バイナリの強制性のため、列タイプを\ ``VARCHAR`` または\ ``TEXT``
データ型に変更することもできます。繰り返しますが、これは基になる列タイプの単なるメタデータの更新です。

.. code:: sql

   ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR;
   ALTER TABLE sample ALTER COLUMN col2 TYPE TEXT;

ただし、col2のサイズを削減したい場合は、基になるテーブルデータの書き換えが必要になります。テーブルの書き換えは通常制限されています。

.. code:: sql

   ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR(64);
   ERROR:  ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a PGD node

非テキストタイプの例として、INTEGERタイプを使用した上記のcol3を検討します。
SMALLINTまたはBIGINTに変換しようとするATCT操作は、上記と同様の方法で失敗します。

.. code:: sql

   ALTER TABLE sample ALTER COLUMN col3 TYPE bigint;
   ERROR:  ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a PGD node

これらの失敗したケースは両方とも、現在の型からターゲット型への自動割り当てキャストがあります。ただし、バイナリの強制力がないため、基になるテーブルデータの書き換えが発生します。

このような場合、制御されたDBA環境では、すべてのノードの非レプリケート環境でこの列のタイプのローリングアップグレードを採用することにより、列のタイプを自動的にキャスト可能なものに変更できます。
DDLはレプリケートされず、列型の変更は自動的にキャスト可能なものであると仮定します。次に、この同じテーブル上の他のノードでの同時アクティビティとともに、変更を実行するノードでローカルに書き換えを許可できます。次に、すべてのノードでこの非レプリケートのATCT操作を1つずつ繰り返し、
EDB
Postgres分散クラスター全体で列タイプの目的の変更をもたらすことができます。これには書き換えが含まれるため、アクティビティは引き続き短期間DMLロックを取得するため、クラスター全体が利用できる必要があります。これらの詳細を設定すると、次のような非レプリケートの変更アクティビティのローリングアップグレードを実行できます。

.. code:: sql

   - - foreach node in EDB Postgres Distributed cluster do:
   SET bdr.ddl_replication TO FALSE;
   ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR(64);
   ALTER TABLE sample ALTER COLUMN col3 TYPE BIGINT;
   RESET bdr.ddl_replication;
   - - done

自動割り当てキャストは多くのデータ型で利用できるため、このローカルの非レプリケートATCT操作は、さまざまな変換をサポートします。また、
``USING``
句を使用するATCT操作は、自動割り当てキャストがないため失敗する可能性があります。この例は、自動割り当てキャストを使用したいくつかの一般的な変換を示しています。

.. code:: sql

   - - foreach node in EDB Postgres Distributed cluster do:
   SET bdr.ddl_replication TO FALSE;
   ATCT operations to-from {INTEGER, SMALLINT, BIGINT}
   ATCT operations to-from {CHAR(n), VARCHAR(n), VARCHAR, TEXT}
   ATCT operations from numeric types to text types
   RESET bdr.ddl_replication;
   - - done

この例は、非レプリケート環境で許可される可能性のあるATCT操作の完全なリストではありません。すべてのATCT操作が機能するわけではありません。自動割り当てができない場合、
DDLレプリケーションを無効にしても失敗します。したがって、数値型からテキスト型への変換は非レプリケート環境で機能しますが、テキスト型から数値型への逆変換は失敗します。

.. code:: sql

   SET bdr.ddl_replication TO FALSE;
   - - conversion from BIGINT to TEXT works
   ALTER TABLE sample ALTER COLUMN col3 TYPE TEXT;
   - - conversion from TEXT back to BIGINT fails
   ALTER TABLE sample ALTER COLUMN col3 TYPE BIGINT;
   ERROR:  ALTER TABLE ... ALTER COLUMN TYPE which cannot be automatically cast to new type may not affect replicated tables on a PGD node
   RESET bdr.ddl_replication;

非レプリケート環境のATCT操作はさまざまな型変換をサポートしていますが、基になるテーブルデータに新しいデータ型に割り当てできない値が含まれている場合、リライトは失敗する場合があります。たとえば、列の現在のタイプが\ ``VARCHAR(256)``
で、非レプリケートATCT操作を試行して\ ``VARCHAR(128)``
に変換するとします。テーブルに128バイトを超える既存のデータがある場合、書き換え操作はローカルに失敗します。

.. code:: sql

   INSERT INTO sample VALUES (1, repeat(a, 200), 10);
   SET bdr.ddl_replication TO FALSE;
   ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR(128);
   INFO:  in rewrite
   ERROR:  value too long for type character varying(128)

基になるテーブルデータが新しい型の特性を満たしている場合、書き換えは成功します。ただし、非レプリケートのローリングデータタイプのアップグレードをまだ実行していない他のノードが、128バイトより広い新しいデータをこのローカルATCT操作に同時に導入する場合、レプリケーションは失敗する可能性があります。これにより、クラスターでのレプリケーションが停止します。したがって、これらの非レプリケートのローリングデータ型のアップグレード操作を実行する間は、データベースおよびアプリケーションレベルでのデータ型の制限と特性に注意してください。このようなATCT操作は、制御された完全に認識したDBA環境で実行およびテストすることを強くお勧めします。これらのATCT操作は非対称であり、失敗した特定の変更をバックアウトすると、時間がかかるテーブルの書き換えが発生する可能性があります。

また、トランザクションブロックで暗黙的なキャスト可能ALTERアクティビティを実行することはできません。

ALTER TYPE
^^^^^^^^^^

``ALTER TYPE`` はレプリケートされますが、
PostgreSQLはこれらの依存関係を記録しないため、グローバルDMLロックはそのデータ型を使用するすべてのテーブルに適用されません。
 :ref:`制限されDDLの回避策 <制限されDDLの回避策>` を参照してください。

コメントオン
^^^^^^^^^^^^

``COMMENT ON`` のすべてのバリアントが許可されますが、
``COMMENT ON TABLESPACE/DATABASE/LARGE OBJECT``
はレプリケートされません。

CREATE PROFILEまたはALTER PROFILE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ファンクションが\ ``SECURITY DEFINER``
の場合、プロファイルに関連付けられている\ ``PASSWORD_VERIFY_FUNCTION``
は\ ``IMMUTABLE`` である必要があります。このような\ ``CREATE PROFILE``
または\ ``ALTER PROFILE``
コマンドはレプリケートされますが、このプロファイルを使用する後続の\ ``CREATE USER``
または\ ``ALTER USER`` コマンドは、 ``writer``
ワーカーが\ ``cannot change current role within security-restricted operation``
エラーをスローするため、レプリケーションを中断します。

CREATE SEQUENCE
^^^^^^^^^^^^^^^

一般に\ ``CREATE SEQUENCE``
がサポートされていますが、グローバルシーケンスを使用する場合、一部のオプションは効果がありません。

CREATE TABLE
^^^^^^^^^^^^

一般に\ ``CREATE TABLE`` はサポートされていますが、
``CREATE TABLE WITH OIDS`` はPGDノードでは許可されていません。

CREATE TABLE ASとSELECT INTO
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``CREATE TABLE AS`` および\ ``SELECT INTO``
は、すべてのサブコマンドも許可される場合にのみ許可されます。

EXPLAIN
^^^^^^^

一般に\ ``EXPLAIN`` は許可されますが、 ``EXPLAIN ANALYZE``
はデータベースに副作用を与える可能性があるため、いくつかの制限があります。

EXPLAIN ANALYZEレプリケーション
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``EXPLAIN ANALYZE``
は、分析されたステートメントのレプリケーションルールに従います。

EXPLAIN ANALYZEロック
^^^^^^^^^^^^^^^^^^^^^

``EXPLAIN ANALYZE``
は、分析されたステートメントのロックルールに従います。

GRANTとREVOKE
^^^^^^^^^^^^^

通常、\ ``GRANT`` および\ ``REVOKE``
ステートメントはサポートされていますが、
``GRANT/REVOKE ON TABLESPACE/LARGE OBJECT`` はレプリケートされません。

ロックテーブル
^^^^^^^^^^^^^^

LOCK TABLEはレプリケートされませんが、 ``bdr.lock_table_locking``
が\ ``on``
に設定されている場合、グローバルDMLロックを取得する場合があります。

``bdr.global_lock_table()``
ファンクションを使用して、グローバルDMLロックを明示的に要求することもできます。

セキュリティラベル
^^^^^^^^^^^^^^^^^^

``SECURITY LABEL`` のすべてのバリアントが許可されますが、
``SECURITY LABEL ON TABLESPACE/DATABASE/LARGE OBJECT``
はレプリケートされません。

TRUNCATEレプリケーション
^^^^^^^^^^^^^^^^^^^^^^^^

``TRUNCATE`` コマンドは、
DDLステートメントではなくDMLとしてレプリケートされます。テーブルの\ ``TRUNCATE``
がレプリケートされるかどうかは、影響を受ける各テーブルのレプリケーション設定によって異なります。

TRUNCATEロック
^^^^^^^^^^^^^^

``TRUNCATE`` は他のDDLと同じ方法でレプリケートされませんが、
``bdr.truncate_locking`` が\ ``on``
に設定されている場合、グローバルDMLロックを取得できます。

ロール操作ステートメント
^^^^^^^^^^^^^^^^^^^^^^^^

ユーザーはPostgreSQLインスタンスのグローバルオブジェクトです。つまり、ユーザーは複数のデータベースにまたがりますが、
PGDは個々のデータベースレベルで動作します。これは、ロール操作ステートメントの処理に追加の検討が必要であることを意味します。

PGDでは、レプリケートされたDDLによって参照されるロールがすべてのノードに存在する必要があります。ロールの付与、パスワードなどは同じである必要はありませんが、存在する必要があります。

``bdr.role_replication``
が有効デフォルトであり、ロール操作ステートメントがPGD対応データベースで実行されている場合、PGDはロール操作ステートメントをレプリケートします。

ロール操作ステートメントには次のものが含まれます。

-  ``CREATE ROLE``

-  ``ALTER ROLE``

-  ``DROP ROLE``

-  ``GRANT ROLE``

-  ``CREATE USER``

-  ``ALTER USER``

-  ``DROP USER``

-  ``CREATE GROUP``

-  ``ALTER GROUP``

-  ``DROP GROUP``

一般に、次のいずれかです。

-  ``bdr.role_replication = off``
   でシステムを構成し、Ansible、Puppet、Chefなどの外部オーケストレーションツールまたは\ ``bdr.replicate_ddl_command(...)``
   によって明示的にレプリケートされて、すべてのロール変更ユーザーとグループを展開します。

-  PostgreSQLインスタンス上のちょうど1つのPGD対応データベースが\ ``bdr.role_replication = on``
   を持つようにシステムを構成し、そのデータベースですべてのロール管理DDLを実行します。

すべてのロール管理コマンドを1つのデータベースで実行することをお勧めします。

ロールレプリケーションがオフになっている場合、管理者は、あるノードでDDLが使用するロールが他のノードにも存在することを確認する必要があります。それ以外の場合、PGD
applyは、他のノードでロールが作成されるまで、エラーでストールします。

..  Note ::
   PGDは、 PGD対応のPostgreSQLインスタンスの非PGD対応データベースで実行される場合、ロール管理ステートメントをキャプチャおよびレプリケートしません。たとえば、DB 'bdrdb' bdrグループメンバーと'postgres'ベアdb、および`bdr.role_replication = on` がある場合、 `bdrdb` で実行される`CREATE USER` はレプリケートされますが、 `postgres` で実行される`CREATE USER` はレプリケートされません。

制限されDDLの回避策
^^^^^^^^^^^^^^^^^^^

PGD
DDLオペレーション処理の制限の一部は回避できます。多くの場合、操作をより小さな変更に分割すると、単一のステートメントとして許可されないか、過剰なロックが必要な目的の結果が生成される場合があります。

コンストレインの追加
^^^^^^^^^^^^^^^^^^^^

DMLロックを必要とせずに\ ``CHECK`` および\ ``FOREIGN KEY``
制約を追加できます。これには、2段階のプロセスが含まれます。

-  ``ALTER TABLE ... ADD CONSTRAINT ... NOT VALID``

-  ``ALTER TABLE ... VALIDATE CONSTRAINT``

2つの異なるトランザクションでこれらの手順を実行します。これらの手順は両方とも、テーブルでのみDDLロックを取得するため、1つ以上のノードがダウンしている場合でも実行できます。ただし、コンストレインを検証するには、PGDは次のことを確認する必要があります。

-  クラスター内のすべてのノードは\ ``ADD CONSTRAINT``
   コマンドを参照します。

-  コンストレインを検証するノードは、これらのノードにNOT
   VALIDコンストレインを作成する前に、他のすべてのノードからレプリケーション変更を適用します。

したがって、新しいメカニズムでは、制約の検証中にすべてのノードがアップしている必要はありませんが、すべてのノードが\ ``ALTER TABLE .. ADD CONSTRAINT ... NOT VALID``
コマンドを適用し、十分に進行していることは必要です。
PGDは、コンストレインを検証する前に、一貫した状態に到達するのを待機します。

新しい機能では、クラスターがRaftプロトコルバージョン24以降で実行されている必要があります。
Raftプロトコルがまだアップグレードされていない場合、古いメカニズムが使用され、DMLロック要求が発生します。

列の追加
^^^^^^^^

揮発性のデフォルトを使用して列を追加するには、別のトランザクションで次のコマンドを実行します。

.. code:: sql

       ALTER TABLE mytable ADD COLUMN newcolumn coltype; -- Note the lack of DEFAULT or NOT NULL

       ALTER TABLE mytable ALTER COLUMN newcolumn DEFAULT volatile-expression;

       BEGIN;
       SELECT bdr.global_lock_table(mytable);
       UPDATE mytable SET newcolumn = default-expression;
       COMMIT;

このアプローチでは、スキーマの変更と行の変更をPGDが実行できる別のトランザクションに分割し、PGDグループ内のすべてのノードで一貫したデータが得られます。

最良の結果を得るには、更新をチャンクにバッチ処理して、一度に数万〜数十万行を更新しないようにします。これは、埋め込みトランザクションで\ ``PROCEDURE``
を使用して行うことができます。

変更の最後のバッチは、テーブルのグローバルDMLロックを取得するトランザクションで実行する必要があります。そうしないと、他のノードのテーブルに同時に挿入される行を見逃す可能性があります。

必要に応じて、\ ``UPDATE``
が完了した後、\ ``ALTER TABLE mytable ALTER COLUMN newcolumn NOT NULL;``
を実行できます。

列のタイプの変更
^^^^^^^^^^^^^^^^

列のタイプを変更すると、PostgreSQLがテーブルを書き換える場合があります。ただし、場合によっては、この書き換えを回避できる場合があります。例

.. code:: sql

   CREATE TABLE foo (id BIGINT PRIMARY KEY, description VARCHAR(128));
   ALTER TABLE foo ALTER COLUMN description TYPE VARCHAR(20);

制限をデータ型の変更ではなくテーブル制約にすることにより、テーブルのリライトを回避するようにこのステートメントをリライトできます。必要に応じて、後続のコマンドでコンストレインを検証して、長いロックを回避できます。

.. code:: sql

   CREATE TABLE foo (id BIGINT PRIMARY KEY, description VARCHAR(128));
   ALTER TABLE foo
     ALTER COLUMN description TYPE varchar,
     ADD CONSTRAINT description_length_limit CHECK (length(description) <= 20) NOT VALID;
   ALTER TABLE foo VALIDATE CONSTRAINT description_length_limit;

検証が失敗した場合は、失敗した行のみを\ ``UPDATE``
できます。このテクニックは、 ``length()`` を使用するか、 ``scale()``
を使用して\ ``NUMERIC`` データ型を使用する\ ``TEXT`` および\ ``VARCHAR``
に使用できます。

列タイプを変更する一般的な場合、最初に目的のタイプの列を追加します。

::

   ALTER TABLE mytable ADD COLUMN newcolumn newtype;

``BEFORE INSERT OR UPDATE ON mytable FOR EACH ROW ..``
として定義されたトリガーを作成します。これは、テーブルへの新しい書き込みによって新しい列が自動的に更新されるように、\ ``NEW.newcolumn``
を\ ``NEW.oldcolumn`` に割り当てます。

``UPDATE`` 埋め込みトランザクションで\ ``PROCEDURE``
を使用して、\ ``oldcolumn`` の値を\ ``newcolumn``
にコピーするバッチ内のテーブル。作業をバッチ処理することは、大きなテーブルの場合、レプリケーションラグを削減するのに役立ちます。
IDの範囲または任意の方法で更新しても問題ありません。または、小さなテーブルの場合、1パスでテーブル全体を更新できます。

``CREATE INDEX ...``
新しい列に必要なインデックス。ロック期間を短縮するために、各ノードでDDLレプリケーションを使用せずに個別に実行される\ ``CREATE INDEX ... CONCURRENTLY``
を使用するのが安全です。

``ALTER`` 必要に応じて、\ ``NOT NULL`` および\ ``CHECK``
制約を追加する列。

1. ``BEGIN`` トランザクション。

2. ``DROP`` 追加したトリガー。

3. ``ALTER TABLE`` 列に必要な\ ``DEFAULT`` を追加します。

4. ``DROP`` 古い列。

1.\ ``ALTER TABLE mytable RENAME COLUMN newcolumn TO oldcolumn`` .

1.\ ``COMMIT`` .

..  Note ::
   列を削除するため、テーブルに依存するビュー、プロシージャなどを再作成する必要がある場合があります。列を削除する場合は、それを参照したすべてを再作成する必要があるため、注意してください。

他のタイプの変更
^^^^^^^^^^^^^^^^

``ALTER TYPE``
ステートメントはレプリケートされますが、影響を受けるテーブルはロックされていません。

このDDLを使用する場合、新しいタイプを使用する前に、すべてのノードでステートメントが正常に実行されたことを確認してください。これは、
``bdr.wait_slot_confirm_lsn()`` ファンクションを使用して実現できます。

この例では、DMLステートメントで新しい値を使用する前に、
DDLがすべてのノードに書き込まれるようにします。

::

   ALTER TYPE contact_method ADD VALUE email;
   SELECT bdr.wait_slot_confirm_lsn(NULL, NULL);

DDLのように動作するPGDファンクション
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

次のPGD管理機能はDDLのように動作します。これは、
DDLレプリケーションがアクティブで、
DDLフィルター設定で許可されている場合、グローバルロックを取得しようとし、アクションがレプリケートされることを意味します。詳細については、各機能のドキュメントを参照してください。

レプリケーションセット管理

-  ``bdr.create_replication_set``

-  ``bdr.alter_replication_set``

-  ``bdr.drop_replication_set``

-  ``bdr.replication_set_add_table``

-  ``bdr.replication_set_remove_table``

-  ``bdr.replication_set_add_ddl_filter``

-  ``bdr.replication_set_remove_ddl_filter``

競合管理

-  ``bdr.alter_table_conflict_detection``

-  ``bdr.column_timestamps_enable``

-  ``bdr.column_timestamps_disable``

シーケンス管理

-  ``bdr.alter_sequence_set_kind``

ストリームトリガー

-  ``bdr.create_conflict_trigger``

-  ``bdr.create_transform_trigger``

-  ``bdr.drop_trigger``
