SPI_execute
は指定したSQLコマンドを、count
行分実行します。
read_only
がtrueの場合、そのコマンドは読み取りのみでなければなりませんが、多少のオーバーヘッドが削減されます。
この関数は接続済みのプロシージャからのみ呼び出し可能です。
count
が0の場合、そのコマンドを、適用される全ての行に対して実行します。
count
が0より多ければ、そのコマンドが実行される行数は制限されます
(ほぼLIMITと似ています)。
例えば、
SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
は、テーブルに挿入できる行は多くても5行のみです。
複数のコマンドを1つの文字列として渡すことができます。
SPI_execute
は最後に実行したコマンドの結果を返します。
count
制限はそれぞれのコマンドに独立に適用されますが、ルールによって生成される隠れたコマンドには適用されません。
read_only
がfalseの場合、文字列内の各コマンドを実行する前にSPI_execute
はコマンドカウンタを増分し、新しいスナップショットを作成します。
このスナップショットは、現在のトランザクション隔離レベルがSERIALIZABLEの場合は変更されません。
しかし、READ COMMITTEDモードでは、このスナップショットは更新され、他のセッションで新しくコミットされたトランザクションの結果を各コマンドから参照できます。
これは、そのコマンドがデータベースを変更する場合、一貫性の維持に重要です。
read_only
がtrueの場合は、SPI_execute
はスナップショットもコマンドカウンタも更新しません。
さらに、普通のSELECTコマンドのみをコマンド文字列内に記述することができます。
このコマンドは、その前後の問い合わせによって事前に確立済みのスナップショットを使用して実行されます。
この実行モードは読み書きモードよりもコマンドごとのオーバーヘッドが省略される分多少高速です。
また、これにより本当に安定(stable)な関数を構築することができます。
つまり、連続した実行は全て同じスナップショットを使用しますので、結果は変わることがないということです。
一般的に、SPIを使用する1つの関数内で読み取りのみコマンドと読み書きコマンドを混在させることは勧めません。 読み取りのみの問い合わせでは、読み書き問い合わせでなされたデータベースの更新結果を参照されないため、非常に混乱した動作に陥ることがあります。
(最後の)コマンドが実行した実際の行数は、(関数の戻り値がSPI_OK_UTILITYでない限り)SPI_processed
グローバル変数内で渡されます。
関数の戻り値がSPI_OK_SELECTの場合、SPITupleTable *SPI_tuptableグローバルポインタを使用して、結果の行にアクセスすることができます。
SPITupleTable構造体は以下のように定義されています。
typedef struct { MemoryContext tuptabcxt; /* 結果テーブルのメモリコンテキスト */ uint32 alloced; /* 割り当て済みのvalsの数 */ uint32 free; /* 解放されたvalsの数 */ TupleDesc tupdesc; /* 行記述子 */ HeapTuple *vals; /* 行 */ } SPITupleTable;
vals が行へのポインタの配列です
(有効な項目数はSPI_processed
で判明します)。
tupdescは、行を扱うSPI関数に渡すことができる行記述子です。
tuptabcxt、alloced、freeはSPI呼び出し元での使用を意図していない内部的なフィールドです。
SPI_finish
は、現在のプロシージャで割り当てられた全てのSPITupleTableを解放します。
SPI_freetuptable
を呼び出して解放する場合、特定の結果テーブルを早めに解放することができます。
command
実行するコマンドを含む文字列。
read_only
読み取りのみの実行の場合true。
count
処理される、あるいは返される行の最大数。
コマンドの実行に成功した場合、以下のいずれかの(非負の)値が返されます。
SELECT(SELECT INTOを除く)が実行された場合。
SELECT INTOが実行された場合。
DELETEが実行された場合。
INSERTが実行された場合。
UPDATEが実行された場合。
ユーティリティコマンド(CREATE TABLEなど)が実行された場合。
エラーの場合、以下のいずれかの負の値が返されます。
command
がNULL、あるいはcount
が0未満の場合。
COPY TO stdoutあるいはCOPY FROM stdinが試行された場合。
DECLARE、CLOSE、FETCHが試行された場合。
トランザクション操作を行うコマンド(BEGIN、COMMIT、ROLLBACK、SAVEPOINT、PREPARE TRANSACTION、COMMIT PREPARED、ROLLBACK PREPARED、およびこれらの亜種)が試行された場合。
コマンド種類が不明な場合(起きてはなりません)。
未接続なプロシージャから呼び出された場合。