2222import io .asyncer .r2dbc .mysql .client .FluxExchangeable ;
2323import io .asyncer .r2dbc .mysql .constant .ServerStatuses ;
2424import io .asyncer .r2dbc .mysql .constant .SslMode ;
25- import io .asyncer .r2dbc .mysql .internal .util .InternalArrays ;
2625import io .asyncer .r2dbc .mysql .internal .util .StringUtils ;
2726import io .asyncer .r2dbc .mysql .message .client .AuthResponse ;
2827import io .asyncer .r2dbc .mysql .message .client .ClientMessage ;
2928import io .asyncer .r2dbc .mysql .message .client .HandshakeResponse ;
30- import io .asyncer .r2dbc .mysql .message .client .LoginClientMessage ;
29+ import io .asyncer .r2dbc .mysql .message .client .LocalInfileResponse ;
30+ import io .asyncer .r2dbc .mysql .message .client .SubsequenceClientMessage ;
3131import io .asyncer .r2dbc .mysql .message .client .PingMessage ;
3232import io .asyncer .r2dbc .mysql .message .client .PrepareQueryMessage ;
3333import io .asyncer .r2dbc .mysql .message .client .PreparedCloseMessage ;
4444import io .asyncer .r2dbc .mysql .message .server .ErrorMessage ;
4545import io .asyncer .r2dbc .mysql .message .server .HandshakeHeader ;
4646import io .asyncer .r2dbc .mysql .message .server .HandshakeRequest ;
47+ import io .asyncer .r2dbc .mysql .message .server .LocalInfileRequest ;
4748import io .asyncer .r2dbc .mysql .message .server .OkMessage ;
4849import io .asyncer .r2dbc .mysql .message .server .PreparedOkMessage ;
4950import io .asyncer .r2dbc .mysql .message .server .ServerMessage ;
7475import java .util .List ;
7576import java .util .Map ;
7677import java .util .concurrent .atomic .AtomicBoolean ;
78+ import java .util .concurrent .atomic .AtomicInteger ;
7779import java .util .function .Consumer ;
7880import java .util .function .Predicate ;
7981
@@ -209,36 +211,26 @@ static Mono<Client> login(Client client, SslMode sslMode, String database, Strin
209211 * terminates with the last {@link CompleteMessage} or a {@link ErrorMessage}. The {@link ErrorMessage}
210212 * will emit an exception. The exchange will be completed by {@link CompleteMessage} after receive the
211213 * last result for the last binding.
214+ * <p>
215+ * Note: this method does not support {@code LOCAL INFILE} due to it should be used for excepted queries.
212216 *
213217 * @param client the {@link Client} to exchange messages with.
214218 * @param sql the query to execute, can be contains multi-statements.
215219 * @return receives complete signal.
216220 */
217221 static Mono <Void > executeVoid (Client client , String sql ) {
218- return Mono .defer (() -> execute0 (client , sql ).doOnNext (EXECUTE_VOID ).then ());
219- }
222+ return Mono .defer (() -> client .<ServerMessage >exchange (new TextQueryMessage (sql ), (message , sink ) -> {
223+ if (message instanceof ErrorMessage ) {
224+ sink .next (((ErrorMessage ) message ).offendedBy (sql ));
225+ sink .complete ();
226+ } else {
227+ sink .next (message );
220228
221- /**
222- * Execute multiple simple queries with one-by-one and return a {@link Mono} for the complete signal or
223- * error. Query execution terminates with the last {@link CompleteMessage} or a {@link ErrorMessage}. The
224- * {@link ErrorMessage} will emit an exception and cancel subsequent statements execution. The exchange
225- * will be completed by {@link CompleteMessage} after receive the last result for the last binding.
226- *
227- * @param client the {@link Client} to exchange messages with.
228- * @param statements the queries to execute, each element can be contains multi-statements.
229- * @return receives complete signal.
230- */
231- static Mono <Void > executeVoid (Client client , String ... statements ) {
232- switch (statements .length ) {
233- case 0 :
234- return Mono .empty ();
235- case 1 :
236- return executeVoid (client , statements [0 ]);
237- default :
238- return client .exchange (new MultiQueryExchangeable (InternalArrays .asIterator (statements )))
239- .doOnNext (EXECUTE_VOID )
240- .then ();
241- }
229+ if (message instanceof CompleteMessage && ((CompleteMessage ) message ).isDone ()) {
230+ sink .complete ();
231+ }
232+ }
233+ }).doOnSubscribe (ignored -> QueryLogger .log (sql )).doOnNext (EXECUTE_VOID ).then ());
242234 }
243235
244236 /**
@@ -303,18 +295,7 @@ static Mono<Void> createSavepoint(Client client, ConnectionState state, String n
303295 * @return the messages received in response to this exchange.
304296 */
305297 private static Flux <ServerMessage > execute0 (Client client , String sql ) {
306- return client .<ServerMessage >exchange (new TextQueryMessage (sql ), (message , sink ) -> {
307- if (message instanceof ErrorMessage ) {
308- sink .next (((ErrorMessage ) message ).offendedBy (sql ));
309- sink .complete ();
310- } else {
311- sink .next (message );
312-
313- if (message instanceof CompleteMessage && ((CompleteMessage ) message ).isDone ()) {
314- sink .complete ();
315- }
316- }
317- }).doOnSubscribe (ignored -> QueryLogger .log (sql ));
298+ return client .exchange (new SimpleQueryExchangeable (sql ));
318299 }
319300
320301 private QueryFlow () { }
@@ -339,6 +320,16 @@ public final void accept(ServerMessage message, SynchronousSink<ServerMessage> s
339320 if (message instanceof ErrorMessage ) {
340321 sink .next (((ErrorMessage ) message ).offendedBy (offendingSql ()));
341322 sink .complete ();
323+ } else if (message instanceof LocalInfileRequest ) {
324+ LocalInfileRequest request = (LocalInfileRequest ) message ;
325+ String path = request .getPath ();
326+
327+ QueryLogger .logLocalInfile (path );
328+
329+ requests .emitNext (
330+ new LocalInfileResponse (request .getEnvelopeId () + 1 , path , sink ),
331+ Sinks .EmitFailureHandler .FAIL_FAST
332+ );
342333 } else {
343334 sink .next (message );
344335
@@ -353,6 +344,59 @@ public final void accept(ServerMessage message, SynchronousSink<ServerMessage> s
353344 abstract protected String offendingSql ();
354345}
355346
347+ final class SimpleQueryExchangeable extends BaseFluxExchangeable {
348+
349+ private static final int INIT = 0 ;
350+
351+ private static final int EXECUTE = 1 ;
352+
353+ private static final int DISPOSE = 2 ;
354+
355+ private final AtomicInteger state = new AtomicInteger (INIT );
356+
357+ private final String sql ;
358+
359+ SimpleQueryExchangeable (String sql ) {
360+ this .sql = sql ;
361+ }
362+
363+ @ Override
364+ public void dispose () {
365+ if (state .getAndSet (DISPOSE ) != DISPOSE ) {
366+ requests .tryEmitComplete ();
367+ }
368+ }
369+
370+ @ Override
371+ public boolean isDisposed () {
372+ return state .get () == DISPOSE ;
373+ }
374+
375+ @ Override
376+ protected void tryNextOrComplete (@ Nullable SynchronousSink <ServerMessage > sink ) {
377+ if (state .compareAndSet (INIT , EXECUTE )) {
378+ QueryLogger .log (sql );
379+
380+ Sinks .EmitResult result = requests .tryEmitNext (new TextQueryMessage (sql ));
381+
382+ if (result == Sinks .EmitResult .OK ) {
383+ return ;
384+ }
385+
386+ QueryFlow .logger .error ("Emit request failed due to {}" , result );
387+ }
388+
389+ if (sink != null ) {
390+ sink .complete ();
391+ }
392+ }
393+
394+ @ Override
395+ protected String offendingSql () {
396+ return sql ;
397+ }
398+ }
399+
356400/**
357401 * An implementation of {@link FluxExchangeable} that considers client-preparing requests.
358402 */
@@ -770,8 +814,8 @@ final class LoginExchangeable extends FluxExchangeable<Void> {
770814
771815 private static final int HANDSHAKE_VERSION = 10 ;
772816
773- private final Sinks .Many <LoginClientMessage > requests = Sinks .many ().unicast ()
774- .onBackpressureBuffer (Queues .<LoginClientMessage >one ().get ());
817+ private final Sinks .Many <SubsequenceClientMessage > requests = Sinks .many ().unicast ()
818+ .onBackpressureBuffer (Queues .<SubsequenceClientMessage >one ().get ());
775819
776820 private final Client client ;
777821
@@ -879,7 +923,7 @@ public void dispose() {
879923 this .requests .tryEmitComplete ();
880924 }
881925
882- private void emitNext (LoginClientMessage message , SynchronousSink <Void > sink ) {
926+ private void emitNext (SubsequenceClientMessage message , SynchronousSink <Void > sink ) {
883927 Sinks .EmitResult result = requests .tryEmitNext (message );
884928
885929 if (result != Sinks .EmitResult .OK ) {
@@ -903,8 +947,6 @@ private Capability clientCapability(Capability serverCapability) {
903947
904948 builder .disableDatabasePinned ();
905949 builder .disableCompression ();
906- // TODO: support LOAD DATA LOCAL INFILE
907- builder .disableLoadDataInfile ();
908950 builder .disableIgnoreAmbiguitySpace ();
909951 builder .disableInteractiveTimeout ();
910952
0 commit comments