LoginSignup
0
0

pg_send_query って何だ?

Last updated at Posted at 2023-12-08

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 関数でも取得できない)

PHP: pg_send_query - Manual

エラー時の動作

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_statuspg_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_busytrue となり、pg_transaction_statusPGSQL_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_statusPGSQL_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_statusPGSQL_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_paramsfalse を返す為、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_paramstrue を返し、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にコマンドを投げて実行することには変わりないので、トータルの処理時間はそこまでかわらないはず。

ただ、自分が知らないだけで他の利点が有るかもしれないので、もし知っていたら教えていただきたい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0