You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2010/08/18 01:39:23 UTC

svn commit: r986525 - /openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java

Author: faywang
Date: Tue Aug 17 23:39:23 2010
New Revision: 986525

URL: http://svn.apache.org/viewvc?rev=986525&view=rev
Log:
OPENJPA-735: OpenJPA support for SolidDB

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

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java?rev=986525&r1=986524&r2=986525&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SolidDBDictionary.java Tue Aug 17 23:39:23 2010
@@ -18,21 +18,23 @@
  */
 package org.apache.openjpa.jdbc.sql;
 
-import java.sql.Connection;
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.sql.Statement;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
+import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.openjpa.jdbc.identifier.DBIdentifier;
 import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
 import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Index;
 import org.apache.openjpa.jdbc.schema.PrimaryKey;
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.schema.Unique;
 import org.apache.openjpa.lib.util.Localizer;
-import org.apache.openjpa.lib.util.ReferenceHashSet;
+import org.apache.openjpa.meta.JavaTypes;
 
 /**
  * Dictionary for SolidDB database.
@@ -52,14 +54,38 @@ public class SolidDBDictionary
      * The default concurrency control mechanism depends on the table type:
      *    Disk-based tables (D-tables) are by default optimistic.
      *    Main-memory tables (M-tables) are always pessimistic.
+     * Since OpenJPA applications expects lock waits (as usually is done with 
+     * normal pessimistic databases), the server should be set to the pessimistic mode. 
+     * The optimistic mode is about not waiting for the locks at all. That increases 
+     * concurrency but requires more programming. The pessimistic mode with the 
+     * READ COMMITTED isolation level (default) should get as much concurrency as one 
+     * might need. The pessimistic locking mode can be set in solid.ini:  
+     *    [General]
+     *        Pessimistic=yes
+     *    
      * 
      */
     public boolean storeIsMemory = false;
-
-    // weak set of connections we've already executed lock mode sql on
-    private final Collection _seenConnections = new ReferenceHashSet
-        (ReferenceHashSet.WEAK);
     
+    /**
+     * If true, then simulate auto-assigned values in SolidDB by
+     * using a trigger that inserts a sequence value into the
+     * primary key value when a row is inserted.
+     */
+    public boolean useTriggersForAutoAssign = true;
+
+    /**
+     * The global sequence name to use for autoassign simulation.
+     */
+    public String autoAssignSequenceName = null;
+
+    /**
+     * Flag to use OpenJPA 0.3 style naming for auto assign sequence name and
+     * trigger name for backwards compatibility.
+     */
+    public boolean openjpa3GeneratedKeyNames = false;
+
+
     private static final Localizer _loc = Localizer.forPackage
         (SolidDBDictionary.class);
 
@@ -124,7 +150,84 @@ public class SolidDBDictionary
             buf.append("MEMORY");
         else
             buf.append("DISK");
-        return new String[]{ buf.toString() };
+        
+        String[] create = new String[]{ buf.toString() };
+        if (!useTriggersForAutoAssign)
+            return create;
+
+        List seqs = null;
+        String seq, trig;
+        for (int i = 0; cols != null && i < cols.length; i++) {
+            if (!cols[i].isAutoAssigned())
+                continue;
+            if (seqs == null)
+                seqs = new ArrayList(4);
+
+            seq = autoAssignSequenceName;
+            if (seq == null) {
+                if (openjpa3GeneratedKeyNames)
+                    seq = getOpenJPA3GeneratedKeySequenceName(cols[i]);
+                else
+                    seq = getGeneratedKeySequenceName(cols[i]);
+                seqs.add("CREATE SEQUENCE " + seq);
+            }
+            if (openjpa3GeneratedKeyNames)
+                trig = getOpenJPA3GeneratedKeyTriggerName(cols[i]);
+            else
+                trig = getGeneratedKeyTriggerName(cols[i]);
+
+            // create the trigger that will insert new values into
+            // the table whenever a row is created
+            // CREATE TRIGGER TRIG01 ON table1 
+            //     BEFORE INSERT 
+            //     REFERENCING NEW COL1 AS NEW_COL1
+            // BEGIN
+            //     EXEC SEQUENCE seq1 NEXT INTO NEW_COL1;
+            // END;
+
+            seqs.add("CREATE TRIGGER " + trig
+                + " ON " + toDBName(table.getIdentifier())
+                + " BEFORE INSERT REFERENCING NEW " + toDBName(cols[i].getIdentifier())
+                + " AS NEW_COL1 BEGIN EXEC SEQUENCE " + seq + " NEXT INTO NEW_COL1; END");
+        }
+        if (seqs == null)
+            return create;
+
+        // combine create table sql and create seqences sql
+        String[] sql = new String[create.length + seqs.size()];
+        System.arraycopy(create, 0, sql, 0, create.length);
+        for (int i = 0; i < seqs.size(); i++)
+            sql[create.length + i] = (String) seqs.get(i);
+        return sql;
+    }
+
+    /**
+     * Trigger name for simulating auto-assign values on the given column.
+     */
+    protected String getGeneratedKeyTriggerName(Column col) {
+        // replace trailing _SEQ with _TRG
+        String seqName = getGeneratedKeySequenceName(col);
+        return seqName.substring(0, seqName.length() - 3) + "TRG";
+    }
+
+    /**
+     * Returns a OpenJPA 3-compatible name for an auto-assign sequence.
+     */
+    protected String getOpenJPA3GeneratedKeySequenceName(Column col) {
+        Table table = col.getTable();
+        DBIdentifier sName = DBIdentifier.preCombine(table.getIdentifier(), "SEQ");
+        return toDBName(getNamingUtil().makeIdentifierValid(sName, table.getSchema().
+            getSchemaGroup(), maxTableNameLength, true));
+    }
+
+    /**
+     * Returns a OpenJPA 3-compatible name for an auto-assign trigger.
+     */
+    protected String getOpenJPA3GeneratedKeyTriggerName(Column col) {
+        Table table = col.getTable();        
+        DBIdentifier sName = DBIdentifier.preCombine(table.getIdentifier(), "TRIG");
+        return toDBName(getNamingUtil().makeIdentifierValid(sName, table.getSchema().
+            getSchemaGroup(), maxTableNameLength, true));
     }
 
     @Override
