手動で生成した初期データを持つ(いくつかのものは持っていません)各々のカタログには、編集可能なデータ形式の初期データを含み、対応する.datファイルがあります。
個々の.datファイルにはPerlのデータ構造文字列が含まれます。
それらは単に評価されることによって1個がカタログの1行に対応するハッシュ参照の配列を含むメモリ上のデータ構造を生成します。
pg_database.datから抜きだしたものに些細な変更を加えたものを使って、鍵となる機能を示します。
[
# A comment could appear here.
{ oid => '1', oid_symbol => 'TemplateDbOid',
descr => 'database\'s default template',
datname => 'template1', encoding => 'ENCODING', datcollate => 'LC_COLLATE',
datctype => 'LC_CTYPE', datistemplate => 't', datallowconn => 't',
datconnlimit => '-1', datlastsysoid => '0', datfrozenxid => '0',
datminmxid => '1', dattablespace => 'pg_default', datacl => '_null_' },
]
特筆すべきポイント:
全体的なファイルレイアウトは次のようになります。 開き大括弧、カタログの行を表現する一つ以上の中括弧、閉じ大括弧。 各々の閉じ中括弧の後にはカンマを書きます。
各々のカタログ行にカンマ区切りでkey=>valueペアを書きます。
記述可能なkeyは、カタログのカラムに加えてメタデータキーであるoid、oid_symbol、array_type_oid、descrです。
(oidとoid_symbolの使い方は後述の69.2.2で説明されていて、一方、array_type_oidは69.2.4で説明されています。
descrはオブジェクトの説明文字列に使用し、pg_descriptionかpg_shdescriptionの適切な方に挿入されます。)
メタデータキーは省略可能であるのに対し、カタログの.hファイルがカラムのデフォルト値を指定する場合を除いてカタログの定義済みカラムはすべて提供されなければなりません。
(上記の例ではpg_database.hが適切なデフォルト値を供するのでdatdbaフィールドは省略されました。)
すべての値は単一引用符で囲まなければなりません。
値中の単一引用符はバックスラッシュでエスケープします。
データを意味するバックスラッシュは二重にできますが、必須ではありません。
これはPerlの単純な単一引用符で引用されたリテラルに関するルールに基づいています。
データとして使われるバックスラッシュは、エスケープ文字列定数(4.1.2.2参照)と同じルールに基づき、ブートストラップスキャナーはエスケープと解釈することに注意してください。
たとえば\tはタブへと変換されます。
最終的な値としてバックスラッシュを使用したい場合は、4つ書く必要があります。
Perlが2つ削除し、ブートストラップスキャナーが認識するために\\が残ります。
NULL値は_null_で表します。
(それと同じ文字列を作る方法はないことに注意してください。)
コメントは#を前に置いてください。また同じ行上に置かなければなりません。
他のカタログエントリのOIDであるフィールド値は、実際の数値のOIDではなくシンボル名で記述されるべきです。
(上記の例ではdattablespaceがこのような参照を含みます。)
これは後述の69.2.3で説明します。
ハッシュは順序付けられないデータ構造なので、フィールドの順や行の配置には重要な意味はありません。
しかし、見た目を統一するために、フォーマットスクリプトreformat_dat_file.plが適用される少数のルールを設定しました。
中括弧のペアの中で、メタデータフィールドのoid、oid_symbol、array_type_oid、および、(もし存在するなら)descrがこの順で最初に来ます。
そして、定義された順にカタログ自身のフィールドが現れます。
可能ならば、行の長さを80文字に制限するために、必要に応じてフィールドの間に改行を挿入します。 改行はメタデータフィールドと通常のフィールドの間にも挿入します。
カタログの.hファイルがカラムのデフォルト値を指定していて、データエントリが同じ値なら、reformat_dat_file.plはデータファイルからデータエントリを省略します。
これでデータ表現が小さくなります。
reformat_dat_file.plは空白行とコメント行をそのまま維持します。
カタログデータパッチを投稿する前に、reformat_dat_file.plを実行することをお勧めします。
便利さのために、単にsrc/include/catalog/に変更を加えてmake reformat-dat-filesを実行することができます。
データ表現をより小さくする新しい方法を付け加えたいのであれば、reformat_dat_file.plで実装し、また
データを完全な表現に戻す方法をCatalog::ParseData()に指示しなければなりません。
初期データに現れるカタログ行にはoid=> メタデータフィールドを書くことで手動で割り当てたOIDを与えることができます。
それだけでなく、OIDを割り当てられたならば、nnnnoid_symbol => メタデータフィールドを書くことでそのOID用のCマクロを作ることができます。
name
他のプリロードカタログ行の中にそのOIDへの参照がある場合には、プリロードカタログ行は割当済みのOIDを持たなければなりません。
Cコードから行OIDが参照されるときにも割当済みのOIDは必要です。
どちらも当てはまらない場合は、oidメタデータフィールドは省略可能です。
その場合、ブートストラップコードが自動的にOIDを割り当てます。
実用的には、カタログの一部のみが実際に相互参照されている場合でも、与えられたプリロードカタログ行のOIDをすべて割当済みにするか、一つも割当済みにしないかのどちらかに通常します。
Cコード中でOIDの実際の数値を書くのは非常に良くないと考えられます。
pg_procを直接参照するのは普通のことなので、自動的に必要なマクロを生成する特別な仕掛けがあります。
src/backend/utils/Gen_fmgrtab.plを見てください。
歴史的理由により、似ていはいますが同じではない方法によるpg_type OID用のマクロを自動生成する仕組みがあります。
ですから、oid_symbolエントリはこれらの2つのカタログに必ずしも存在しなければならないというわけではありません。
同様に、pg_classシステムカタログのOIDとインデックスマクロは自動的に設定されます。
他のすべてのシステムカタログでは、oid_symbolを使って必要なマクロを手動で指定しなければなりません。
新しいプリロード行のために利用可能なOIDを見つけるには、src/include/catalog/unused_oidsスクリプトを実行してください。
未使用のOIDの範囲が表示されます。
(たとえば、出力行45-900はOIDs 45から900が利用されていないことを示します。)
今の所OID 1–9999 は手動での割当のために予約されています。
unused_oidsスクリプトは、単にカタログヘッダーと.datを見てそこに出現していないOIDを探しているだけです。
間違い見つけるためにduplicate_oidsを利用することもできます。
(genbki.plは手動アサインされていない全ての行にOIDを割り当て、また、コンパイル時に重複OIDを検出します。)
即座にコミットされるとは期待できないパッチ用にOIDを選ぶときの最良の手法は、8000—9999の範囲でランダムに選択したところから始まるおおむね連続したOIDのグループを使うことです。
これは同時に開発されている他のパッチとのOID衝突の危険を最小化します。
8000—9999の範囲を開発目的に空けておくため、パッチがマスタgitリポジトリにコミットされた後、そのOIDはこの範囲の下位の使用可能な場所に番号の振り直しをすべきです。
通例これは各開発サイクルの終わり近くに行われ、同時にそのサイクルでコミットされたパッチで消費された全てのOIDを移動するでしょう。
スクリプトrenumber_oids.plはこの目的に使用できます。
コミットされていないパッチが最近コミットされたパッチとOID衝突していることに気づいた場合に、このような状況から回復するのにもrenumber_oids.plがおそらく役立つでしょう。
パッチに割り当てられたOIDを番号付け替えすることがあるこの慣習のため、パッチに割り当てられたOIDはそのパッチが正式リリースに含まれるまでは永続的と考えるべきではありません。 さまざまな互換性の問題を生み出すかもしれないため、一度リリースされた手動でアサインされたオブジェクトのOIDは変更しません。
genbki.plは、手動アサインされたOIDを持たないカタログエントリにOIDを割り当てる必要がある場合、10000—11999範囲の値を使います。
ブートストラップ実行開始の際にはサーバのOIDカウンタは12000に設定されます。
したがって、information_schema.sqlスクリプトを実行して作られるオブジェクトなど、ブートストラップ後の段階において通常のSQLコマンドで作られたオブジェクトは12000以上のOIDを受け取ります。
通常のデータベース操作で割り当てられたOIDは16384以上に限定されます。
これはgenbki.plやブートストラップの中で自動的に割り当てられたOIDに対して10000—16383の範囲が空いていること保証します。
これらの自動割り当てされたOIDは永続的とはいえず、あるインストレーションから他のインストレーションで変更されるかもしれません。
原則としては、ある初期カタログ行から他への相互参照は、参照しているフィールドで参照されている行の事前割り当てされたOIDを書くことだけで記述できます。
しかしながら、間違いやすく、読みにくく、また、新たに割り当てられたOIDが番号付け直しされたときに破損しやすいため、これはプロジェクト方針に反します。
そのため、genbki.plが代わりにシンボル参照を記述する機構を提供しています。
そのルールは以下のとおりです。
BKI_LOOKUP(をカラム定義に加えることで、特定のカタログカラムでのシンボル参照が利用可能になります。
ここでlookuprule)lookupruleは参照されているカタログ名で、例えばpg_procです。
BKI_LOOKUPを、Oid、regproc、oidvector、Oid[]のカラムに加えることができます。
最後の2つにおいては、配列の個々の要素を検索することを暗に意味します。
文字セット符号化方式を参照する整数の列にBKI_LOOKUP(encoding)を加えることも許容されます。これは今のところカタログのOIDとして現れませんが、値の集合をgenbki.plに知らせます。
そうしたカラムでは、InvalidOidの意味で0を用いる以外には、すべてのエントリでシンボル参照を使用しなければなりません。
(カラムがregprocと宣言されている場合は、0の代わりに-と書くことができます。)
genbki.plは認識できない名前には警告を出します。
たいていのカタログオブジェクト類は単純にその名前で参照されます。
型名は参照されているpg_typeのエントリのtypnameと正確に一致しなければならないことに注意してください。int4に対するintegerなどの別名は使えません。
それがpg_proc.dat内でユニークなら、関数はpronameで表現できます。
(regprocの入力はこのように働きます。)
そうでなければ、regprocedureのように、proname(argtypename,argtypename,...)と書いてください。
引数型名は正確にpg_proc.datエントリのproargtypesで指定しなければなりません。
空白は挿入しないでください。
演算子はoprname(lefttype,righttype)で表現します。
型名は正確にpg_operator.datエントリのoprleftフィールドとoprrightフィールドで記述します。
(省略された単項演算子のオペランドは0と書きます。)
opclassesとopfamiliesの名前はアクセスメソッド内でのみユニークなので、access_method_name/object_nameで表します。
以上のいずれの場合にもスキーマ修飾の規定はありません。
ブートストラップ中に作成されるすべてのオブジェクトは、pg_catalogスキーマにあると期待されます。
一般的な検索の仕組みに加えて、PGNSPがpg_catalogスキーマのOIDで置換され、PGUIDがブートストラップのスーパーユーザロールのOIDで置換されるという特別な習慣があります。
これらの使用方法はやや歴史的なものですが今のところ、これらを一般化する必要はありませんでした。
genbki.plは実行中にすべてのシンボル参照を解決し、生成したBKIファイルの中に単純な数字のOIDを設定します。
ですから、ブートストラップバックエンドはシンボル参照にかかわる必要はありません。
たいていのスカラデータ型は対応する配列型を持つはずです(すなわち、要素がスカラ型の標準varlena配列型で、スカラ型のpg_typeエントリのtyparrayフィールドから参照されているもの)。
genbki.plはたいていの場合に配列型に対するpg_typeエントリも自動的に生成できます。
この機能を使うには、スカラ型のpg_typeエントリにarray_type_oid => というメタデータフィールドを記述して、配列型に使用するOIDを指定します。
自動的にそのOIDが書かれるため、このときnnnntyparrayフィールドを省いてもよいです。
生成された配列型の名前は、スカラ型の名前の手前にアンダースコアを付けたものです。
配列エントリの他のフィールドは、pg_type.hでBKI_ARRAY_DEFAULT(注釈から充当され、もし無ければスカラ型からコピーされます。
(value)typalignに対する特別な場合もあります。)
さらに両エントリのtypelemおよびtyparrayフィールドは相互参照するように設定されます。
カタログデータファイルを更新する共通の作業を実施するためのもっとも簡単な方法の提案を示します。
カタログにデフォルト付きの新しいカラムを追加する.
BKI_DEFAULT(注釈付きでヘッダーファイルにカラムを追加します。
非デフォルト値が必要な既存の行に対してのみフィールドを追加によるデータファイルの調整が必要です。
value)
デフォルト値を持たない既存のカラムにデフォルト値を追加する.
BKI_DEFAULT注釈をヘッダーファイルに追加し、冗長になったフィールドエントリを削除するためにmake reformat-dat-filesを実行します。
デフォルト値の有無にかかわらず、カラムを削除する.
ヘッダーからカラムを削除し、make reformat-dat-filesを実行して不要になったフィールドエントリを削除します。
既存のデフォルト値を変更もしくは削除する.
現在のデータが正しく解釈されなくなるため、単にヘッダーファイルを変更することはできません。
まずmake expand-dat-filesを実行し、すべてのデフォルト値が明示的に挿入されるようにデータファイルを書き換えます。
次にBKI_DEFAULT注釈を変更もしくは削除し、make reformat-dat-filesを実行して余分のフィールドを再び削除します。
特定の目的のための大量の編集:
reformat_dat_file.plを使って色々な大量の変更を実施できます。
一度限りのコードを挿入できることを示すブロックコメントを見つけます。
次の例では、pg_proc中の2つの論理値型フィールドを一つの文字フィールドに統合します。
デフォルトがある新しいカラムをpg_proc.hに追加します。
+ /* see PROKIND_ categories below */ + char prokind BKI_DEFAULT(f);
臨機応変に適当な値を挿入するために、reformat_dat_file.plを元に新しいスクリプトを作ります。
- # At this point we have the full row in memory as a hash
- # and can do any operations we want. As written, it only
- # removes default values, but this script can be adapted to
- # do one-off bulk-editing.
+ # One-off change to migrate to prokind
+ # Default has already been filled in by now, so change to other
+ # values as appropriate
+ if ($values{proisagg} eq 't')
+ {
+ $values{prokind} = 'a';
+ }
+ elsif ($values{proiswindow} eq 't')
+ {
+ $values{prokind} = 'w';
+ }
スクリプトを実行します。
$ cd src/include/catalog $ perl rewrite_dat_with_prokind.pl pg_proc.dat
この時点でpg_proc.datにはprokind、proisagg、proiswindowのすべての3つのカラムがありますが、非デフォルト値を持つ行だけに表れます。
pg_proc.hから古いカラムを削除します。
- /* is it an aggregate? */ - bool proisagg BKI_DEFAULT(f); - - /* is it a window function? */ - bool proiswindow BKI_DEFAULT(f);
最後に、make reformat-dat-filesを実行してpg_proc.datから不要になった古いエントリを削除します。
さらなる大量編集スクリプトの例については、https://www.postgresql.org/message-id/CAJVSVGVX8gXnPm+Xa=DxR7kFYprcQ1tNcCT5D0O3ShfnM6jehA@mail.gmail.comに付随するconvert_oid2name.plとremove_pg_type_oid_symbols.plを見てください。