postgresql-jdbc.git / summary / log / commit / refs

commit    70021888f453fed8aae66ea8ac0818277f37440e
Author:   Dave Cramer <davecramer@gmail.com>
Date:     Wed May 16 00:35:51 2012 +0000

    rest of Add hstore patch


.../test/extensions/ExtensionsSuite.java | 60 +++++++++ org/postgresql/test/extensions/HStoreTest.java | 79 ++++++++++++ org/postgresql/util/HStoreConverter.java | 140 +++++++++++++++++++++ 3 files changed, 279 insertions(+) diff --git a/org/postgresql/test/extensions/ExtensionsSuite.java b/org/postgresql/test/extensions/ExtensionsSuite.java new file mode 100644 index 00000000..0b8e4a1c --- /dev/null +++ b/org/postgresql/test/extensions/ExtensionsSuite.java @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2007-2011, PostgreSQL Global Development Group +* +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.test.extensions; + +import junit.framework.TestSuite; + +import java.sql.*; +import org.postgresql.test.TestUtil; + +/* + * Executes all known tests for PostgreSQL extensions supported by JDBC driver + */ +public class ExtensionsSuite extends TestSuite +{ + + /* + * The main entry point for JUnit + */ + public static TestSuite suite() throws Exception + { + Class.forName("org.postgresql.Driver"); + TestSuite suite = new TestSuite(); + + Connection connection = TestUtil.openDB(); + try + { + if (isHStoreEnabled(connection)) { + suite.addTestSuite(HStoreTest.class); + } + } + finally + { + connection.close(); + } + + return suite; + } + + /** + * Not all servers have hstore extensions installed. + */ + private static boolean isHStoreEnabled(Connection conn) { + try { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT 'a=>1'::hstore::text"); + rs.close(); + stmt.close(); + return true; + } catch (SQLException sqle) { + return false; + } + } + +} + diff --git a/org/postgresql/test/extensions/HStoreTest.java b/org/postgresql/test/extensions/HStoreTest.java new file mode 100644 index 00000000..3f1567cf --- /dev/null +++ b/org/postgresql/test/extensions/HStoreTest.java @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2007-2011, PostgreSQL Global Development Group +* +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.test.extensions; + +import java.sql.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; +import org.postgresql.test.TestUtil; + +// SELECT 'hstore'::regtype::oid +// SELECT 'hstore[]'::regtype::oid + +public class HStoreTest extends TestCase { + + private Connection _conn; + + public HStoreTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + _conn = TestUtil.openDB(); + } + + protected void tearDown() throws SQLException { + TestUtil.closeDB(_conn); + } + + public void testHStoreSelect() throws SQLException { + PreparedStatement pstmt = _conn.prepareStatement("SELECT 'a=>1,b=>2'::hstore"); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + String str = rs.getString(1); + if (!("\"a\"=>\"1\", \"b\"=>\"2\"".equals(str) || "\"b\"=>\"2\", \"a\"=>\"1\"".equals(str))) { + fail("Expected " + "\"a\"=>\"1\", \"b\"=>\"2\"" + " but got " + str); + } + Map correct = new HashMap(); + correct.put("a", "1"); + correct.put("b", "2"); + assertEquals(correct, rs.getObject(1)); + } + + public void testHStoreSelectNullValue() throws SQLException { + PreparedStatement pstmt = _conn.prepareStatement("SELECT 'a=>NULL'::hstore"); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals("\"a\"=>NULL", rs.getString(1)); + Map correct = Collections.singletonMap("a", null); + assertEquals(correct, rs.getObject(1)); + } + + public void testHStoreSend() throws SQLException { + Map correct = Collections.singletonMap("a", new Integer(1)); + PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::text"); + pstmt.setObject(1, correct); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals("\"a\"=>\"1\"", rs.getString(1)); + } + + public void testHStoreSendEscaped() throws SQLException { + Map correct = Collections.singletonMap("a", "t'e\ns\"t"); + PreparedStatement pstmt = _conn.prepareStatement("SELECT ?"); + pstmt.setObject(1, correct); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(correct, rs.getObject(1)); + assertEquals("\"a\"=>\"t'e\ns\\\"t\"", rs.getString(1)); + } + +} diff --git a/org/postgresql/util/HStoreConverter.java b/org/postgresql/util/HStoreConverter.java new file mode 100644 index 00000000..099d871f --- /dev/null +++ b/org/postgresql/util/HStoreConverter.java @@ -0,0 +1,140 @@ +package org.postgresql.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.postgresql.core.Encoding; + +public class HStoreConverter { + public static Map fromBytes(byte[] b, Encoding encoding) throws SQLException { + Map m = new HashMap(); + int pos = 0; + int numElements = ByteConverter.int4(b, pos); pos+=4; + try { + for (int i = 0; i < numElements; ++i) { + int keyLen = ByteConverter.int4(b, pos); pos += 4; + String key = encoding.decode(b, pos, keyLen); pos += keyLen; + int valLen = ByteConverter.int4(b, pos); pos += 4; + String val; + if (valLen == -1) { + val = null; + } else { + val = encoding.decode(b, pos, valLen); pos += valLen; + } + m.put(key, val); + } + } + catch (IOException ioe) + { + throw new PSQLException(GT.tr("Invalid character data was found. This is most likely caused by stored data containing characters that are invalid for the character set the database was created in. The most common example of this is storing 8bit data in a SQL_ASCII database."), PSQLState.DATA_ERROR, ioe); + } + return m; + } + + public static byte[] toBytes(Map m, Encoding encoding) throws SQLException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(4 + 10 * m.size()); + byte[] lenBuf = new byte[4]; + try { + ByteConverter.int4(lenBuf, 0, m.size()); baos.write(lenBuf); + for (Iterator i = m.entrySet().iterator(); i.hasNext(); ) { + Entry e = (Entry) i.next(); + byte[] key = encoding.encode(e.getKey().toString()); + ByteConverter.int4(lenBuf, 0, key.length); baos.write(lenBuf); + baos.write(key); + + if (e.getValue() == null) { + ByteConverter.int4(lenBuf, 0, -1); baos.write(lenBuf); + } else { + byte[] val = encoding.encode(e.getValue().toString()); + ByteConverter.int4(lenBuf, 0, val.length); baos.write(lenBuf); + baos.write(val); + } + } + } + catch (IOException ioe) + { + throw new PSQLException(GT.tr("Invalid character data was found. This is most likely caused by stored data containing characters that are invalid for the character set the database was created in. The most common example of this is storing 8bit data in a SQL_ASCII database."), PSQLState.DATA_ERROR, ioe); + } + return baos.toByteArray(); + } + + public static String toString(Map map) throws SQLException { + if (map.isEmpty()) { + return ""; + } + StringBuffer sb = new StringBuffer(map.size() * 8); + for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) { + Entry e = (Entry) i.next(); + appendEscaped(sb, e.getKey()); + sb.append("=>"); + appendEscaped(sb, e.getValue()); + sb.append(", "); + } + sb.setLength(sb.length() - 2); + return sb.toString(); + } + + private static void appendEscaped(StringBuffer sb, Object val) throws SQLException { + if (val != null) { + sb.append('"'); + String s = val.toString(); + for (int pos = 0; pos < s.length(); pos++) { + char ch = s.charAt(pos); + if (ch == '"' || ch == '\\') { + sb.append('\\'); + } + sb.append(ch); + } + sb.append('"'); + } else { + sb.append("NULL"); + } + } + + public static Map fromString(String s) { + Map m = new HashMap(); + int pos = 0; + StringBuffer sb = new StringBuffer(); + while (pos < s.length()) { + sb.setLength(0); + int start = s.indexOf('"', pos); + int end = appendUntilQuote(sb, s, start); + String key = sb.toString(); + pos = end + 3; + + String val; + if (s.charAt(pos) == 'N') { + val = null; + pos += 4; + } else { + sb.setLength(0); + end = appendUntilQuote(sb, s, pos); + val = sb.toString(); + pos = end; + } + pos++; + m.put(key, val); + } + return m; + } + + private static int appendUntilQuote(StringBuffer sb, String s, int pos) { + for (pos += 1; pos < s.length(); pos++) { + char ch = s.charAt(pos); + if (ch == '"') { + break; + } + if (ch == '\\') { + pos++; + ch = s.charAt(pos); + } + sb.append(ch); + } + return pos; + } +} \ No newline at end of file [parent: d90e278bbf77]