/*------------------------------------------------------------------------- * * A preliminary version of a custom type wrapper for hstore data. * Once it gets some testing and cleanups it will go into the official * PG JDBC driver, but stick it here for now because we need it sooner. * * Copyright (c) 2009, PostgreSQL Global Development Group * * IDENTIFICATION * $PostgreSQL$ * *------------------------------------------------------------------------- */ package org.postgresql.util; import java.io.Serializable; import java.sql.SQLException; import java.util.Set; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Iterator; import java.util.Collection; /** * This implements a class that handles the PostgreSQL contrib/hstore type */ public class PGHStore extends PGobject implements Serializable, Cloneable, Map { private final static long serialVersionUID = 1; private Map _map; /** * required by the driver */ public PGHStore() { setType("hstore"); _map = new HashMap(); } /** * Initialize a hstore with a given string representation * * @param value String representated hstore * @throws SQLException Is thrown if the string representation has an unknown format * @see #setValue(String) */ public PGHStore(String value) throws SQLException { this(); setValue(value); } public PGHStore(Map map) { this(); setValue(map); } public void setValue(Map map) { _map = map; } /** */ public void setValue(String value) throws SQLException { Parser p = new Parser(); _map = p.parse(value); } /** * Returns the stored information as a string * * @return String represented hstore */ public String getValue() { StringBuffer buf = new StringBuffer(); Iterator i = _map.keySet().iterator(); boolean first = true; while (i.hasNext()) { Object key = i.next(); Object value = _map.get(key); if (first) { first = false; } else { buf.append(','); } writeValue(buf, key); buf.append("=>"); writeValue(buf, value); } return buf.toString(); } private static void writeValue(StringBuffer buf, Object o) { if (o == null) { buf.append("NULL"); return; } String s = o.toString(); buf.append('"'); for (int i=0; i') { state = WVAL; } else if (c == '\0') { throw new SQLException("KJJ, unexpected end of string"); } else { throw new SQLException("KJJ, syntax err [" + c + "] at " + ptr); } } else if (state == WVAL) { if (!getValue(true)) { throw new SQLException("KJJ, unexpected end of string"); } String val = cur.toString(); cur = null; if (!escaped && "null".equalsIgnoreCase(val)) { val = null; } values.add(val); state = WDEL; } else if (state == WDEL) { if (c == ',') { state = WKEY; } else if (c == '\0') { return; } else if (!Character.isWhitespace(c)) { throw new SQLException("KJJ, syntax err"); } } else { throw new SQLException("KJJ unknown state"); } ptr++; } } } // Farm out all the work to the real underlying map. public void clear() { _map.clear(); } public boolean containsKey(Object key) { return _map.containsKey(key); } public boolean containsValue(Object value) { return _map.containsValue(value); } public Set entrySet() { return _map.entrySet(); } public Object get(Object key) { return _map.get(key); } public int hashCode() { return _map.hashCode(); } public boolean isEmpty() { return _map.isEmpty(); } public Set keySet() { return _map.keySet(); } @SuppressWarnings("unchecked") public Object put(Object key, Object value) { return _map.put(key, value); } @SuppressWarnings("unchecked") public void putAll(Map m) { _map.putAll(m); } public Object remove(Object key) { return _map.remove(key); } public int size() { return _map.size(); } public Collection values() { return _map.values(); } }