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にコマンドを投げて実行することには変わりないので、トータルの処理時間はそこまでかわらないはず。
ただ、自分が知らないだけで他の利点が有るかもしれないので、もし知っていたら教えていただきたい。