A custom scan is represented in a finished plan tree using the following structure: カスタムスキャンは完成した計画ツリー内で、以下の構造体を使って表現されます。
typedef struct CustomScan
{
Scan scan;
uint32 flags;
List *custom_plans;
List *custom_exprs;
List *custom_private;
List *custom_scan_tlist;
Bitmapset *custom_relids;
const CustomScanMethods *methods;
} CustomScan;
<structfield>scan</structfield> must be initialized as for any other scan, including
estimated costs, target lists, qualifications, and so on.
<structfield>flags</structfield> is a bit mask with the same meaning as in
<structname>CustomPath</structname>.
<structfield>custom_plans</structfield> can be used to store child
<structname>Plan</structname> nodes.
<structfield>custom_exprs</structfield> should be used to
store expression trees that will need to be fixed up by
<filename>setrefs.c</filename> and <filename>subselect.c</filename>, while
<structfield>custom_private</structfield> should be used to store other private data
that is only used by the custom scan provider itself.
<structfield>custom_scan_tlist</structfield> can be NIL when scanning a base
relation, indicating that the custom scan returns scan tuples that match
the base relation's row type. Otherwise it is a target list describing
the actual scan tuples. <structfield>custom_scan_tlist</structfield> must be
provided for joins, and could be provided for scans if the custom scan
provider can compute some non-Var expressions.
<structfield>custom_relids</structfield> is set by the core code to the set of
relations (range table indexes) that this scan node handles; except when
this scan is replacing a join, it will have only one member.
<structfield>methods</structfield> must point to a (usually statically allocated)
object implementing the required custom scan methods, which are further
detailed below.
scanは他のすべてのスキャンと同じく、推定コスト、対象のリスト、制約などを含めて初期化される必要があります。
flagsはCustomPathと同じ意味のビットマスクです。
custom_plansは子のPlanノードを格納するために使うことができます。
custom_exprsはsetrefs.cおよびsubselect.cによって作成される必要がある式のツリーを格納するために使われます。
一方でcustom_privateはカスタムスキャンプロバイダ自体によってのみ使用されるその他のプライベートデータを格納するために使われます。
custom_scan_tlistはベースリレーションをスキャンするときはNILとすることができます。
これはカスタムスキャンがベースリレーションの行の型と一致するスキャンタプルを返すことを意味します。
それ以外の場合は、実際のスキャンタプルを表現する対象のリストとなります。
custom_scan_tlistは結合の場合には提供される必要があります。
また、カスタムスキャンプロバイダがVarでない式を計算できる場合はスキャン用に提供することができます。
custom_relidsは、コアコードにより、このスキャンノードが処理するリレーションの集合(範囲テーブルのインデックス)にセットされます。
ただし、このスキャンが結合を置換する場合は例外で、ただ1つのメンバだけになります。
methodsは必要なカスタムスキャンメソッドを実装しているオブジェクト(通常は静的に割り当てられる)を指していなければなりません。
これについては以下で詳しく説明します。
When a <structname>CustomScan</structname> scans a single relation,
<structfield>scan.scanrelid</structfield> must be the range table index of the table
to be scanned. When it replaces a join, <structfield>scan.scanrelid</structfield>
should be zero.
CustomScanがリレーションを1つだけスキャンするときは、scan.scanrelidはスキャンされるテーブルの範囲テーブルのインデックスである必要があります。
結合を置換するときはscan.scanrelidはゼロになります。
Plan trees must be able to be duplicated using <function>copyObject</function>,
so all the data stored within the <quote>custom</quote> fields must consist of
nodes that that function can handle. Furthermore, custom scan providers
cannot substitute a larger structure that embeds
a <structname>CustomScan</structname> for the structure itself, as would be possible
for a <structname>CustomPath</structname> or <structname>CustomScanState</structname>.
計画ツリーはcopyObjectにより複製できる必要があるので、「custom」フィールド内に格納されるすべてのデータは、その関数が処理できるノードから構成されていなければなりません。
また、カスタムスキャンプロバイダはCustomScanを組み込んでいる大きな構造体をCustomScanの構造体で代替することができません。
CustomPathやCustomScanStateに対してはこれが可能です。
Node *(*CreateCustomScanState) (CustomScan *cscan);
Allocate a <structname>CustomScanState</structname> for this
<structname>CustomScan</structname>. The actual allocation will often be larger than
required for an ordinary <structname>CustomScanState</structname>, because many
providers will wish to embed that as the first field of a larger structure.
The value returned must have the node tag and <structfield>methods</structfield>
set appropriately, but other fields should be left as zeroes at this
stage; after <function>ExecInitCustomScan</function> performs basic initialization,
the <function>BeginCustomScan</function> callback will be invoked to give the
custom scan provider a chance to do whatever else is needed.
このCustomScanにCustomScanStateの領域を割り当てます。
多くのプロバイダは、より大きな構造体の最初のフィールドとしてこれを組み込もうとするので、実際の割り当ては通常のCustomScanStateが必要とするよりも多くくなることが多いでしょう。
戻り値では、ノードのタグとmethodsが適切に設定されている必要がありますが、その他のフィールドはこの段階ではゼロのままになっています。
ExecInitCustomScanが基本的な初期化をした後、BeginCustomScanコールバックが呼び出されることで、カスタムスキャンプロバイダがその他の必要なことを実行する機会が与えられます。