Skip to content

Commit

Permalink
Fix string based null handling for scalars, records & arrays (#494)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb authored Jun 25, 2020
1 parent ce48841 commit 92b7fd4
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ int[] parseElementBuffers(char delim, CharSequence buffer, List<CharSequence> el
int[] dimensions = new int[0];
int len = buffer.length();
StringBuilder elementText = null;
boolean quoted = false;

int depth = -1;
int charIdx;
Expand All @@ -305,7 +306,8 @@ int[] parseElementBuffers(char delim, CharSequence buffer, List<CharSequence> el
case '}':
if (elementText != null) {
++dimensions[depth];
elementText = addTextElement(elementText, elements);
elementText = addTextElement(elementText, quoted, elements);
quoted = false;
}
if (--depth < 0) {
break scan;
Expand All @@ -318,6 +320,7 @@ int[] parseElementBuffers(char delim, CharSequence buffer, List<CharSequence> el
case '"':
elementText = new StringBuilder();
charIdx = readString(buffer, charIdx, elementText);
quoted = true;
break;

case '[':
Expand All @@ -337,7 +340,8 @@ int[] parseElementBuffers(char delim, CharSequence buffer, List<CharSequence> el
if (ch == delim) {
if (elementText != null) {
++dimensions[depth];
elementText = addTextElement(elementText, elements);
elementText = addTextElement(elementText, quoted, elements);
quoted = false;
}
break;
}
Expand All @@ -353,9 +357,9 @@ int[] parseElementBuffers(char delim, CharSequence buffer, List<CharSequence> el
return dimensions;
}

StringBuilder addTextElement(StringBuilder text, List<CharSequence> elements) {
StringBuilder addTextElement(StringBuilder text, boolean quoted, List<CharSequence> elements) {
String textStr = text.toString();
if (textStr.equalsIgnoreCase("NULL")) {
if (!quoted && textStr.equalsIgnoreCase("NULL")) {
elements.add(null);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,6 @@ public Object decode(Context context, Type type, Short typeLength, Integer typeM

targetClass = targetClass != null ? targetClass : getDefaultClass();

if (buffer.length() == 4 && buffer.toString().equalsIgnoreCase("NULL")) {
return null;
}

try {
return decodeValue(context, type, typeLength, typeModifier, buffer, targetClass, targetContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,7 @@ StringBuilder addTextElement(StringBuilder text, boolean empty, List<CharSequenc
attributes.add(null);
}
else {
String textStr = text.toString();
if (textStr.equalsIgnoreCase("NULL")) {
attributes.add(null);
}
else {
attributes.add(textStr);
}
attributes.add(text.toString());
}
return null;
}
Expand Down
89 changes: 89 additions & 0 deletions driver/src/test/java/com/impossibl/postgres/jdbc/ArrayTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@ public void testGetNull() throws SQLException {
stmt.close();
}

@Test
public void testTextModeGetNull() throws SQLException {
Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery("SELECT null; SELECT 1");
assertTrue(rs.next());
assertNull(rs.getArray(1));
assertNull(rs.getObject(1));
assertArrayEquals(null, rs.getObject(1, Integer[].class));

rs.close();
stmt.close();
}

@Test
public void testSendRecvMultiple() throws SQLException {

Expand Down Expand Up @@ -359,6 +373,81 @@ public void testNullValues() throws SQLException {
stmt.close();
}

@Test
public void testNullValuesTextMode() throws SQLException {

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT ARRAY[1,NULL,3]; SELECT 1");
assertTrue(rs.next());
Array arr = rs.getArray(1);
Integer[] i = (Integer[]) arr.getArray();
assertEquals(3, i.length);
assertEquals(1, i[0].intValue());
assertNull(i[1]);
assertEquals(3, i[2].intValue());
arr.free();
rs.close();
stmt.close();
}

@Test
public void testStringNullValues() throws SQLException {

try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT ARRAY['null',NULL,'null',NULL,'null']");
assertTrue(rs.next());
Array arr = rs.getArray(1);
String[] i = (String[]) arr.getArray();
assertEquals(5, i.length);
assertEquals("null", i[0]);
assertEquals(null, i[1]);
assertEquals("null", i[2]);
assertEquals(null, i[3]);
assertEquals("null", i[4]);
arr.free();
rs.close();
}


try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT ARRAY[NULL,'null',NULL,'null',NULL]");
assertTrue(rs.next());
Array arr = rs.getArray(1);
String[] i = (String[]) arr.getArray();
assertEquals(5, i.length);
assertEquals(null, i[0]);
assertEquals("null", i[1]);
assertEquals(null, i[2]);
assertEquals("null", i[3]);
assertEquals(null, i[4]);
arr.free();
rs.close();
}

try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT ARRAY['null']");
assertTrue(rs.next());
Array arr = rs.getArray(1);
String[] i = (String[]) arr.getArray();
assertEquals(1, i.length);
assertEquals("null", i[0]);
arr.free();
rs.close();
}

try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT ARRAY[null]::varchar[]");
assertTrue(rs.next());
Array arr = rs.getArray(1);
String[] i = (String[]) arr.getArray();
assertEquals(1, i.length);
assertEquals(null, i[0]);
arr.free();
rs.close();
}

}

@Test
public void testUnknownArrayType() throws SQLException {
Statement stmt = conn.createStatement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

Expand Down Expand Up @@ -1010,4 +1011,35 @@ public void testTurkishLocale() throws SQLException {
}
}

@Test
public void testReadStringNull() throws Exception {
try (PreparedStatement pst = con.prepareStatement("INSERT INTO teststring(a) VALUES (?)")) {
pst.setString(1, "null");
pst.executeUpdate();
pst.setString(1, null);
pst.executeUpdate();
}

try (Statement st = con.createStatement()) {
ResultSet rs = st.executeQuery("SELECT a FROM teststring");
assertTrue(rs.next());
assertEquals("12345", rs.getString(1));
assertTrue(rs.next());
assertEquals("null", rs.getString(1));
assertTrue(rs.next());
assertNull(rs.getString(1));
}

// forced into text mode
try (Statement st = con.createStatement()) {
ResultSet rs = st.executeQuery("SELECT a FROM teststring; SELECT 1");
assertTrue(rs.next());
assertEquals("12345", rs.getString(1));
assertTrue(rs.next());
assertEquals("null", rs.getString(1));
assertTrue(rs.next());
assertNull(rs.getString(1));
}
}

}
50 changes: 49 additions & 1 deletion driver/src/test/java/com/impossibl/postgres/jdbc/StructTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public void testConnectionTypeMapFail() throws SQLException {
assertTrue(rs.next());

try {
TestStruct ts2 = (TestStruct) rs.getObject(1);
@SuppressWarnings("unused") TestStruct ts2 = (TestStruct) rs.getObject(1);
Assert.fail("Cast should have failed");
}
catch (ClassCastException e) {
Expand All @@ -288,4 +288,52 @@ public void testConnectionTypeMapFail() throws SQLException {

}

@Test
public void testTextModeNullHandling() throws SQLException {

TestStruct ts = new TestStruct(), ts2;
ts.str = "null";
ts.str2 = null;

PreparedStatement pst = conn.prepareStatement("INSERT INTO struct_test VALUES (?)");
pst.setObject(1, ts);
pst.executeUpdate();
pst.close();

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM struct_test; SELECT 1;");
assertTrue(rs.next());
assertNotNull(ts2 = rs.getObject(1, TestStruct.class));
assertEquals("null", ts2.str);
assertNull(ts2.str2);
assertNull(ts2.id);
assertNull(ts2.num);
rs.close();
st.close();
}

@Test
public void testNullHandling() throws SQLException {

TestStruct ts = new TestStruct(), ts2;
ts.str = "null";
ts.str2 = null;

PreparedStatement pst = conn.prepareStatement("INSERT INTO struct_test VALUES (?)");
pst.setObject(1, ts);
pst.executeUpdate();
pst.close();

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM struct_test;");
assertTrue(rs.next());
assertNotNull(ts2 = rs.getObject(1, TestStruct.class));
assertEquals("null", ts2.str);
assertNull(ts2.str2);
assertNull(ts2.id);
assertNull(ts2.num);
rs.close();
st.close();
}

}

0 comments on commit 92b7fd4

Please sign in to comment.