Permalink
Browse files

fix: support parenthesis in {oj ...} JDBC escape syntax #865

Non-standard `{oj (...)}` is produced by CrystalReports, so enable that deviation from the spec and ignore the parenthesis.

Note: this basically reverts "strict" part of #657
  • Loading branch information...
AlBundy33 authored and vlsi committed Jun 4, 2018
1 parent b92bd65 commit 38356e6889613a65fc48a455495f18dbb3565731
@@ -1278,6 +1278,7 @@ private static String escapeFunction(String functionName, String args, boolean s
}
private static final char[] QUOTE_OR_ALPHABETIC_MARKER = {'\"', '0'};
private static final char[] QUOTE_OR_ALPHABETIC_MARKER_OR_PARENTHESIS = {'\"', '0', '('};
private static final char[] SINGLE_QUOTE = {'\''};
// Static variables for parsing SQL when replaceProcessing is true.
@@ -1288,7 +1289,7 @@ private static String escapeFunction(String functionName, String args, boolean s
ESC_TIMESTAMP("ts", SINGLE_QUOTE, "TIMESTAMP "),
ESC_FUNCTION("fn", QUOTE_OR_ALPHABETIC_MARKER, null),
ESC_OUTERJOIN("oj", QUOTE_OR_ALPHABETIC_MARKER, null),
ESC_OUTERJOIN("oj", QUOTE_OR_ALPHABETIC_MARKER_OR_PARENTHESIS, null),
ESC_ESCAPECHAR("escape", SINGLE_QUOTE, "ESCAPE ");
private final char[] escapeKeyword;
@@ -22,6 +22,8 @@
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -696,6 +698,34 @@ public static void printResultSet(ResultSet rs) throws SQLException {
}
}
public static List<String> resultSetToLines(ResultSet rs) throws SQLException {
List<String> res = new ArrayList<String>();
ResultSetMetaData rsmd = rs.getMetaData();
StringBuilder sb = new StringBuilder();
while (rs.next()) {
sb.setLength(0);
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
if (i != 1) {
sb.append(',');
}
sb.append(rs.getString(i));
}
res.add(sb.toString());
}
return res;
}
public static String join(List<String> list) {
StringBuilder sb = new StringBuilder();
for (String s : list) {
if (sb.length() > 0) {
sb.append('\n');
}
sb.append(s);
}
return sb.toString();
}
/*
* Find the column for the given label. Only SQLExceptions for system or set-up problems are
* thrown. The PSQLState.UNDEFINED_COLUMN type exception is consumed to allow cleanup. Relying on
@@ -125,7 +125,8 @@
CopyTest.class,
CopyLargeFileTest.class,
ServerErrorTest.class,
UpsertTest.class
UpsertTest.class,
OuterJoinSyntaxTest.class
})
public class Jdbc2TestSuite {
}
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2018, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.test.jdbc2;
import org.postgresql.test.TestUtil;
import org.junit.Assert;
import org.junit.Test;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
/**
* Executes the query with the outer join syntax. The joined tables are encapsulated with parenthesis.
* <b>Note:</b> This queries worked up to driver version 9.4.1211 (postgresql-9.4.1211.jre7.jar).
* Encapsulation with parenthesis is used by third party like CrystalReports.
*/
public class OuterJoinSyntaxTest extends BaseTest4 {
@Test
public void testOuterJoinSyntaxWithSingleJoinAndWithoutOj() throws Exception {
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text"
+ " from (values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id)",
Arrays.asList("1,one,1,a", "2,two,null,null"));
}
@Test
public void testOuterJoinSyntaxWithMultipleJoinsAndWithoutOj() throws Exception {
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text,"
+ " t3.id as t3_id, t3.text as t3_text"
+ " from (values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id)"
+ " left outer join (values (4, '1'), (2, '2')) as t3 (id, text) on (t2.id = t3.id)",
Arrays.asList("1,one,1,a,null,null", "2,two,null,null,null,null"));
}
@Test
public void testOuterJoinSyntaxWithSingleJoinAndWithOj() throws Exception {
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text"
+ " from {oj (values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id) }",
Arrays.asList("1,one,1,a", "2,two,null,null"));
}
@Test
public void testOuterJoinSyntaxWithMultipleJoinsAndWithOj() throws Exception {
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text,"
+ " t3.id as t3_id, t3.text as t3_text"
+ " from {oj (values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id)"
+ " left outer join (values (1, '1'), (2, '2')) as t3 (id, text) on (t2.id = t3.id)}",
Arrays.asList("1,one,1,a,1,1", "2,two,null,null,null,null"));
}
@Test
public void testOuterJoinSyntaxWithMultipleJoinsAndWithOj2() throws Exception {
// multiple joins with oj and missing space character after oj
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text,"
+ " t3.id as t3_id, t3.text as t3_text"
+ " from {oj(values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id)"
+ " left outer join (values (4, '1'), (2, '2')) as t3 (id, text) on (t2.id = t3.id)}",
Arrays.asList("1,one,1,a,null,null", "2,two,null,null,null,null"));
}
@Test
public void testOuterJoinSyntaxWithMultipleJoinsAndWithOj3() throws Exception {
// multiple joins with oj and missing space character after oj and some more parenthesis
testOuterJoinSyntax(
"select t1.id as t1_id, t1.text as t1_text,"
+ " t2.id as t2_id, t2.text as t2_text,"
+ " t3.id as t3_id, t3.text as t3_text"
+ " from {oj(((values (1, 'one'), (2, 'two')) as t1 (id, text)"
+ " left outer join (values (1, 'a'), (3, 'b')) as t2 (id, text) on (t1.id = t2.id))"
+ " left outer join (values (1, '1'), (4, '2')) as t3 (id, text) on (t2.id = t3.id))}",
Arrays.asList("1,one,1,a,1,1", "2,two,null,null,null,null"));
}
/**
* Executes the statement.
*
* @param theQuery the query to execute
* @param expectedResult the expected columns in result set
* @throws Exception on error
*/
private void testOuterJoinSyntax(String theQuery, List<String> expectedResult) throws Exception {
final Statement st = con.createStatement();
try {
final ResultSet rs = st.executeQuery(theQuery);
try {
Assert.assertEquals("SQL " + theQuery, TestUtil.join(TestUtil.resultSetToLines(rs)), TestUtil.join(expectedResult));
} finally {
TestUtil.closeQuietly(rs);
}
} finally {
TestUtil.closeQuietly(st);
}
}
}

0 comments on commit 38356e6

Please sign in to comment.