diff --git a/pgjdbc/src/main/java/org/postgresql/PGProperty.java b/pgjdbc/src/main/java/org/postgresql/PGProperty.java
index 5f2e216..2e56833 100644
--- a/pgjdbc/src/main/java/org/postgresql/PGProperty.java
+++ b/pgjdbc/src/main/java/org/postgresql/PGProperty.java
@@ -128,6 +128,12 @@ public enum PGProperty {
DEFAULT_ROW_FETCH_SIZE("defaultRowFetchSize", "0",
"Positive number of rows that should be fetched from the database when more rows are needed for ResultSet by each fetch iteration"),
+ /**
+ * Use binary format for sending and receiving data if possible.
+ */
+ BIT_TO_STRING("bitToString", "false",
+ "Auto Convert bit or bit(n) to String type in ResultSet.getObject"),
+
/**
* Use binary format for sending and receiving data if possible.
*/
diff --git a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java
index df672cd..29b43f1 100644
--- a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java
@@ -29,6 +29,12 @@ public interface BaseConnection extends PGConnection, Connection {
*/
ClientLogic getClientLogic();
+ /**
+ * True if bit convert to string type else to boolean type, default is false.
+ * @return
+ */
+ boolean getBitToString();
+
/**
* Cancel the current query executing on this connection.
*
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/BooleanTypeUtil.java b/pgjdbc/src/main/java/org/postgresql/jdbc/BooleanTypeUtil.java
index 87cfbbf..7e56025 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/BooleanTypeUtil.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/BooleanTypeUtil.java
@@ -11,6 +11,10 @@ import org.postgresql.util.PSQLState;
import org.postgresql.log.Logger;
import org.postgresql.log.Log;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
/**
*
Helper class to handle boolean type of PostgreSQL.
@@ -21,6 +25,8 @@ import org.postgresql.log.Log;
class BooleanTypeUtil {
private static Log LOGGER = Logger.getLogger(BooleanTypeUtil.class.getName());
+ private static final Set TRUE_SETS = Arrays.stream(new String[]{"1", "true", "t", "yes", "y", "on"}).collect(Collectors.toSet());
+ private static final Set FALSE_SETS = Arrays.stream(new String[]{"0", "false", "f", "no", "n", "off"}).collect(Collectors.toSet());
private BooleanTypeUtil() {
}
@@ -54,19 +60,24 @@ class BooleanTypeUtil {
private static boolean fromString(final String strval) throws PSQLException {
// Leading or trailing whitespace is ignored, and case does not matter.
final String val = strval.trim();
- if ("1".equals(val) || "true".equalsIgnoreCase(val)
- || "t".equalsIgnoreCase(val) || "yes".equalsIgnoreCase(val)
- || "y".equalsIgnoreCase(val) || "on".equalsIgnoreCase(val)) {
+ if (isTrueStr(val)) {
return true;
}
- if ("0".equals(val) || "false".equalsIgnoreCase(val)
- || "f".equalsIgnoreCase(val) || "no".equalsIgnoreCase(val)
- || "n".equalsIgnoreCase(val) || "off".equalsIgnoreCase(val)) {
+ if (isFalseStr(val)) {
return false;
}
throw cannotCoerceException(strval);
}
+ private static boolean isTrueStr(final String strval) {
+ return TRUE_SETS.contains(strval.toLowerCase());
+ }
+
+ private static boolean isFalseStr(final String strval) {
+ return FALSE_SETS.contains(strval.toLowerCase());
+ }
+
+
private static boolean fromCharacter(final Character charval) throws PSQLException {
if ('1' == charval || 't' == charval || 'T' == charval
|| 'y' == charval || 'Y' == charval) {
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
index e2f77a6..7056343 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
@@ -77,10 +77,7 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.io.File;
-import java.io.InputStream;
import java.net.URISyntaxException;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
import org.postgresql.core.types.PGClob;
import org.postgresql.core.types.PGBlob;
@@ -166,6 +163,9 @@ public class PgConnection implements BaseConnection {
// Current warnings; there might be more on queryExecutor too.
private SQLWarning firstWarning = null;
+ // True if bit to string else bit to boolean.
+ private boolean bitToString = false;
+
// Timer for scheduling TimerTasks for this connection.
// Only instantiated if a task is actually scheduled.
private volatile Timer cancelTimer = null;
@@ -244,6 +244,7 @@ public class PgConnection implements BaseConnection {
this.creatingURL = url;
+ bitToString = PGProperty.BIT_TO_STRING.getBoolean(info);
setDefaultFetchSize(PGProperty.DEFAULT_ROW_FETCH_SIZE.getInt(info));
setPrepareThreshold(PGProperty.PREPARE_THRESHOLD.getInt(info));
@@ -1276,6 +1277,11 @@ public class PgConnection implements BaseConnection {
}
}
+ @Override
+ public boolean getBitToString() {
+ return bitToString;
+ }
+
public int getPrepareThreshold() {
return prepareThreshold;
}
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
index 62b4ca7..ec22500 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java
@@ -234,6 +234,11 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
}
}
+ public void setBit(int parameterIndex, boolean x) throws SQLException {
+ checkClosed();
+ bindString(parameterIndex, x ? "1" : "0", Oid.BIT);
+ }
+
public void setByte(int parameterIndex, byte x) throws SQLException {
setShort(parameterIndex, x);
}
@@ -632,9 +637,11 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
}
break;
case Types.BOOLEAN:
- case Types.BIT:
setBoolean(parameterIndex, BooleanTypeUtil.castToBoolean(in));
break;
+ case Types.BIT:
+ setBit(parameterIndex, BooleanTypeUtil.castToBoolean(in));
+ break;
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
index 5990176..382dd8c 100644
--- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgResultSet.java
@@ -27,8 +27,6 @@ import org.postgresql.util.PGobject;
import org.postgresql.util.PGtokenizer;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
-import org.postgresql.log.Logger;
-import org.postgresql.log.Log;
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
@@ -241,8 +239,9 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
protected Object internalGetObject(int columnIndex, Field field) throws SQLException {
switch (getSQLType(columnIndex)) {
case Types.BOOLEAN:
- case Types.BIT:
return getBoolean(columnIndex);
+ case Types.BIT:
+ return getBit(columnIndex);
case Types.SQLXML:
return getSQLXML(columnIndex);
case Types.TINYINT:
@@ -2093,6 +2092,20 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
return BooleanTypeUtil.castToBoolean(getString(columnIndex));
}
+ public Object getBit(int columnIndex) throws SQLException {
+ connection.getLogger().trace("[" + connection.getSocketAddress() + "] " + " getBit columnIndex: " + columnIndex);
+ checkResultSet(columnIndex);
+ if (wasNullFlag) {
+ return null; // SQL NULL
+ }
+
+ String val = getString(columnIndex);
+ if (connection.getBitToString()) {
+ return val;
+ }
+ return BooleanTypeUtil.castToBoolean(val);
+ }
+
private static final BigInteger BYTEMAX = new BigInteger(Byte.toString(Byte.MAX_VALUE));
private static final BigInteger BYTEMIN = new BigInteger(Byte.toString(Byte.MIN_VALUE));
diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetBitNTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetBitNTest.java
new file mode 100644
index 0000000..5ec8158
--- /dev/null
+++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc2/ResultSetBitNTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004, PostgreSQL Global Development Group
+ * See the LICENSE file in the project root for more information.
+ */
+
+package org.postgresql.test.jdbc2;
+
+import org.junit.Test;
+import org.postgresql.test.TestUtil;
+import org.postgresql.util.PGobject;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/*
+ * ResultSet tests.
+ */
+public class ResultSetBitNTest extends BaseTest4 {
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ TestUtil.createTable(con, "test_bit", "id bit, id1 bit(1), id2 bit(10)");
+ String insertOne = "insert into test_bit (id, id1, id2) values ('1', b'0', b'1111100000')";
+ try (Statement stmt = con.createStatement()) {
+ stmt.executeUpdate(insertOne);
+ }
+ }
+
+ @Override
+ public void tearDown() throws SQLException {
+ TestUtil.dropTable(con, "test_bit");
+ super.tearDown();
+ }
+
+ @Override
+ protected void updateProperties(Properties props) {
+ super.updateProperties(props);
+ props.setProperty("loggerLevel", "TRACE");
+ props.setProperty("bitToString", "true");
+ }
+
+ @Test
+ public void testInsertDirectly() throws SQLException {
+ String insertSql = "insert into test_bit (id, id1, id2) values ('1', b'0', b'1111100000')";
+ try (Statement st = con.createStatement()) {
+ int number = st.executeUpdate(insertSql);
+ assertEquals(1, number);
+ }
+ }
+
+ @Test
+ public void testInsertByPreparedStatementObj() throws SQLException {
+ String insertSql = "insert into test_bit (id, id1, id2) values (?::bit, ?::bit, ?)";
+ try (PreparedStatement ps = con.prepareStatement(insertSql)) {
+ ps.setObject(1, "1");
+ ps.setObject(2, "0");
+ PGobject pObj = new PGobject();
+ pObj.setType("bit");
+ pObj.setValue("1010111111");
+ ps.setObject(3, pObj);
+ boolean success = ps.execute();
+ assertFalse(success);
+ int num = ps.getUpdateCount();
+ assertEquals(1, num);
+ }
+ }
+
+ @Test
+ public void testInsertByPreparedStatementString() throws SQLException {
+ String insertSql = "insert into test_bit (id, id1, id2) values (?::bit,?::bit,?)";
+ try (PreparedStatement ps = con.prepareStatement(insertSql)) {
+ ps.setString(1, "1");
+ ps.setString(2, "0");
+ PGobject pObj = new PGobject();
+ pObj.setType("bit");
+ pObj.setValue("1010111111");
+ ps.setObject(3, pObj);
+ boolean success = ps.execute();
+ assertFalse(success);
+ int num = ps.getUpdateCount();
+ assertEquals(1, num);
+ }
+ }
+
+ @Test
+ public void testSelectDirectly() throws SQLException {
+ String sql = "select id, id1, id2 from test_bit";
+ try (Statement st = con.createStatement()) {
+ try (ResultSet rs = st.executeQuery(sql)) {
+ assertTrue(rs.next());
+ Object obj = rs.getObject(1);
+ assertEquals("1", obj);
+ Object obj1 = rs.getObject(2);
+ assertEquals("0", obj1);
+ Object obj2 = rs.getObject(3);
+ assertEquals("1111100000", obj2);
+ }
+ }
+ }
+}