@@ -188,37 +291,69 @@ public class SolidDBDictionary
     }
    
     @Override
-    public Connection decorate(Connection conn)
-    throws SQLException {
-        conn = super.decorate(conn);
-        // if we haven't already done so, initialize the lock mode of the
-        // connection
-        if (_seenConnections.add(conn)) {
-            String sql = "SET OPTIMISTIC LOCK TIMEOUT 100";
-            execute(sql, conn, true);
-        }
-        return conn;
-    }    
-
-    private void execute(String sql, Connection conn, boolean throwExc) {
-        Statement stmnt = null;
-        try {
-            stmnt = conn.createStatement();
-            stmnt.executeUpdate(sql);
-        } catch (SQLException se) {
-            if (throwExc)
-                throw SQLExceptions.getStore(se, this);
-            else {
-                if (log.isTraceEnabled())
-                    log.trace(_loc.get("can-not-execute", sql));
-            }
-        } finally {
-            if (stmnt != null)
-                try {
-                    stmnt.close();
-                } catch (SQLException se) {
-                }
+    public boolean isSystemIndex(DBIdentifier name, Table table) {
+        // names starting with "$$" are reserved for SolidDB internal use
+        String strName = DBIdentifier.isNull(name) ? null : name.getName();
+        boolean startsWith$$ = false;
+        if (strName != null) {
+            startsWith$$ = name.isDelimited() ? strName.startsWith("\"$$") :
+                strName.startsWith("$$");
         }
+        return super.isSystemIndex(name, table) || startsWith$$; 
     }
 
+    @Override
+    public void setBigDecimal(PreparedStatement stmnt, int idx, BigDecimal val,
+            Column col) throws SQLException {
+        int type = (val == null || col == null) ? JavaTypes.BIGDECIMAL
+                : col.getJavaType();
+        switch (type) {
+        case JavaTypes.DOUBLE:
+        case JavaTypes.DOUBLE_OBJ:
+            setDouble(stmnt, idx, val.doubleValue(), col);
+            break;
+        case JavaTypes.FLOAT:
+        case JavaTypes.FLOAT_OBJ:
+            setDouble(stmnt, idx, val.floatValue(), col);
+            break;
+        case JavaTypes.LONG:
+        case JavaTypes.LONG_OBJ:
+            setLong(stmnt, idx, val.longValue(), col);
+            break;
+        default:
+            super.setBigDecimal(stmnt, idx, val, col);
+        }
+    }
+
+    @Override
+    public void setDouble(PreparedStatement stmnt, int idx, double val,
+            Column col) throws SQLException {
+        int type = (col == null) ? JavaTypes.DOUBLE
+                : col.getJavaType();
+        switch (type) {
+        case JavaTypes.DOUBLE:
+        case JavaTypes.DOUBLE_OBJ:
+            setDouble(stmnt, idx, val, col);
+            break;
+        case JavaTypes.FLOAT:
+        case JavaTypes.FLOAT_OBJ:
+            setDouble(stmnt, idx, new Double(val).floatValue(), col);
+            break;
+        case JavaTypes.LONG:
+        case JavaTypes.LONG_OBJ:
+            setLong(stmnt, idx, new Double(val).longValue(), col);
+            break;
+        }
+    }
+    
+    @Override
+    public boolean needsToCreateIndex(Index idx, Table table) {
+       // SolidDB will automatically create a unique index for the 
+       // constraint, so don't create another index again
+       PrimaryKey pk = table.getPrimaryKey();
+       if (pk != null && idx.columnsMatch(pk.getColumns()))
+           return false;
+       return true;
+    }
+    
 }