operator

例えば、

select * from branches b where b.bid = 1;

というSQLで'='というoperatorがどのように処理されるのか。

parserの処理

make_op()でoper(), make_op_expr()を実行し、executorが使うOpExprデータを作成する。
oper()では、operator名('=')と左辺/右辺のデータ型から、システムカタログのpg_operatorを検索し、executorが実行する関数を選択する。上記SQLの例では、int4eqが選ばれる。
make_op_expr()では、oper()の情報からOpExprノードを作成する。

executorの処理

executorの初期化でExecInitExpr()が実行され、OpExprノードからFuncExprStateを作成する。ここでFuncExprState->xprstate.evalfuncにExecEvalOperを設定している。
executorの実行フェーズではシーケンシャルスキャンの場合、ExecScan()がタプルを1行ずつ取り出してExecQual()を実行し、検索条件に一致するか調べていく。ExecQual()では、FuncExprState->xprstate.evalfuncを実行して検索条件を評価する。evalfuncはExecEvalOper()が設定されているので、これが実行される。
ExecEvalOper()では、まずinit_fcache()を実行する。init_fcache()では実行する関数(例ではint4eq)の実行権限があるか調べる。次にFuncExprState->xprstate.evalfuncをExecMakeFunctionResult()に書き換えてから、ExecMakeFunctionResult()を実行する。evalfuncを書き換えることにより、2行目以降のタプルではExecEvalOper()ではなく、ExecMakeFunctionResult()が直接実行されることになる。権限のチェックは1度だけ行えばいいからである。
ExecMakeFunctionResult()では、FunctionCallInvode()でparserが選択した関数(int4eq)を実行する。また、実行する関数の引数や戻り値がSet(配列などの集合データ)ではなく、単一の値が使われる場合、evalfuncをExecMakeFunctionResultNoSets()に書き換えている。
ExecMakeFunctionResultNoSets()はExecMakeFunctionResult()を簡略化した関数で、Setデータを扱わない変わりに動作速度が速い。int4eqはSetデータを扱わないので、evalfuncがExecMakeFunctionResultNoSets()に書き換えられる。つまり2行目以降のタプルでは、ExecQual()からExecMakeFunctionResultsNoSets()が実行される。これにより、'='の比較をできるだけ高速に実行するようになっている。