/* * 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.postgresql.test.TestUtil; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @RunWith(Parameterized.class) public class QuotationTest extends BaseTest4 { private enum QuoteStyle { SIMPLE("'"), DOLLAR_NOTAG("$$"), DOLLAR_A("$a$"), DOLLAR_DEF("$DEF$"); private final String quote; QuoteStyle(String quote) { this.quote = quote; } @Override public String toString() { return quote; } } private final String expr; private final String expected; public QuotationTest(QuoteStyle quoteStyle, String expected, String expr) { this.expected = expected; this.expr = expr; } @Parameterized.Parameters(name = "{index}: quotes(style={0}, src={1}, quoted={2})") public static Iterable<Object[]> data() { Collection<String> prefix = new ArrayList<String>(); // Too many prefixes make test run long prefix.add(""); prefix.add("/*\n$\n*//* ? *//*{fn *//* now} */"); prefix.add("-- $\n"); prefix.add("--\n/* $ */"); Collection<Object[]> ids = new ArrayList<Object[]>(); Collection<String> garbageValues = new ArrayList<String>(); garbageValues.add("{fn now}"); garbageValues.add("{extract}"); garbageValues.add("{select}"); garbageValues.add("?select"); garbageValues.add("select?"); garbageValues.add("??select"); garbageValues.add("}{"); garbageValues.add("{"); garbageValues.add("}"); garbageValues.add("--"); garbageValues.add("/*"); garbageValues.add("*/"); for (QuoteStyle quoteStyle : QuoteStyle.values()) { garbageValues.add(quoteStyle.toString()); } for (char ch = 'a'; ch <= 'z'; ch++) { garbageValues.add(Character.toString(ch)); } for (QuoteStyle quoteStyle : QuoteStyle.values()) { for (String garbage : garbageValues) { String unquoted = garbage; for (int i = 0; i < 3; i++) { String quoted = unquoted; if (quoteStyle == QuoteStyle.SIMPLE) { quoted = quoted.replaceAll("'", "''"); } quoted = quoteStyle.toString() + quoted + quoteStyle.toString(); if (quoted.endsWith("$$$") && quoteStyle == QuoteStyle.DOLLAR_NOTAG) { // $$$a$$$ is parsed like $$ $a $$ $ -> thus we skip this test continue; } if (quoteStyle != QuoteStyle.SIMPLE && garbage.equals(quoteStyle.toString())) { // $a$$a$$a$ is not valid continue; } String expected = unquoted; for (String p : prefix) { ids.add(new Object[]{quoteStyle, expected, p + quoted}); } if (unquoted.length() == 1) { char ch = unquoted.charAt(0); if (ch >= 'a' && ch <= 'z') { // Will assume if 'a' works, then 'aa', 'aaa' will also work break; } } unquoted += garbage; } } } return ids; } @Test public void quotedString() throws SQLException { PreparedStatement ps = con.prepareStatement("select " + expr); try { ResultSet rs = ps.executeQuery(); rs.next(); String val = rs.getString(1); Assert.assertEquals(expected, val); } catch (SQLException e) { TestUtil.closeQuietly(ps); } } @Test public void bindInTheMiddle() throws SQLException { PreparedStatement ps = con.prepareStatement("select " + expr + ", ?, " + expr); try { ps.setInt(1, 42); ResultSet rs = ps.executeQuery(); rs.next(); String val1 = rs.getString(1); String val3 = rs.getString(3); Assert.assertEquals(expected, val1); Assert.assertEquals(expected, val3); } catch (SQLException e) { TestUtil.closeQuietly(ps); } } }