pg_send_query って何だ?
概要
PHP で PostgreSQL を使用したい場合、多くの人が PostgreSQL 関数を利用するだろう。PHPマニュアルのPostgreSQL関数を見ると、pg_send_ から始まる関数がいくつかあり使い方が気になったので調べてみた。
ちなみに自分は普段 pg_query_params, pg_fetch_assoc くらいしか使っていなかった。
pg_send_* 関数について
pg_send_* という名前の関数は現在、pg_send_execute, pg_send_prepare, pg_send_query, pg_send_query_params の4種類が存在する。
それぞれの関数名の似ている pg_execute, pg_prepare, pg_query, pg_query_params と似た構造をしていて引数が同じだが返値が異なる。 pg_send_* 関数の返値は、実行が成功したら true, 失敗したら 0 になる。
pg_send_* 関数は、実行時に結果を待たずに終了する。実行結果(PgSql\Resultオブジェクト)を取得するには pg_get_result 関数を使用する。結果を取得せずに連続でSQL実行したいのであれば、連続で pg_send_* を実行すれば時間短縮になるのだろう。
pg_send_* 関数を実行した場合、SQLエラーが起きても pg_get_result 関数で PgSql\Result オブジェクトを取得できる為、pg_result_error, pg_result_error_field 関数を使用してより詳細なエラー情報を取得できる。(pg_query, pg_query_params 関数ではエラー時に PgSql\Result を返さないし、pg_get_result 関数でも取得できない)
エラー時の動作
pg_send_* 関数は実行結果を待たないため、エラー時(不正なSQL実行時など)の動作が変化する。
pg_query_params では、以下のようにWarningがでて、返値は false になる。
$r = pg_query_params($conn, "SELEEEEECT * FROM hoge", array());
//=> false
Warning: pg_query_params(): Query failed: ERROR: syntax error at or near "SEEEELECT"
LINE 1: SELEEEEECT * FROM hoge
pg_send_query_params 関数では Warning も何もなく、返値も true が返る。
$r = pg_send_query_params($conn, "SELEEEEECT * FROM hoge", array());
//=> true
エラーを取得するには、pg_get_result($conn) で PgSql\Result オブジェクトを取得してからpg_result_error($result) でエラーメッセージがあるか確認するか、pg_last_error($conn) でエラーメッセージを確認する。
$r = pg_send_query_params($conn, "SELEEEEECT * FROM hoge", array());
//=> true
$result = pg_get_result($conn);
if (($errmsg = pg_result_error($result))) {
echo "ErrorMessage: {$errmsg}\n";
}
pg_result_error_field($result, $field_code) 関数でより詳細なエラー情報を取得できるが、pg_last_error 関数や pg_result_error 関数で取得するエラーメッセージで充分だし読みやすいので、普段は使わないでもよいだろう。
pg_send_* ではなく pg_query_params 等でエラーが発生した場合は、pg_get_result 関数で PgSql\Result を取得できない。よって、PgSql\Result が必要な pg_result_error 関数や pg_result_error_field 関数は使えないので、pg_last_error 関数を使用する必要がある。
DB状態の確認
pg_connection_status, pg_connection_busy, pg_transaction_status と pg_result_status 等はDB/SQL実行結果の状態を確認する関数である。これらを pg_send_query_params , pg_query_params 関数の前後に実行し、どのようにステータス変化するかを確認した。
簡単にまとめると、
-
pg_query_params関数の前後では、pg_connection_status,pg_connection_busy,pg_transaction_status関数の返値は変化しなかった -
pg_connection_status関数は常にPGSQL_CONNECTION_OKを返した -
pg_connection_busy関数の返値は細かくtrue/falseが切り替わっているようだ。pg_send_*関数の実行後pg_get_result実行前までや、SQLエラー発生後しばらくはtrueだった - トランザクション中はもちろんだが、
pg_send_*関数実行直後もpg_transaction_status関数の返値が変化することがわかった -
pg_result_status関数はその名の通り、PgSql\Resultオブジェクトの状態を返してくれた
試したコード例と各状態を以下に列挙する。
コード例1 - pg_query_params で SELECT文
// 実行前(A)
$result = pg_query_params($conn, "SELECT * FROM hoge", array());
// 実行後(B)
| (A) | (B) | |
|---|---|---|
| pg_connection_busy | false | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_IDLE |
| $result |
PgSql\Resultオブジェクト |
|
| pg_result_status | PGSQL_TUPLES_OK |
コード例2 - pg_send_query_params で SELECT文
// pg_send_* 実行前(A)
$retval = pg_send_query_params($conn, "SELECT * FROM hoge", array());
// pg_send_* 実行後(B)
$result = pg_get_result($conn);
// pg_get_result 実行後(C)
| (A) | (B) | (C) | |
|---|---|---|---|
| pg_connection_busy | false | true | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_ACTIVE | PGSQL_TRANSACTION_IDLE |
| $retval | true | ||
| $result |
PgSql\Resultオブジェクト |
||
| pg_result_status | PGSQL_TUPLES_OK |
コード例1との違いは、pg_send_* の直後に pg_connection_busy が true となり、pg_transaction_status が PGSQL_TRANSACTION_ACTIVE となる点。pg_get_result の実行後はコード例1と同じになる。
コード例3 - pg_query_params で INSERT/UPDATE/DELETE文
// 実行前(A)
$result = pg_query_params($conn, "INSERT hoge (col1) VALUES(\$1)", array('val1'));
// 実行後(B)
| (A) | (B) | |
|---|---|---|
| pg_connection_busy | false | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_IDLE |
| $result |
PgSql\Resultオブジェクト |
|
| pg_result_status | PGSQL_COMMAND_OK |
pg_result_status が PGSQL_COMMAND_OK に変わっただけで、他はコード例1と同じ。UPDATE,DELETE文にしても同様
コード例4 - pg_send_query_params で INSERT/UPDATE/DELETE文
// pg_send_* 実行前(A)
$retval = pg_send_query_params($conn, "INSERT hoge (col1) VALUES(\$1)", array('val1'));
// pg_send_* 実行後(B)
$result = pg_get_result($conn);
// pg_get_result 実行後(C)
| (A) | (B) | (C) | |
|---|---|---|---|
| pg_connection_busy | false | true | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_ACTIVE | PGSQL_TRANSACTION_IDLE |
| $retval | true | ||
| $result |
PgSql\Resultオブジェクト |
||
| pg_result_status | PGSQL_COMMAND_OK |
pg_result_status が PGSQL_COMMAND_OK に変わっただけで、他はコード例2と同じ。UPDATE,DELETE文にしても同様
コード例5: pg_query_params でトランザクション中にSELECT文
pg_query($conn, "BEGIN");
// 実行前(A)
$result = pg_query_params($conn, "SELECT * FROM hoge", array());
// 実行後(B)
pg_query($conn, "END");
| (A) | (B) | |
|---|---|---|
| pg_connection_busy | false | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_INTRANS | PGSQL_TRANSACTION_INTRANS |
| $result |
PgSql\Resultオブジェクト |
|
| pg_result_status | PGSQL_TUPLES_OK |
コード例1とほぼ同じだが、pg_transaction_status の結果が PGSQL_TRANSACTION_IDLE ではなく PGSQL_TRANSACTION_INTRANS になっている
コード例6 - pg_send_query_params でトランザクション中にSELECT文
pg_query($conn, "BEGIN");
// pg_send_* 実行前(A)
$retval = pg_send_query_params($conn, "SELECT * FROM hoge", array());
// pg_send_* 実行後(B)
$result = pg_get_result($conn);
// pg_get_result 実行後(C)
pg_query($conn, "END");
| (A) | (B) | (C) | |
|---|---|---|---|
| pg_connection_busy | false | true | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_INTRANS | PGSQL_TRANSACTION_ACTIVE | PGSQL_TRANSACTION_INTRANS |
| $retval | true | ||
| $result |
PgSql\Resultオブジェクト |
||
| pg_result_status | PGSQL_TUPLES_OK |
コード例2とほぼ同じだが、pg_transaction_statusの結果が PGSQL_TRANSACTION_IDLE ではなく PGSQL_TRANSACTION_INTRANS になっている
コード例7 - pg_query_params でSQLエラー発生
// 実行前(A)
$result = pg_query_params($conn, "SELEEEECT * FROM hoge", array());
// 実行後(B)
| (A) | (B) | |
|---|---|---|
| pg_connection_busy | false | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_IDLE |
| $result | false | |
| pg_result_status | (実行不可) |
SQLエラーが発生すると、pg_query_params が false を返す為、PgSql\Result は取得できない。
エラー内容は pg_last_error($conn) からエラーメッセージを取得し判断するしかないか。
コード例8 - pg_send_query_params でSQLエラー発生
// pg_send_* 実行前(A)
$retval = pg_send_query_params($conn, "SELEEEEECT * FROM hoge", array());
// pg_send_* 実行後(B)
$result = pg_get_result($conn);
// pg_get_result 実行後(C)
| (A) | (B) | (C) | (C') | |
|---|---|---|---|---|
| pg_connection_busy | false | true | false | true |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_ACTIVE | PGSQL_TRANSACTION_IDLE | PGSQL_TRANSACTION_ACTIVE |
| $retval | true | |||
| $result |
PgSql\Resultオブジェクト |
PgSql\Resultオブジェクト |
||
| pg_result_status | PGSQL_FATAL_ERROR | PGSQL_FATAL_ERROR |
SQLエラーが発生しても、pg_send_query_params は true を返し、pg_get_result($conn)で PgSql\Result が取得可能。pg_result_status($result) とすると、PGSQL_FATAL_ERROR を返し、エラーが起きていたことがわかる。
エラー内容は pg_last_error($conn) からエラーメッセージを取得してもよいし、PgSql\Result オブジェクトから pg_result_error($result) 関数 や pg_result_error_field($result, $field_code) 関数でもエラー情報を取得できる。
細かい点だがSQLエラー時は pg_get_result 実行直後も pg_connection_busy 関数が true を返し、pg_transaction_status 関数が PGSQL_TRANSACTION_ACTIVE を返す こともある ので注意(C')。
コード例9: pg_query_params でトランザクション中にSQLエラー発生
pg_query($conn, "BEGIN");
// 実行前(A)
$result = pg_query_params($conn, "SELEEEEECT * FROM hoge", array());
// 実行後(B)
pg_query($conn, "END");
| (A) | (B) | |
|---|---|---|
| pg_connection_busy | false | false |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_INTRANS | PGSQL_TRANSACTION_INERROR |
| $result | false | |
| pg_result_status | (実行不可) |
SQLエラー発生後はトランザクションが終了する(END や ROLLBACK を実行する)まで、pg_transaction_status 関数は PGSQL_TRANSACTION_INERROR を返す。
コード例10 - pg_send_query_params でトランザクション中にSQLエラー発生
pg_query($conn, "BEGIN");
// pg_send_* 実行前(A)
$retval = pg_send_query_params($conn, "SELEEEEECT * FROM hoge", array());
// pg_send_* 実行後(B)
$result = pg_get_result($conn);
// pg_get_result 実行後(C)
pg_query($conn, "END");
| (A) | (B) | (C) | (C') | |
|---|---|---|---|---|
| pg_connection_busy | false | true | false | true |
| pg_connection_status | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK | PGSQL_CONNECTION_OK |
| pg_transaction_status | PGSQL_TRANSACTION_INTRANS | PGSQL_TRANSACTION_ACTIVE | PGSQL_TRANSACTION_INERROR | PGSQL_TRANSACTION_ACTIVE |
| $retval | true | |||
| $result |
PgSql\Resultオブジェクト |
PgSql\Resultオブジェクト |
||
| pg_result_status | PGSQL_FATAL_ERROR | PGSQL_FATAL_ERROR |
コード例8とほぼ同じ。トランザクション中なので pg_transaction_status の返値が異なる
コード例8と同じく、SQLエラー時は pg_get_result 実行後も pg_connection_busy 関数が true を返し、pg_transaction_status 関数が PGSQL_TRANSACTION_ACTIVE を返すこともあるので注意(C')。
まとめ
pg_send_* 関数を使用すれば、より詳細なエラー情報を取得し、返答が不要なSQLを連続実行できるといった利点がある。ただ、手間の割にメリットは薄いように思われるので通常は pg_query_params 等で充分だろう。
SQL連続実行にしても、順にPostgreSQLにコマンドを投げて実行することには変わりないので、トータルの処理時間はそこまでかわらないはず。
ただ、自分が知らないだけで他の利点が有るかもしれないので、もし知っていたら教えていただきたい。