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", 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"), "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. * Use binary format for sending and receiving data if possible.
*/ */

View File

@ -29,6 +29,12 @@ public interface BaseConnection extends PGConnection, Connection {
*/ */
ClientLogic getClientLogic(); 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. * 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.Logger;
import org.postgresql.log.Log; 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> * <p>Helper class to handle boolean type of PostgreSQL.</p>
@ -21,6 +25,8 @@ import org.postgresql.log.Log;
class BooleanTypeUtil { class BooleanTypeUtil {
private static Log LOGGER = Logger.getLogger(BooleanTypeUtil.class.getName()); 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() { private BooleanTypeUtil() {
} }
@ -54,19 +60,24 @@ class BooleanTypeUtil {
private static boolean fromString(final String strval) throws PSQLException { private static boolean fromString(final String strval) throws PSQLException {
// Leading or trailing whitespace is ignored, and case does not matter. // Leading or trailing whitespace is ignored, and case does not matter.
final String val = strval.trim(); final String val = strval.trim();
if ("1".equals(val) || "true".equalsIgnoreCase(val) if (isTrueStr(val)) {
|| "t".equalsIgnoreCase(val) || "yes".equalsIgnoreCase(val)
|| "y".equalsIgnoreCase(val) || "on".equalsIgnoreCase(val)) {
return true; return true;
} }
if ("0".equals(val) || "false".equalsIgnoreCase(val) if (isFalseStr(val)) {
|| "f".equalsIgnoreCase(val) || "no".equalsIgnoreCase(val)
|| "n".equalsIgnoreCase(val) || "off".equalsIgnoreCase(val)) {
return false; return false;
} }
throw cannotCoerceException(strval); 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 { private static boolean fromCharacter(final Character charval) throws PSQLException {
if ('1' == charval || 't' == charval || 'T' == charval if ('1' == charval || 't' == charval || 'T' == charval
|| 'y' == charval || 'Y' == charval) { || 'y' == charval || 'Y' == charval) {

View File

@ -77,10 +77,7 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.io.File; import java.io.File;
import java.io.InputStream;
import java.net.URISyntaxException; 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.PGClob;
import org.postgresql.core.types.PGBlob; import org.postgresql.core.types.PGBlob;
@ -166,6 +163,9 @@ public class PgConnection implements BaseConnection {
// Current warnings; there might be more on queryExecutor too. // Current warnings; there might be more on queryExecutor too.
private SQLWarning firstWarning = null; private SQLWarning firstWarning = null;
// True if bit to string else bit to boolean.
private boolean bitToString = false;
// Timer for scheduling TimerTasks for this connection. // Timer for scheduling TimerTasks for this connection.
// Only instantiated if a task is actually scheduled. // Only instantiated if a task is actually scheduled.
private volatile Timer cancelTimer = null; private volatile Timer cancelTimer = null;
@ -244,6 +244,7 @@ public class PgConnection implements BaseConnection {
this.creatingURL = url; this.creatingURL = url;
bitToString = PGProperty.BIT_TO_STRING.getBoolean(info);
setDefaultFetchSize(PGProperty.DEFAULT_ROW_FETCH_SIZE.getInt(info)); setDefaultFetchSize(PGProperty.DEFAULT_ROW_FETCH_SIZE.getInt(info));
setPrepareThreshold(PGProperty.PREPARE_THRESHOLD.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() { public int getPrepareThreshold() {
return prepareThreshold; 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 { public void setByte(int parameterIndex, byte x) throws SQLException {
setShort(parameterIndex, x); setShort(parameterIndex, x);
} }
@ -632,9 +637,11 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
} }
break; break;
case Types.BOOLEAN: case Types.BOOLEAN:
case Types.BIT:
setBoolean(parameterIndex, BooleanTypeUtil.castToBoolean(in)); setBoolean(parameterIndex, BooleanTypeUtil.castToBoolean(in));
break; break;
case Types.BIT:
setBit(parameterIndex, BooleanTypeUtil.castToBoolean(in));
break;
case Types.BINARY: case Types.BINARY:
case Types.VARBINARY: case Types.VARBINARY:
case Types.LONGVARBINARY: case Types.LONGVARBINARY:

View File

@ -27,8 +27,6 @@ import org.postgresql.util.PGobject;
import org.postgresql.util.PGtokenizer; import org.postgresql.util.PGtokenizer;
import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState; import org.postgresql.util.PSQLState;
import org.postgresql.log.Logger;
import org.postgresql.log.Log;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.CharArrayReader; 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 { protected Object internalGetObject(int columnIndex, Field field) throws SQLException {
switch (getSQLType(columnIndex)) { switch (getSQLType(columnIndex)) {
case Types.BOOLEAN: case Types.BOOLEAN:
case Types.BIT:
return getBoolean(columnIndex); return getBoolean(columnIndex);
case Types.BIT:
return getBit(columnIndex);
case Types.SQLXML: case Types.SQLXML:
return getSQLXML(columnIndex); return getSQLXML(columnIndex);
case Types.TINYINT: case Types.TINYINT:
@ -2093,6 +2092,20 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
return BooleanTypeUtil.castToBoolean(getString(columnIndex)); 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 BYTEMAX = new BigInteger(Byte.toString(Byte.MAX_VALUE));
private static final BigInteger BYTEMIN = new BigInteger(Byte.toString(Byte.MIN_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);
}
}
}
}