手動で生成した初期データを持つ(いくつかのものは持っていません)各々のカタログには、編集可能なデータ形式の初期データを含み、対応する.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', datdba => 'PGUID', encoding => 'ENCODING', datcollate => 'LC_COLLATE', datctype => 'LC_CTYPE', datistemplate => 't', datallowconn => 't', datconnlimit => '-1', datlastsysoid => '0', datfrozenxid => '0', datminmxid => '1', dattablespace => '1663', datacl => '_null_' }, ]
特筆すべきポイント:
全体的なファイルレイアウトは次のようになります。 開き大括弧、カタログの行を表現する一つ以上の中括弧、閉じ大括弧。 各々の閉じ中括弧の後にはカンマを書きます。
各々のカタログ行にカンマ区切りでkey
=>
value
ペアを書きます。
記述可能なkey
は、カタログのカラムに加えてメタデータキーであるoid
、oid_symbol
、descr
です。
(oid
とoid_symbol
の使い方は後述の69.2.2に説明されています。
descr
はオブジェクトの説明文字列に使用し、pg_description
かpg_shdescription
の適切な方に挿入されます。)
メタデータキーは省略可能であるのに対し、カタログの.h
ファイルがカラムのデフォルト値を指定する場合を除いてカタログの定義済みカラムはすべて提供されなければなりません。
すべての値は単一引用符で囲まなければなりません。
値中の単一引用符はバックスラッシュでエスケープします。
データを意味するバックスラッシュは二重にできますが、必須ではありません。
これはPerlの単純な単一引用符で引用されたリテラルに関するルールに基づいています。
データとして使われるバックスラッシュは、エスケープ文字列定数(4.1.2.2参照)と同じルールに基づき、ブートストラップスキャナーはエスケープと解釈することに注意してください。
たとえば\t
はタブへと変換されます。
最終的な値としてバックスラッシュを使用したい場合は、4つ書く必要があります。
Perlが2つ削除し、ブートストラップスキャナーが認識するために\\
が残ります。
NULL値は_null_
で表します。
(それと同じ文字列を作る方法はないことに注意してください。)
コメントは#
を前に置いてください。また同じ行上に置かなければなりません。
読みやすくするために、他のカタログエントリのOIDであるフィールド値は数字のOIDではなく、名前で表すことができます。 これは後述の69.2.3で説明します。
ハッシュは順序付けられないデータ構造なので、フィールドの順や行の配置には重要な意味はありません。
しかし、見た目を統一するために、フォーマットスクリプトreformat_dat_file.pl
が適用される少数のルールを設定しました。
中括弧のペアの中で、メタデータフィールドのoid
、oid_symbol
、(もし存在するなら)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を割り当てられたならば、nnnn
oid_symbol =>
メタデータフィールドを書くことでそのOID用のCマクロを作ることができます。
name
他のプリロードカタログ行の中にそのOIDへの参照がある場合には、プリロードカタログ行は割当済みのOIDを持たなければなりません。
Cコードから行OIDが参照されるときにも割当済みのOIDは必要です。
どちらも当てはまらない場合は、oid
メタデータフィールドは省略可能です。
その場合、ブートストラップコードが自動的にOIDを割り当てるか、OIDを持たないカタログでは0のままになります。
実用的には、カタログの一部のみが実際に相互参照されている場合でも、与えられたプリロードカタログ行の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カウンタは1000から始まります。
テーブル中のカタログ行がOIDを必要としており、oid
フィールドにOIDが予め割り当てられていない場合は、1000以上のOIDを受け取ります。
初期カタログ行間の相互参照は、参照する行の割当済みOIDを記述するだけで可能です。
しかしこれは間違いやすく、また読みにくくなります。
そのため、頻繁に参照されるカタログでは、genbki.pl
が代わりにシンボル参照を記述する機構を提供しています。
今の所、アクセスメソッド、関数、演算子、演算子クラス、演算子ファミリー、型で参照アクセスが可能です。
そのルールは以下のとおりです。
BKI_LOOKUP(
をカラム定義に加えることで、特定のカタログカラムでのシンボル参照が利用可能になります。
ここでlookuprule
)lookuprule
は、pg_am
、pg_proc
、pg_operator
、pg_opclass
、pg_opfamily
、pg_type
のどれかです。
BKI_LOOKUP
を、Oid
、regproc
、oidvector
、Oid[]
のカラムに加えることができます。
最後の2つにおいては、配列の個々の要素を検索することを暗に意味します。
そうしたカラムでは、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スキーマにあると期待されます。
genbki.pl
は実行中にすべてのシンボル参照を解決し、生成したBKIファイルの中に単純な数字のOIDを設定します。
ですから、ブートストラップバックエンドはシンボル参照にかかわる必要はありません。
カタログデータファイルを更新する共通の作業を実施するためのもっとも簡単な方法の提案を示します。
カタログにデフォルト付きの新しいカラムを追加する.
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
を見てください。