add bitToString info property to solve bit type use issue

This commit is contained in:
justbk
2022-05-17 20:21:24 +08:00
committed by justbk2015
parent 5b73c0af0b
commit 5383ada7fd
7 changed files with 169 additions and 13 deletions

View File

@ -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.
*/

View File

@ -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.
*

View File

@ -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;
/**
* <p>Helper class to handle boolean type of PostgreSQL.</p>
@ -21,6 +25,8 @@ import org.postgresql.log.Log;
class BooleanTypeUtil {
private static Log LOGGER = Logger.getLogger(BooleanTypeUtil.class.getName());
private static final Set<String> TRUE_SETS = Arrays.stream(new String[]{"1", "true", "t", "yes", "y", "on"}).collect(Collectors.toSet());
private static final Set<String> 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) {

View File

@ -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;
}

View File

@ -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:

View File

@ -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));

View File

@ -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);
}
}
}
}