3434import io .r2dbc .spi .IsolationLevel ;
3535import io .r2dbc .spi .Lifecycle ;
3636import io .r2dbc .spi .R2dbcNonTransientResourceException ;
37+ import io .r2dbc .spi .Readable ;
3738import io .r2dbc .spi .TransactionDefinition ;
3839import io .r2dbc .spi .ValidationDepth ;
3940import org .jetbrains .annotations .Nullable ;
@@ -64,12 +65,6 @@ public final class MySqlConnection implements Connection, Lifecycle, ConnectionS
6465
6566 private static final String PING_MARKER = "/* ping */" ;
6667
67- private static final String ZONE_PREFIX_POSIX = "posix/" ;
68-
69- private static final String ZONE_PREFIX_RIGHT = "right/" ;
70-
71- private static final int PREFIX_LENGTH = 6 ;
72-
7368 private static final ServerVersion MARIA_11_1_1 = ServerVersion .create (11 , 1 , 1 , true );
7469
7570 private static final ServerVersion MYSQL_8_0_3 = ServerVersion .create (8 , 0 , 3 );
@@ -333,7 +328,8 @@ public Mono<Void> setTransactionIsolationLevel(IsolationLevel isolationLevel) {
333328 requireNonNull (isolationLevel , "isolationLevel must not be null" );
334329
335330 // Set subsequent transaction isolation level.
336- return QueryFlow .executeVoid (client , "SET SESSION TRANSACTION ISOLATION LEVEL " + isolationLevel .asSql ())
331+ return QueryFlow .executeVoid (client ,
332+ "SET SESSION TRANSACTION ISOLATION LEVEL " + isolationLevel .asSql ())
337333 .doOnSuccess (ignored -> {
338334 this .sessionLevel = isolationLevel ;
339335 if (!this .isInTransaction ()) {
@@ -436,7 +432,7 @@ public Mono<Void> setStatementTimeout(Duration timeout) {
436432 final ServerVersion serverVersion = context .getServerVersion ();
437433 final long timeoutMs = timeout .toMillis ();
438434 final String sql = isMariaDb ? "SET max_statement_time=" + timeoutMs / 1000.0
439- : "SET SESSION MAX_EXECUTION_TIME=" + timeoutMs ;
435+ : "SET SESSION MAX_EXECUTION_TIME=" + timeoutMs ;
440436
441437 // mariadb: https://mariadb.com/kb/en/aborting-statements/
442438 // mysql: https://dev.mysql.com/blog-archive/server-side-select-statement-timeouts/
@@ -485,10 +481,10 @@ static Mono<MySqlConnection> init(
485481 Mono <MySqlConnection > connection = initSessionVariables (client , sessionVariables )
486482 .then (loadSessionVariables (client , codecs , context ))
487483 .map (data -> {
488- ZoneId serverZoneId = data .serverZoneId ;
489- if (serverZoneId != null ) {
490- logger .debug ("Set server time zone to {} from init query " , serverZoneId );
491- context .setServerZoneId ( serverZoneId );
484+ ZoneId timeZone = data .timeZone ;
485+ if (timeZone != null ) {
486+ logger .debug ("Got server time zone {} from loading session variables " , timeZone );
487+ context .setTimeZone ( timeZone );
492488 }
493489
494490 return new MySqlConnection (client , context , codecs , data .level , data .lockWaitTimeout ,
@@ -531,21 +527,21 @@ private static Mono<Void> initSessionVariables(Client client, List<String> sessi
531527 return QueryFlow .executeVoid (client , query .toString ());
532528 }
533529
534- private static Mono <InitData > loadSessionVariables (
530+ private static Mono <SessionData > loadSessionVariables (
535531 Client client , Codecs codecs , ConnectionContext context
536532 ) {
537533 StringBuilder query = new StringBuilder (160 )
538534 .append ("SELECT " )
539535 .append (transactionIsolationColumn (context ))
540536 .append (",@@innodb_lock_wait_timeout AS l,@@version_comment AS v" );
541537
542- Function <MySqlResult , Flux <InitData >> handler ;
538+ Function <MySqlResult , Flux <SessionData >> handler ;
543539
544- if (context .shouldSetServerZoneId ()) {
545- query .append (",@@system_time_zone AS s,@@time_zone AS t" );
546- handler = MySqlConnection ::fullInit ;
540+ if (context .isTimeZoneInitialized ()) {
541+ handler = r -> convertSessionData (r , false );
547542 } else {
548- handler = MySqlConnection ::init ;
543+ query .append (",@@system_time_zone AS s,@@time_zone AS t" );
544+ handler = r -> convertSessionData (r , true );
549545 }
550546
551547 return new TextSimpleStatement (client , codecs , context , query .toString ())
@@ -569,70 +565,39 @@ private static Mono<Void> initDatabase(Client client, String database) {
569565 });
570566 }
571567
572- private static Flux <InitData > init (MySqlResult r ) {
573- return r .map ((row , meta ) -> new InitData (convertIsolationLevel (row .get (0 , String .class )),
574- convertLockWaitTimeout (row .get (1 , Long .class )),
575- row .get (2 , String .class ), null ));
576- }
577-
578- private static Flux <InitData > fullInit (MySqlResult r ) {
579- return r .map ((row , meta ) -> {
580- IsolationLevel level = convertIsolationLevel (row .get (0 , String .class ));
581- long lockWaitTimeout = convertLockWaitTimeout (row .get (1 , Long .class ));
582- String product = row .get (2 , String .class );
583- String systemTimeZone = row .get (3 , String .class );
584- String timeZone = row .get (4 , String .class );
585- ZoneId zoneId ;
586-
587- if (timeZone == null || timeZone .isEmpty () || "SYSTEM" .equalsIgnoreCase (timeZone )) {
588- if (systemTimeZone == null || systemTimeZone .isEmpty ()) {
589- logger .warn ("MySQL does not return any timezone, trying to use system default timezone" );
590- zoneId = ZoneId .systemDefault ();
591- } else {
592- zoneId = convertZoneId (systemTimeZone );
593- }
594- } else {
595- zoneId = convertZoneId (timeZone );
596- }
568+ private static Flux <SessionData > convertSessionData (MySqlResult r , boolean timeZone ) {
569+ return r .map (readable -> {
570+ IsolationLevel level = convertIsolationLevel (readable .get (0 , String .class ));
571+ long lockWaitTimeout = convertLockWaitTimeout (readable .get (1 , Long .class ));
572+ String product = readable .get (2 , String .class );
597573
598- return new InitData (level , lockWaitTimeout , product , zoneId );
574+ return new SessionData (level , lockWaitTimeout , product , timeZone ? readZoneId ( readable ) : null );
599575 });
600576 }
601577
602- /**
603- * Creates a {@link ZoneId} from MySQL timezone result, or fallback to system default timezone if not
604- * found.
605- *
606- * @param id the ID/name of MySQL timezone.
607- * @return the {@link ZoneId}.
608- */
609- private static ZoneId convertZoneId (String id ) {
610- String realId ;
578+ private static ZoneId readZoneId (Readable readable ) {
579+ String systemTimeZone = readable .get (3 , String .class );
580+ String timeZone = readable .get (4 , String .class );
611581
612- if (id .startsWith (ZONE_PREFIX_POSIX ) || id .startsWith (ZONE_PREFIX_RIGHT )) {
613- realId = id .substring (PREFIX_LENGTH );
582+ if (timeZone == null || timeZone .isEmpty () || "SYSTEM" .equalsIgnoreCase (timeZone )) {
583+ if (systemTimeZone == null || systemTimeZone .isEmpty ()) {
584+ logger .warn ("MySQL does not return any timezone, trying to use system default timezone" );
585+ return ZoneId .systemDefault ().normalized ();
586+ } else {
587+ return convertZoneId (systemTimeZone );
588+ }
614589 } else {
615- realId = id ;
590+ return convertZoneId ( timeZone ) ;
616591 }
592+ }
617593
594+ private static ZoneId convertZoneId (String id ) {
618595 try {
619- switch (realId ) {
620- case "Factory" :
621- // It seems like UTC.
622- return ZoneOffset .UTC ;
623- case "America/Nuuk" :
624- // America/Godthab is the same as America/Nuuk, with DST.
625- return ZoneId .of ("America/Godthab" );
626- case "ROC" :
627- // It is equal to +08:00.
628- return ZoneId .of ("+8" );
629- }
630-
631- return ZoneId .of (realId , ZoneId .SHORT_IDS );
596+ return StringUtils .parseZoneId (id );
632597 } catch (DateTimeException e ) {
633598 logger .warn ("The server timezone is unknown <{}>, trying to use system default timezone" , id , e );
634599
635- return ZoneId .systemDefault ();
600+ return ZoneId .systemDefault (). normalized () ;
636601 }
637602 }
638603
@@ -691,7 +656,7 @@ private static String transactionIsolationColumn(ConnectionContext context) {
691656 "@@transaction_isolation AS i" : "@@tx_isolation AS i" ;
692657 }
693658
694- private static class InitData {
659+ private static class SessionData {
695660
696661 private final IsolationLevel level ;
697662
@@ -701,14 +666,14 @@ private static class InitData {
701666 private final String product ;
702667
703668 @ Nullable
704- private final ZoneId serverZoneId ;
669+ private final ZoneId timeZone ;
705670
706- private InitData (IsolationLevel level , long lockWaitTimeout , @ Nullable String product ,
707- @ Nullable ZoneId serverZoneId ) {
671+ private SessionData (IsolationLevel level , long lockWaitTimeout , @ Nullable String product ,
672+ @ Nullable ZoneId timeZone ) {
708673 this .level = level ;
709674 this .lockWaitTimeout = lockWaitTimeout ;
710675 this .product = product ;
711- this .serverZoneId = serverZoneId ;
676+ this .timeZone = timeZone ;
712677 }
713678 }
714679}
0 commit comments