Server-Side PreparedStatementのパラメータがサーバへ送信されるタイミング

C/Jマニュアルfor3.1によれば

ドライバは(PreparedStatementが実行されるよりも以前に)パラメータが設定された時点でこの大きなデータをサーバサイドのPreparedStatementに送ります。

ということらしい.ここで言う"大きなデータ"とはsetBinaryStream()、setAsciiStream()、setUnicodeStream()、setBlob()、あるいはsetClob()で渡されたものを指す.
原文だとこう書いてある.

The driver streams the 'large' data 'out-of-band' to the prepared statement on the server side when the parameter is set (before execution of the prepared statement).

つまり,ServerPreparedStatement.setBlob()が呼ばれた時にPacketを送るということですよね.

しかしServerPreparedStatement.setBlob()他メソッドのコードを見るに,事前送信している気配が無い.

実際にやってみても,executeする前に送っているようには見えない.

System.err.println("11111111111111111111");
pstmt.setInt(1, 10);
System.err.println("22222222222222222222");
blob.setBytes(1, new byte[10000000]);
pstmt.setBlob(2, blob);
pstmt.setBytes(2, new byte[1]);
blob.setBytes(1, new byte[10000000]);
pstmt.setBlob(2, blob);
pstmt.setBytes(2, new byte[1]);
System.err.println("33333333333333333333");
pstmt.execute();
System.err.println("44444444444444444444");

この例だと"2222..2"と"3333..33"の間でPacketが送られるはずだが,しかし

11111111111111111111
22222222222222222222
33333333333333333333
/* conn id 50 */ SET @debug_stmt_param4_0=10;
/* conn id 50 */ SET @debug_stmt_param4_1='[B@6e70c7';
/* conn id 50 */ EXECUTE debug_stmt_4 USING @debug_stmt_param4_0, @debug_stmt_param4_1;

44444444444444444444

"333..33"と"444..44"の間でまとめて送信しているだけ.

マニュアル的には

従って、パラメータを小さいものへ変更する場合には、PreparedStatementを再実行する前にclearParameters()メソッドを呼びすべてのパラメータを再設定する必要があります。

なのだが、clearParameters()を行わなくとも通ってしまう.

がー、こういうの見つけると気になって先に進めない.orz



JDBC 4.0 Spec読んでたら何か見つけた.

A value must be provided for each parameter marker in the PreparedStatement
object before it can be executed. The methods used to execute a PreparedStatement
object (executeQuery, executeUpdate and execute) will throw an SQLException if a
value is not supplied for a parameter marker.
The values set for the parameter markers of a PreparedStatement object are not
reset when it is executed. The method clearParameters can be called to explicitly
clear the values that have been set. Setting a parameter with a different value will
replace the previous value with the new one.

Note – If, in the execution of a PreparedStatement object, the JDBC driver reads
values set for the parameter markers by the methods setAsciiStream,
setBinaryStream, setCharacterStream, setNCharacterStream or
setUnicodeStream, those parameters must be reset prior to the next execution of
the PreparedStatement object otherwise a SQLException will be thrown. A
SQLException will also be thrown if the same stream is used by multiple
parameter markers within the same PreparedStatement object execution.

setBlobは対象外?

さておき、この説明によるとjava.sql.PreparedStatementは設定されたパラメータはexecute時にリセットされないので再実行可能,明示的にリセットするにはclearParametersメソッドを使うべし,ただしsetAsciiStream他は(※ストリームなので残らないから)再セットしないで再実行するとSQLExceptionがスローされるよ,ということらしい.

別にSPEC的には事前送信は規定してないね.そしてC/Jも事前送信しない.マニュアルが何か変な気がする.しかしJDBC仕様書ってほんとあいまいな定義しかしてくれてないのね.まあ異なるRDBMSへの共通のインタフェースを定義というわけだから分からなくも無いけど.