diff --git a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionConfiguration.java b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionConfiguration.java
index 93ba9ce78..3857451a1 100644
--- a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionConfiguration.java
+++ b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionConfiguration.java
@@ -1220,8 +1220,10 @@ public Builder metrics(boolean enabled) {
/**
* Option to whether the driver should interpret MySQL's TINYINT(1) as a BIT type.
- * When enabled, TINYINT(1) columns (both SIGNED and UNSIGNED) will be treated as
- * BIT. default to {@code true}.
+ * When enabled, TINYINT(1) columns will be treated as BIT. Defaults to {@code true}.
+ *
+ * Note: Only signed TINYINT(1) columns can be treated as BIT or Boolean.
+ * Ref: https://bugs.mysql.com/bug.php?id=100309
*
* @param tinyInt1isBit {@code true} to treat TINYINT(1) as BIT
* @return this {@link Builder}
diff --git a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionFactoryProvider.java b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionFactoryProvider.java
index bff335123..5905c56ca 100644
--- a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionFactoryProvider.java
+++ b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/MySqlConnectionFactoryProvider.java
@@ -332,8 +332,10 @@ public final class MySqlConnectionFactoryProvider implements ConnectionFactoryPr
/**
* Option to whether the driver should interpret MySQL's TINYINT(1) as a BIT type.
- * When enabled, TINYINT(1) columns (both SIGNED and UNSIGNED) will be treated as
- * BIT. default to {@code true}.
+ * When enabled, TINYINT(1) columns will be treated as BIT. Defaults to {@code true}.
+ *
+ * Note: Only signed TINYINT(1) columns can be treated as BIT or Boolean.
+ * Ref: https://bugs.mysql.com/bug.php?id=100309
*
* @since 1.4.0
*/
diff --git a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/BooleanCodec.java b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/BooleanCodec.java
index 0a59265c3..8fb98c273 100644
--- a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/BooleanCodec.java
+++ b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/BooleanCodec.java
@@ -32,6 +32,8 @@
*/
final class BooleanCodec extends AbstractPrimitiveCodec {
+ private static final Integer INTEGER_ONE = Integer.valueOf(1);
+
static final BooleanCodec INSTANCE = new BooleanCodec();
private BooleanCodec() {
@@ -86,7 +88,7 @@ public MySqlParameter encode(Object value, CodecContext context) {
public boolean doCanDecode(MySqlReadableMetadata metadata) {
MySqlType type = metadata.getType();
return ((type == MySqlType.BIT || type == MySqlType.TINYINT) &&
- Integer.valueOf(1).equals(metadata.getPrecision())) || type == MySqlType.VARCHAR;
+ INTEGER_ONE.equals(metadata.getPrecision())) || type == MySqlType.VARCHAR;
}
public Boolean createFromLong(long l) {
diff --git a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/DefaultCodecs.java b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/DefaultCodecs.java
index ba022875a..34f2c67c1 100644
--- a/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/DefaultCodecs.java
+++ b/r2dbc-mysql/src/main/java/io/asyncer/r2dbc/mysql/codec/DefaultCodecs.java
@@ -45,8 +45,6 @@
*/
final class DefaultCodecs implements Codecs {
- private static final Integer INTEGER_ONE = Integer.valueOf(1);
-
private static final List> DEFAULT_CODECS = InternalArrays.asImmutableList(
ByteCodec.INSTANCE,
ShortCodec.INSTANCE,
@@ -369,18 +367,22 @@ private static Class> chooseClass(final MySqlReadableMetadata metadata, Class<
return type.isAssignableFrom(javaType) ? javaType : type;
}
- private static Class> getDefaultJavaType(final MySqlReadableMetadata metadata, final CodecContext codecContext) {
- final MySqlType type = metadata.getType();
- final Integer precision = metadata.getPrecision();
- if (INTEGER_ONE.equals(precision) && (type == MySqlType.TINYINT || type == MySqlType.TINYINT_UNSIGNED)
- && codecContext.isTinyInt1isBit()) {
- return Boolean.class;
+ private static boolean shouldBeTreatedAsBoolean(final @Nullable Integer precision, final MySqlType type,
+ final CodecContext context) {
+ if (precision == null || precision != 1) {
+ return false;
}
-
// ref: https://github.com/asyncer-io/r2dbc-mysql/issues/277
// BIT(1) should be treated as Boolean by default.
- if (INTEGER_ONE.equals(precision) && type == MySqlType.BIT) {
+ return type == MySqlType.BIT || type == MySqlType.TINYINT && context.isTinyInt1isBit();
+ }
+
+ private static Class> getDefaultJavaType(final MySqlReadableMetadata metadata, final CodecContext codecContext) {
+ final MySqlType type = metadata.getType();
+ final Integer precision = metadata.getPrecision();
+
+ if (shouldBeTreatedAsBoolean(precision, type, codecContext)) {
return Boolean.class;
}
diff --git a/r2dbc-mysql/src/test/java/io/asyncer/r2dbc/mysql/ConnectionIntegrationTest.java b/r2dbc-mysql/src/test/java/io/asyncer/r2dbc/mysql/ConnectionIntegrationTest.java
index fccd38530..4e4fa34ae 100644
--- a/r2dbc-mysql/src/test/java/io/asyncer/r2dbc/mysql/ConnectionIntegrationTest.java
+++ b/r2dbc-mysql/src/test/java/io/asyncer/r2dbc/mysql/ConnectionIntegrationTest.java
@@ -592,6 +592,19 @@ public void tinyInt1isBitTrueTestValue1() {
);
}
+ @Test
+ public void tinyInt1isBitTrueTestUnsignedTinyInt1isNotBoolean() {
+ complete(connection -> Mono.from(connection.createStatement("CREATE TEMPORARY TABLE `test` (`id` INT NOT NULL PRIMARY KEY, `value` TINYINT(1) UNSIGNED)").execute())
+ .flatMap(IntegrationTestSupport::extractRowsUpdated)
+ .thenMany(connection.createStatement("INSERT INTO `test` VALUES (1, 1)").execute())
+ .flatMap(IntegrationTestSupport::extractRowsUpdated)
+ .thenMany(connection.createStatement("SELECT `value` FROM `test`").execute())
+ .flatMap(result -> result.map((row, metadata) -> row.get("value", Object.class)))
+ .doOnNext(value -> assertThat(value).isInstanceOf(Short.class))
+ .doOnNext(value -> assertThat(value).isEqualTo(Short.valueOf((short)1)))
+ );
+ }
+
@Test
public void tinyInt1isBitTrueTestValue0() {
complete(connection -> Mono.from(connection.createStatement("CREATE TEMPORARY TABLE `test` (`id` INT NOT NULL PRIMARY KEY, `value` TINYINT(1))").execute())