You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mt...@apache.org on 2009/04/05 14:07:49 UTC

svn commit: r762073 - /openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java

Author: mtylenda
Date: Sun Apr  5 12:07:49 2009
New Revision: 762073

URL: http://svn.apache.org/viewvc?rev=762073&view=rev
Log:
OPENJPA-723: Feature request for PostgreSQL XML Column Mapping

Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java?rev=762073&r1=762072&r2=762073&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java Sun Apr  5 12:07:49 2009
@@ -22,6 +22,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -38,10 +39,12 @@
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.Sequence;
 import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.lib.jdbc.DelegatingConnection;
 import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement;
 import org.apache.openjpa.lib.util.ConcreteClassGenerator;
 import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.StoreException;
 import org.postgresql.PGConnection;
@@ -151,7 +154,6 @@
         clobTypeName = "TEXT";
         longVarcharTypeName = "TEXT";
         doubleTypeName = "DOUBLE PRECISION";
-        varcharTypeName = "VARCHAR{0}";
         timestampTypeName = "ABSTIME";
         fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
             "BOOL", "BYTEA", "NAME", "INT8", "INT2", "INT2VECTOR", "INT4",
@@ -258,10 +260,18 @@
         stmnt.setBoolean(idx, val);
     }
 
+    /**
+     * Handle XML and bytea/oid columns in a PostgreSQL way.
+     */
     public void setNull(PreparedStatement stmnt, int idx, int colType,
         Column col)
         throws SQLException {
-        // OPENJPA-
+        if (col != null && col.isXML()) {
+            stmnt.setNull(idx, Types.OTHER);
+            return;
+        }
+
+        // OPENJPA-308
         if (colType == Types.BLOB)
             colType = Types.BINARY;
         stmnt.setNull(idx, colType);
@@ -381,8 +391,8 @@
                 conn.setAutoCommit(false);
                 PGConnection pgconn = (PGConnection)conn.getInnermostDelegate();
                 LargeObjectManager lom = pgconn.getLargeObjectAPI();
-                // The create method is valid in versions previous 8.3
-                // in 8.3 this methos is deprecated, use createLO
+                // The create method is valid in versions previous to 8.3
+                // in 8.3 this method is deprecated, use createLO
                 int oid = lom.create();
                 LargeObject lo = lom.open(oid, LargeObjectManager.WRITE);
                 OutputStream os = lo.getOutputStream();
@@ -495,8 +505,98 @@
                 try { conn.close (); } catch (SQLException e) {}
         }
     }
+
+    /**
+     * Determine whether XML column is supported.
+     */
+    public void connectedConfiguration(Connection conn) throws SQLException {
+        super.connectedConfiguration(conn);
+        
+        DatabaseMetaData metaData = conn.getMetaData();
+        int maj = 0;
+        int min = 0;
+        if (isJDBC3) {
+            maj = metaData.getDatabaseMajorVersion();
+            min = metaData.getDatabaseMinorVersion();
+        } else {
+            try {
+                // The product version looks like "8.3.5".
+                String productVersion = metaData.getDatabaseProductVersion();
+                String majMin[] = productVersion.split("\\.");
+                maj = Integer.parseInt(majMin[0]);
+                min = Integer.parseInt(majMin[1]);
+            } catch (Exception e) {
+                // We don't understand the version format.
+                if (log.isWarnEnabled())
+                    log.warn(e.toString(),e);
+            }
+        }
+        
+        if ((maj >= 9 || (maj == 8 && min >= 3))) {
+            supportsXMLColumn = true;
+        }
+    }
+ 
+    /**
+     * If column is an XML column, PostgreSQL requires that its value is set
+     * by using {@link PreparedStatement#setObject(int, Object, int)}
+     * with {@link Types#OTHER} as the third argument.
+     */
+    public void setClobString(PreparedStatement stmnt, int idx, String val,
+        Column col) throws SQLException {
+        if (col != null && col.isXML())
+            stmnt.setObject(idx, val, Types.OTHER);
+        else
+            super.setClobString(stmnt, idx, val, col);
+    }
+
+    /**
+     * Append XML comparison.
+     * 
+     * @param buf the SQL buffer to write the comparison
+     * @param op the comparison operation to perform
+     * @param lhs the left hand side of the comparison
+     * @param rhs the right hand side of the comparison
+     * @param lhsxml indicates whether the left operand maps to XML
+     * @param rhsxml indicates whether the right operand maps to XML
+     */
+    public void appendXmlComparison(SQLBuffer buf, String op, FilterValue lhs,
+        FilterValue rhs, boolean lhsxml, boolean rhsxml) {
+        super.appendXmlComparison(buf, op, lhs, rhs, lhsxml, rhsxml);
+        if (lhsxml)
+            appendXmlValue(buf, lhs);
+        else
+            lhs.appendTo(buf);
+        buf.append(" ").append(op).append(" ");
+        if (rhsxml)
+            appendXmlValue(buf, rhs);
+        else
+            rhs.appendTo(buf);
+    }
     
     /**
+     * Append XML column value so that it can be used in comparisons.
+     * 
+     * @param buf the SQL buffer to write the value
+     * @param val the value to be written
+     */
+    private void appendXmlValue(SQLBuffer buf, FilterValue val) {
+        Class rc = Filters.wrap(val.getType());
+        int type = getJDBCType(JavaTypes.getTypeCode(rc), false);
+        boolean isXmlAttribute = (val.getXmlMapping() == null) ? false
+                : val.getXmlMapping().isXmlAttribute();
+        SQLBuffer newBufer = new SQLBuffer(this);
+        newBufer.append("(xpath('/*/");
+        val.appendTo(newBufer);
+        if (!isXmlAttribute)
+            newBufer.append("/text()");
+        newBufer.append("',").
+            append(val.getColumnAlias(val.getFieldMapping().getColumns()[0])).
+            append("))[1]");
+        appendCast(buf, newBufer, type);
+    }
+
+    /**
      * Connection wrapper to work around the postgres empty result set bug.
      */
     protected abstract static class PostgresConnection
@@ -557,7 +657,7 @@
                 ResultSet rs = getResultSet(wrap);
 
                 // ResultSet should be empty: if not, then maybe an
-                // actual error occured
+                // actual error occurred
                 if (rs == null)
                     throw se;