You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2010/05/27 16:10:47 UTC

svn commit: r948843 - in /incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core: database/ interfaces/

Author: kwright
Date: Thu May 27 14:10:47 2010
New Revision: 948843

URL: http://svn.apache.org/viewvc?rev=948843&view=rev
Log:
Allow the database implementation to control the driver class name and database url.

Added:
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java   (with props)
Modified:
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/ConnectionFactory.java
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceMySQL.java
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfacePostgreSQL.java
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/Database.java
    incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/DatabaseFactory.java

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/ConnectionFactory.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/ConnectionFactory.java?rev=948843&r1=948842&r2=948843&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/ConnectionFactory.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/ConnectionFactory.java Thu May 27 14:10:47 2010
@@ -36,10 +36,6 @@ public class ConnectionFactory
 {
   public static final String _rcsid = "@(#)$Id$";
 
-  private static final String _url = "jdbc:postgresql://localhost/";
-  // private static final String _url = "jdbc:mysql://localhost/";
-  private static final String _driver = "org.postgresql.Driver";
-  // private static final String _driver = "org.gjt.mm.mysql.Driver";
 
   private static final int defaultMaxDBConnections = 200;
   private static final int defaultTimeoutValue = 86400;
@@ -52,14 +48,11 @@ public class ConnectionFactory
   {
   }
 
-  public static Connection getConnection(String database, String userName, String password)
+  public static Connection getConnection(String jdbcUrl, String jdbcDriver, String database, String userName, String password)
     throws LCFException
   {
-    String dburl = _url + database;
-    if (database.length() == 0)
-      database = "_root_";
 
-    ConnectionPoolManager _pool = poolManager.ensurePoolExists();
+    ConnectionPoolManager _pool = poolManager.ensurePoolExists(jdbcDriver);
     try
     {
       // Hope for a connection now
@@ -85,7 +78,7 @@ public class ConnectionFactory
 
         // Logging.db.debug("adding pool alias [" + database + "]");
         // I had to up the timeout from one hour to 3 due to the webconnector keeping some connections open a very long time...
-        _pool.addAlias(database, _driver, dburl,
+        _pool.addAlias(database, jdbcDriver, jdbcUrl,
           userName, password,
           maxDBConnections,
           300,                    // Idle timeout: idle time before closing connection: 5 minutes
@@ -201,7 +194,7 @@ public class ConnectionFactory
     {
     }
 
-    public ConnectionPoolManager ensurePoolExists()
+    public ConnectionPoolManager ensurePoolExists(String jdbcDriver)
       throws LCFException
     {
       synchronized (poolExistenceLock)
@@ -210,7 +203,7 @@ public class ConnectionFactory
           return _pool;
         try
         {
-          Class.forName(_driver);
+          Class.forName(jdbcDriver);
         }
         catch (Exception e)
         {

Added: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java?rev=948843&view=auto
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java (added)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java Thu May 27 14:10:47 2010
@@ -0,0 +1,926 @@
+/* $Id$ */
+
+/**
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.apache.lcf.core.database;
+
+import org.apache.lcf.core.interfaces.*;
+import org.apache.lcf.core.system.Logging;
+import java.util.*;
+
+public class DBInterfaceDerby implements IDBInterface
+{
+  public static final String _rcsid = "@(#)$Id$";
+
+  protected final static String _url = "jdbc:derby:";
+  protected final static String _driver = "org.apache.derby.jdbc.EmbeddedDriver";
+  
+  protected IThreadContext context;
+  protected IDatabase database;
+  protected String cacheKey;
+  // Postgresql serializable transactions are broken in that transactions that occur within them do not in fact work properly.
+  // So, once we enter the serializable realm, STOP any additional transactions from doing anything at all.
+  protected int serializableDepth = 0;
+
+  public DBInterfaceDerby(IThreadContext tc, String databaseName, String userName, String password)
+    throws LCFException
+  {
+    this.context = tc;
+    if (databaseName == null)
+      databaseName = "default";
+    database = DatabaseFactory.make(tc,_url+databaseName,_driver,databaseName,userName,password);
+    cacheKey = CacheKeyFactory.makeDatabaseKey(databaseName);
+  }
+
+  /** Get the database name.
+  *@return the database name.
+  */
+  public String getDatabaseName()
+  {
+    return database.getDatabaseName();
+  }
+
+  /** Get the current transaction id.
+  *@return the current transaction identifier, or null if no transaction.
+  */
+  public String getTransactionID()
+  {
+    return database.getTransactionID();
+  }
+
+  /** Get the database general cache key.
+  *@return the general cache key for the database.
+  */
+  public String getDatabaseCacheKey()
+  {
+    return cacheKey;
+  }
+
+  /** Perform a table lock operation.
+  *@param tableName is the name of the table.
+  */
+  public void performLock(String tableName)
+    throws LCFException
+  {
+    performModification("LOCK TABLE "+tableName+" IN EXCLUSIVE MODE",null,null);
+  }
+
+  /** Perform an insert operation.
+  *@param tableName is the name of the table.
+  *@param invalidateKeys are the cache keys that should be
+  * invalidated.
+  *@param parameterMap is the map of column name/values to write.
+  */
+  public void performInsert(String tableName, Map parameterMap, StringSet invalidateKeys)
+    throws LCFException
+  {
+    ArrayList paramArray = new ArrayList();
+
+    StringBuffer bf = new StringBuffer();
+    bf.append("INSERT INTO ");
+    bf.append(tableName);
+    bf.append(" (") ;
+
+    StringBuffer values = new StringBuffer(" VALUES (");
+
+    // loop for cols
+    Iterator it = parameterMap.entrySet().iterator();
+    boolean first = true;
+    while (it.hasNext())
+    {
+      Map.Entry e = (Map.Entry)it.next();
+      String key = (String)e.getKey();
+
+      Object o = e.getValue();
+      if (o != null)
+      {
+        paramArray.add(o);
+
+        if (!first)
+        {
+          bf.append(',');
+          values.append(',');
+        }
+        bf.append(key);
+        values.append('?');
+
+        first = false;
+      }
+    }
+
+    bf.append(')');
+    values.append(')');
+    bf.append(values);
+
+    // Do the modification
+    performModification(bf.toString(),paramArray,invalidateKeys);
+  }
+
+
+  /** Perform an update operation.
+  *@param tableName is the name of the table.
+  *@param invalidateKeys are the cache keys that should be invalidated.
+  *@param parameterMap is the map of column name/values to write.
+  *@param whereClause is the where clause describing the match (including the WHERE), or null if none.
+  *@param whereParameters are the parameters that come with the where clause, if any.
+  */
+  public void performUpdate(String tableName, Map parameterMap, String whereClause, ArrayList whereParameters, StringSet invalidateKeys)
+    throws LCFException
+  {
+    ArrayList paramArray = new ArrayList();
+
+    StringBuffer bf = new StringBuffer();
+    bf.append("UPDATE ");
+    bf.append(tableName);
+    bf.append(" SET ") ;
+
+    // loop for parameters
+    Iterator it = parameterMap.entrySet().iterator();
+    boolean first = true;
+    while (it.hasNext())
+    {
+      Map.Entry e = (Map.Entry)it.next();
+      String key = (String)e.getKey();
+
+      Object o = e.getValue();
+
+      if (!first)
+      {
+        bf.append(',');
+      }
+      bf.append(key);
+      bf.append('=');
+      if (o == null)
+      {
+        bf.append("NULL");
+      }
+      else
+      {
+        bf.append('?');
+        paramArray.add(o);
+      }
+
+      first = false;
+    }
+
+    if (whereClause != null)
+    {
+      bf.append(' ');
+      bf.append(whereClause);
+      if (whereParameters != null)
+      {
+        for (int i = 0; i < whereParameters.size(); i++)
+        {
+          Object value = whereParameters.get(i);
+          paramArray.add(value);
+        }
+      }
+    }
+
+    // Do the modification
+    performModification(bf.toString(),paramArray,invalidateKeys);
+
+  }
+
+
+  /** Perform a delete operation.
+  *@param tableName is the name of the table to delete from.
+  *@param invalidateKeys are the cache keys that should be invalidated.
+  *@param whereClause is the where clause describing the match (including the WHERE), or null if none.
+  *@param whereParameters are the parameters that come with the where clause, if any.
+  */
+  public void performDelete(String tableName, String whereClause, ArrayList whereParameters, StringSet invalidateKeys)
+    throws LCFException
+  {
+    StringBuffer bf = new StringBuffer();
+    bf.append("DELETE FROM ");
+    bf.append(tableName);
+    if (whereClause != null)
+    {
+      bf.append(' ');
+      bf.append(whereClause);
+    }
+    else
+      whereParameters = null;
+
+    // Do the modification
+    performModification(bf.toString(),whereParameters,invalidateKeys);
+
+  }
+
+  /** Perform a table creation operation.
+  *@param tableName is the name of the table to create.
+  *@param columnMap is the map describing the columns and types.  NOTE that these are abstract
+  * types, which will be mapped to the proper types for the actual database inside this
+  * layer.
+  *@param invalidateKeys are the cache keys that should be invalidated, if any.
+  */
+  public void performCreate(String tableName, Map columnMap, StringSet invalidateKeys)
+    throws LCFException
+  {
+    int constraintNumber = 0;
+    StringBuffer queryBuffer = new StringBuffer("CREATE TABLE ");
+    queryBuffer.append(tableName);
+    queryBuffer.append('(');
+    Iterator iter = columnMap.keySet().iterator();
+    boolean first = true;
+    while (iter.hasNext())
+    {
+      String columnName = (String)iter.next();
+      ColumnDescription cd = (ColumnDescription)columnMap.get(columnName);
+      if (!first)
+        queryBuffer.append(',');
+      else
+        first = false;
+      appendDescription(queryBuffer,columnName,cd,false);
+    }
+    queryBuffer.append(')');
+
+    performModification(queryBuffer.toString(),null,invalidateKeys);
+
+  }
+
+  protected void appendDescription(StringBuffer queryBuffer, String columnName, ColumnDescription cd, boolean forceNull)
+    throws LCFException
+  {
+    queryBuffer.append(columnName);
+    queryBuffer.append(' ');
+    queryBuffer.append(mapType(cd.getTypeString()));
+    if (forceNull || cd.getIsNull())
+      queryBuffer.append(" NULL");
+    else
+      queryBuffer.append(" NOT NULL");
+    if (cd.getIsPrimaryKey())
+      queryBuffer.append("CONSTRAINT c" + IDFactory.make(context) + " PRIMARY KEY");
+    if (cd.getReferenceTable() != null)
+    {
+      queryBuffer.append("CONSTRAINT c" + IDFactory.make(context) + " REFERENCES ");
+      queryBuffer.append(cd.getReferenceTable());
+      queryBuffer.append('(');
+      queryBuffer.append(cd.getReferenceColumn());
+      queryBuffer.append(") ON DELETE");
+      if (cd.getReferenceCascade())
+        queryBuffer.append(" CASCADE");
+      else
+        queryBuffer.append(" RESTRICT");
+    }
+  }
+
+  /** Perform a table alter operation.
+  *@param tableName is the name of the table to alter.
+  *@param columnMap is the map describing the columns and types to add.  These
+  * are in the same form as for performCreate.
+  *@param columnModifyMap is the map describing the columns to be changed.  The key is the
+  * existing column name, and the value is the new type of the column.  Data will be copied from
+  * the old column to the new.
+  *@param columnDeleteList is the list of column names to delete.
+  *@param invalidateKeys are the cache keys that should be invalidated, if any.
+  */
+  public void performAlter(String tableName, Map columnMap, Map columnModifyMap, ArrayList columnDeleteList,
+    StringSet invalidateKeys)
+    throws LCFException
+  {
+    beginTransaction(TRANSACTION_ENCLOSING);
+    try
+    {
+      if (columnDeleteList != null)
+      {
+        int i = 0;
+        while (i < columnDeleteList.size())
+        {
+          String columnName = (String)columnDeleteList.get(i++);
+          performModification("ALTER TABLE ONLY "+tableName+" DROP "+columnName,null,invalidateKeys);
+        }
+      }
+
+      // Do the modifies.  This involves renaming each column to a temp column, then creating a new one, then copying
+      if (columnModifyMap != null)
+      {
+        Iterator iter = columnModifyMap.keySet().iterator();
+        while (iter.hasNext())
+        {
+          String columnName = (String)iter.next();
+          ColumnDescription cd = (ColumnDescription)columnModifyMap.get(columnName);
+          String renameColumn = "__temp__";
+          // Create a new column we can copy the data into.
+          performModification("RENAME COLUMN "+tableName+"."+columnName+" TO "+renameColumn,null,invalidateKeys);
+          // Create new column
+          StringBuffer sb = new StringBuffer();
+          appendDescription(sb,columnName,cd,true);
+          performModification("ALTER TABLE "+tableName+" ADD "+sb.toString(),null,invalidateKeys);
+          // Copy old data to new
+          performModification("UPDATE "+tableName+" SET "+columnName+"="+renameColumn,null,invalidateKeys);
+          // Make the column null, if it needs it
+          if (cd.getIsNull() == false)
+            performModification("ALTER TABLE "+tableName+" ALTER "+columnName+" SET NOT NULL",null,invalidateKeys);
+          // Drop old column
+          performModification("ALTER TABLE "+tableName+" DROP "+renameColumn,null,invalidateKeys);
+        }
+      }
+
+      // Now, do the adds
+      if (columnMap != null)
+      {
+        Iterator iter = columnMap.keySet().iterator();
+        while (iter.hasNext())
+        {
+          String columnName = (String)iter.next();
+          ColumnDescription cd = (ColumnDescription)columnMap.get(columnName);
+          StringBuffer sb = new StringBuffer();
+          appendDescription(sb,columnName,cd,false);
+          performModification("ALTER TABLE "+tableName+" ADD "+sb.toString(),null,invalidateKeys);
+        }
+      }
+    }
+    catch (LCFException e)
+    {
+      signalRollback();
+      throw e;
+    }
+    catch (Error e)
+    {
+      signalRollback();
+      throw e;
+    }
+    finally
+    {
+      endTransaction();
+    }
+
+  }
+
+
+  /** Map a standard type into a derby type.
+  *@param inputType is the input type.
+  *@return the output type.
+  */
+  protected static String mapType(String inputType)
+  {
+    if (inputType.equalsIgnoreCase("longtext"))
+      return "clob";
+    return inputType;
+  }
+
+  /** Add an index to a table.
+  *@param tableName is the name of the table to add the index for.
+  *@param unique is a boolean that if true describes a unique index.
+  *@param columnList is the list of columns that need to be included
+  * in the index, in order.
+  */
+  public void addTableIndex(String tableName, boolean unique, ArrayList columnList)
+    throws LCFException
+  {
+    String[] columns = new String[columnList.size()];
+    int i = 0;
+    while (i < columns.length)
+    {
+      columns[i] = (String)columnList.get(i);
+      i++;
+    }
+    performAddIndex(null,tableName,new IndexDescription(unique,columns));
+  }
+
+  /** Add an index to a table.
+  *@param tableName is the name of the table to add the index for.
+  *@param indexName is the optional name of the table index.  If null, a name will be chosen automatically.
+  *@param description is the index description.
+  */
+  public void performAddIndex(String indexName, String tableName, IndexDescription description)
+    throws LCFException
+  {
+    String[] columnNames = description.getColumnNames();
+    if (columnNames.length == 0)
+      return;
+
+    if (indexName == null)
+      // Build an index name
+      indexName = "I"+IDFactory.make(context);
+    StringBuffer queryBuffer = new StringBuffer("CREATE ");
+    if (description.getIsUnique())
+      queryBuffer.append("UNIQUE ");
+    queryBuffer.append("INDEX ");
+    queryBuffer.append(indexName);
+    queryBuffer.append(" ON ");
+    queryBuffer.append(tableName);
+    queryBuffer.append(" (");
+    int i = 0;
+    while (i < columnNames.length)
+    {
+      String colName = columnNames[i];
+      if (i > 0)
+        queryBuffer.append(',');
+      queryBuffer.append(colName);
+      i++;
+    }
+    queryBuffer.append(')');
+
+    performModification(queryBuffer.toString(),null,null);
+  }
+
+  /** Remove an index.
+  *@param indexName is the name of the index to remove.
+  */
+  public void performRemoveIndex(String indexName)
+    throws LCFException
+  {
+    performModification("DROP INDEX "+indexName,null,null);
+  }
+
+  /** Analyze a table.
+  *@param tableName is the name of the table to analyze/calculate statistics for.
+  */
+  public void analyzeTable(String tableName)
+    throws LCFException
+  {
+    // Does nothing on Derby
+  }
+
+  /** Reindex a table.
+  *@param tableName is the name of the table to rebuild indexes for.
+  */
+  public void reindexTable(String tableName)
+    throws LCFException
+  {
+    // Does nothing on Derby
+  }
+
+  /** Perform a table drop operation.
+  *@param tableName is the name of the table to drop.
+  *@param invalidateKeys are the cache keys that should be invalidated, if any.
+  */
+  public void performDrop(String tableName, StringSet invalidateKeys)
+    throws LCFException
+  {
+    performModification("DROP TABLE "+tableName,null,invalidateKeys);
+  }
+
+  /** Perform user lookup.
+  *@param userName is the user name to lookup.
+  *@return true if the user exists.
+  */
+  public boolean lookupUser(String userName, StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    ArrayList params = new ArrayList();
+    params.add(userName);
+    IResultSet set = performQuery("SELECT * FROM pg_user WHERE usename=?",params,cacheKeys,queryClass);
+    if (set.getRowCount() == 0)
+      return false;
+    return true;
+  }
+
+  /** Perform user create.
+  *@param userName is the user name.
+  *@param password is the user's password.
+  */
+  public void performCreateUser(String userName, String password)
+    throws LCFException
+  {
+    performModification("CREATE USER "+userName+" PASSWORD "+
+      quoteSQLString(password),null,null);
+  }
+
+  /** Perform user delete.
+  *@param userName is the user name.
+  */
+  public void performDropUser(String userName)
+    throws LCFException
+  {
+    performModification("DROP USER "+userName,null,null);
+  }
+
+  /** Perform database lookup.
+  *@param databaseName is the database name.
+  *@param cacheKeys are the cache keys, if any.
+  *@return true if the database exists.
+  */
+  public boolean lookupDatabase(String databaseName, StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    ArrayList params = new ArrayList();
+    params.add(databaseName);
+    IResultSet set = performQuery("SELECT * FROM pg_database WHERE datname=?",params,cacheKeys,queryClass);
+    if (set.getRowCount() == 0)
+      return false;
+    return true;
+  }
+
+  /** Perform database create.
+  *@param databaseName is the database name.
+  *@param databaseUser is the user to grant access to the database.
+  *@param databasePassword is the password of the user to grant access to the database.
+  *@param invalidateKeys are the cache keys that should be invalidated, if any.
+  */
+  public void performCreateDatabase(String databaseName, String databaseUser, String databasePassword,
+    StringSet invalidateKeys)
+    throws LCFException
+  {
+    performModification("CREATE DATABASE "+databaseName+" OWNER="+
+      databaseUser+" ENCODING="+
+      quoteSQLString("utf8"),null,invalidateKeys);
+  }
+
+  /** Perform database drop.
+  *@param databaseName is the database name.
+  *@param invalidateKeys are the cache keys that should be invalidated, if any.
+  */
+  public void performDropDatabase(String databaseName, StringSet invalidateKeys)
+    throws LCFException
+  {
+    performModification("DROP DATABASE "+databaseName,null,invalidateKeys);
+  }
+
+  /** Reinterpret an exception tossed by the database layer.  We need to disambiguate the various kinds of exception that
+  * should be thrown.
+  *@param theException is the exception to reinterpret
+  *@return the reinterpreted exception to throw.
+  */
+  protected LCFException reinterpretException(LCFException theException)
+  {
+    if (Logging.db.isDebugEnabled())
+      Logging.db.debug("Reinterpreting exception '"+theException.getMessage()+"'.  The exception type is "+Integer.toString(theException.getErrorCode()));
+    if (theException.getErrorCode() != LCFException.DATABASE_CONNECTION_ERROR)
+      return theException;
+    Throwable e = theException.getCause();
+    if (!(e instanceof java.sql.SQLException))
+      return theException;
+    if (Logging.db.isDebugEnabled())
+      Logging.db.debug("Exception "+theException.getMessage()+" is possibly a transaction abort signal");
+    String message = e.getMessage();
+    if (message.indexOf("deadlock detected") != -1)
+      return new LCFException(message,e,LCFException.DATABASE_TRANSACTION_ABORT);
+    if (message.indexOf("could not serialize") != -1)
+      return new LCFException(message,e,LCFException.DATABASE_TRANSACTION_ABORT);
+    // Note well: We also have to treat 'duplicate key' as a transaction abort, since this is what you get when two threads attempt to
+    // insert the same row.  (Everything only works, then, as long as there is a unique constraint corresponding to every bad insert that
+    // one could make.)
+    if (message.indexOf("duplicate key") != -1)
+      return new LCFException(message,e,LCFException.DATABASE_TRANSACTION_ABORT);
+    if (Logging.db.isDebugEnabled())
+      Logging.db.debug("Exception "+theException.getMessage()+" is NOT a transaction abort signal");
+    return theException;
+  }
+
+  /** Perform a general database modification query.
+  *@param query is the query string.
+  *@param params are the parameterized values, if needed.
+  *@param invalidateKeys are the cache keys to invalidate.
+  */
+  public void performModification(String query, ArrayList params, StringSet invalidateKeys)
+    throws LCFException
+  {
+    try
+    {
+      database.executeQuery(query,params,null,invalidateKeys,null,false,0,null,null);
+    }
+    catch (LCFException e)
+    {
+      throw reinterpretException(e);
+    }
+  }
+
+  /** Get a table's schema.
+  *@param tableName is the name of the table.
+  *@param cacheKeys are the keys against which to cache the query, or null.
+  *@param queryClass is the name of the query class, or null.
+  *@return a map of column names and ColumnDescription objects, describing the schema, or null if the
+  * table doesn't exist.
+  */
+  public Map getTableSchema(String tableName, StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    // MHL
+    StringBuffer query = new StringBuffer();
+    query.append("SELECT pg_attribute.attname AS \"Field\",");
+    query.append("CASE pg_type.typname WHEN 'int2' THEN 'smallint' WHEN 'int4' THEN 'int'");
+    query.append(" WHEN 'int8' THEN 'bigint' WHEN 'varchar' THEN 'varchar(' || pg_attribute.atttypmod-4 || ')'");
+    query.append(" WHEN 'text' THEN 'longtext'");
+    query.append(" WHEN 'bpchar' THEN 'char(' || pg_attribute.atttypmod-4 || ')'");
+    query.append(" ELSE pg_type.typname END AS \"Type\",");
+    query.append("CASE WHEN pg_attribute.attnotnull THEN '' ELSE 'YES' END AS \"Null\",");
+    query.append("CASE pg_type.typname WHEN 'varchar' THEN substring(pg_attrdef.adsrc from '^(.*).*$') ELSE pg_attrdef.adsrc END AS Default ");
+    query.append("FROM pg_class INNER JOIN pg_attribute ON (pg_class.oid=pg_attribute.attrelid) INNER JOIN pg_type ON (pg_attribute.atttypid=pg_type.oid) ");
+    query.append("LEFT JOIN pg_attrdef ON (pg_class.oid=pg_attrdef.adrelid AND pg_attribute.attnum=pg_attrdef.adnum) ");
+    query.append("WHERE pg_class.relname=").append(quoteSQLString(tableName)).append(" AND pg_attribute.attnum>=1 AND NOT pg_attribute.attisdropped ");
+    query.append("ORDER BY pg_attribute.attnum");
+
+    IResultSet set = performQuery(query.toString(),null,cacheKeys,queryClass);
+    if (set.getRowCount() == 0)
+      return null;
+    // Digest the result
+    HashMap rval = new HashMap();
+    int i = 0;
+    while (i < set.getRowCount())
+    {
+      IResultRow row = set.getRow(i++);
+      String fieldName = row.getValue("Field").toString();
+      String type = row.getValue("Type").toString();
+      boolean isNull = row.getValue("Null").toString().equals("YES");
+      boolean isPrimaryKey = false; // row.getValue("Key").toString().equals("PRI");
+      rval.put(fieldName,new ColumnDescription(type,isPrimaryKey,isNull,null,null,false));
+    }
+
+    return rval;
+  }
+
+  /** Get a table's indexes.
+  *@param tableName is the name of the table.
+  *@param cacheKeys are the keys against which to cache the query, or null.
+  *@param queryClass is the name of the query class, or null.
+  *@return a map of index names and IndexDescription objects, describing the indexes.
+  */
+  public Map getTableIndexes(String tableName, StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    Map rval = new HashMap();
+
+    // This query returns all index names for the table
+    String query = "SELECT t0.CONGLOMERATENAME FROM SYSCONGLOMERATES t0,SYSTABLES t1 WHERE t0.TABLEID=t1.TABLEID AND t0.ISINDEX=1 AND t1.TABLENAME='"+tableName+"'";
+    
+    // It doesn't look like there's a way to find exactly what is in the index, and what the columns are.  Since
+    // the goal of Derby is to build tests, and this method is used primarily on installation, we can probably accept
+    // the poor performance implied in tearing an index down and recreating it unnecessarily, so I'm going to do a fake-out.
+    
+    IResultSet result = performQuery(query,null,cacheKeys,queryClass);
+    int i = 0;
+    while (i < result.getRowCount())
+    {
+      IResultRow row = result.getRow(i++);
+      String indexName = (String)row.getValue("CONGLOMERATENAME");
+
+      rval.put(indexName,new IndexDescription(false,new String[0]));
+    }
+
+    return rval;
+  }
+
+  /** Get a database's tables.
+  *@param cacheKeys are the cache keys for the query, or null.
+  *@param queryClass is the name of the query class, or null.
+  *@return the set of tables.
+  */
+  public StringSet getAllTables(StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    IResultSet set = performQuery("SELECT TABLENAME FROM SYSTABLES WHERE TABLE_TYPE='T'",null,cacheKeys,queryClass);
+    StringSetBuffer ssb = new StringSetBuffer();
+    String columnName = "TABLENAME";
+
+    int i = 0;
+    while (i < set.getRowCount())
+    {
+      IResultRow row = set.getRow(i++);
+      String value = row.getValue(columnName).toString();
+      ssb.add(value);
+    }
+    return new StringSet(ssb);
+  }
+
+  /** Perform a general "data fetch" query.
+  *@param query is the query string.
+  *@param params are the parameterized values, if needed.
+  *@param cacheKeys are the cache keys, if needed (null if no cache desired).
+  *@param queryClass is the LRU class name against which this query would be cached,
+  * or null if no LRU behavior desired.
+  *@return a resultset.
+  */
+  public IResultSet performQuery(String query, ArrayList params, StringSet cacheKeys, String queryClass)
+    throws LCFException
+  {
+    try
+    {
+      return database.executeQuery(query,params,cacheKeys,null,queryClass,true,-1,null,null);
+    }
+    catch (LCFException e)
+    {
+      throw reinterpretException(e);
+    }
+  }
+
+  /** Perform a general "data fetch" query.
+  *@param query is the query string.
+  *@param params are the parameterized values, if needed.
+  *@param cacheKeys are the cache keys, if needed (null if no cache desired).
+  *@param queryClass is the LRU class name against which this query would be cached,
+  * or null if no LRU behavior desired.
+  *@param maxResults is the maximum number of results returned (-1 for all).
+  *@param returnLimit is a description of how to limit the return result, or null if no limit.
+  *@return a resultset.
+  */
+  public IResultSet performQuery(String query, ArrayList params, StringSet cacheKeys, String queryClass,
+    int maxResults, ILimitChecker returnLimit)
+    throws LCFException
+  {
+    try
+    {
+      return database.executeQuery(query,params,cacheKeys,null,queryClass,true,maxResults,null,returnLimit);
+    }
+    catch (LCFException e)
+    {
+      throw reinterpretException(e);
+    }
+  }
+
+  /** Perform a general "data fetch" query.
+  *@param query is the query string.
+  *@param params are the parameterized values, if needed.
+  *@param cacheKeys are the cache keys, if needed (null if no cache desired).
+  *@param queryClass is the LRU class name against which this query would be cached,
+  * or null if no LRU behavior desired.
+  *@param maxResults is the maximum number of results returned (-1 for all).
+  *@param resultSpec is a result specification, or null for the standard treatment.
+  *@param returnLimit is a description of how to limit the return result, or null if no limit.
+  *@return a resultset.
+  */
+  public IResultSet performQuery(String query, ArrayList params, StringSet cacheKeys, String queryClass,
+    int maxResults, ResultSpecification resultSpec, ILimitChecker returnLimit)
+    throws LCFException
+  {
+    try
+    {
+      return database.executeQuery(query,params,cacheKeys,null,queryClass,true,maxResults,resultSpec,returnLimit);
+    }
+    catch (LCFException e)
+    {
+      throw reinterpretException(e);
+    }
+  }
+
+  /** Quote a sql string.
+  * This method quotes a sql string in the proper manner for the database in question.
+  *@param string is the input string.
+  *@return the properly quoted (and escaped) output string.
+  */
+  public String quoteSQLString(String string)
+  {
+    StringBuffer rval = new StringBuffer();
+    char quoteChar = '\'';
+    rval.append(quoteChar);
+    int i = 0;
+    while (i < string.length())
+    {
+      char x = string.charAt(i++);
+      if (x == quoteChar)
+        rval.append(quoteChar);
+      rval.append(x);
+    }
+    rval.append(quoteChar);
+    return rval.toString();
+  }
+
+  /** Prepare a sql date for use in a query.
+  * This method prepares a query constant using the sql date string passed in.
+  * The date passed in is presumed to be in "standard form", or something that might have
+  * come back from a resultset of a query.
+  *@param date is the date in standard form.
+  *@return the sql date expression to use for date comparisons.
+  */
+  public String prepareSQLDate(String date)
+  {
+    // MHL
+    return null;
+  }
+
+  /** Obtain the maximum number of individual items that should be
+  * present in an IN clause.  Exceeding this amount will potentially cause the query performance
+  * to drop.
+  *@return the maximum number of IN clause members.
+  */
+  public int getMaxInClause()
+  {
+    return 100;
+  }
+
+  /** Begin a database transaction.  This method call MUST be paired with an endTransaction() call,
+  * or database handles will be lost.  If the transaction should be rolled back, then signalRollback() should
+  * be called before the transaction is ended.
+  * It is strongly recommended that the code that uses transactions be structured so that a try block
+  * starts immediately after this method call.  The body of the try block will contain all direct or indirect
+  * calls to executeQuery().  After this should be a catch for every exception type, including Error, which should call the
+  * signalRollback() method, and rethrow the exception.  Then, after that a finally{} block which calls endTransaction().
+  */
+  public void beginTransaction()
+    throws LCFException
+  {
+    beginTransaction(TRANSACTION_ENCLOSING);
+  }
+
+  /** Begin a database transaction.  This method call MUST be paired with an endTransaction() call,
+  * or database handles will be lost.  If the transaction should be rolled back, then signalRollback() should
+  * be called before the transaction is ended.
+  * It is strongly recommended that the code that uses transactions be structured so that a try block
+  * starts immediately after this method call.  The body of the try block will contain all direct or indirect
+  * calls to executeQuery().  After this should be a catch for every exception type, including Error, which should call the
+  * signalRollback() method, and rethrow the exception.  Then, after that a finally{} block which calls endTransaction().
+  *@param transactionType is the kind of transaction desired.
+  */
+  public void beginTransaction(int transactionType)
+    throws LCFException
+  {
+    if (database.getCurrentTransactionType() == database.TRANSACTION_SERIALIZED)
+    {
+      serializableDepth++;
+      return;
+    }
+
+    if (transactionType == TRANSACTION_ENCLOSING)
+    {
+      int enclosingTransactionType = database.getCurrentTransactionType();
+      switch (enclosingTransactionType)
+      {
+      case IDatabase.TRANSACTION_READCOMMITTED:
+        transactionType = TRANSACTION_READCOMMITTED;
+        break;
+      case IDatabase.TRANSACTION_SERIALIZED:
+        transactionType = TRANSACTION_SERIALIZED;
+        break;
+      default:
+        throw new LCFException("Unknown transaction type");
+      }
+    }
+
+    switch (transactionType)
+    {
+    case TRANSACTION_READCOMMITTED:
+      try
+      {
+        performModification("SET ISOLATION READ COMMITTED",null,null);
+      }
+      catch (Error e)
+      {
+        database.signalRollback();
+        database.endTransaction();
+        throw e;
+      }
+      catch (LCFException e)
+      {
+        database.signalRollback();
+        database.endTransaction();
+        throw e;
+      }
+      database.beginTransaction(database.TRANSACTION_READCOMMITTED);
+      break;
+    case TRANSACTION_SERIALIZED:
+      try
+      {
+        performModification("SET ISOLATION SERIALIZABLE",null,null);
+      }
+      catch (Error e)
+      {
+        database.signalRollback();
+        database.endTransaction();
+        throw e;
+      }
+      catch (LCFException e)
+      {
+        database.signalRollback();
+        database.endTransaction();
+        throw e;
+      }
+      database.beginTransaction(database.TRANSACTION_SERIALIZED);
+      break;
+    default:
+      throw new LCFException("Bad transaction type");
+    }
+  }
+
+  /** Signal that a rollback should occur on the next endTransaction().
+  */
+  public void signalRollback()
+  {
+    if (serializableDepth == 0)
+      database.signalRollback();
+  }
+
+  /** End a database transaction, either performing a commit or a rollback (depending on whether
+  * signalRollback() was called within the transaction).
+  */
+  public void endTransaction()
+    throws LCFException
+  {
+    if (serializableDepth > 0)
+    {
+      serializableDepth--;
+      return;
+    }
+
+    database.endTransaction();
+  }
+
+
+}
+

Propchange: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceDerby.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceMySQL.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceMySQL.java?rev=948843&r1=948842&r2=948843&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceMySQL.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfaceMySQL.java Thu May 27 14:10:47 2010
@@ -25,6 +25,9 @@ public class DBInterfaceMySQL implements
 {
   public static final String _rcsid = "@(#)$Id$";
 
+  private static final String _url = "jdbc:mysql://localhost/";
+  private static final String _driver = "org.gjt.mm.mysql.Driver";
+
   protected IThreadContext context;
   protected IDatabase database;
   protected String cacheKey;
@@ -35,7 +38,7 @@ public class DBInterfaceMySQL implements
     this.context = tc;
     if (databaseName == null)
       databaseName = "mysql";
-    database = DatabaseFactory.make(tc,databaseName,userName,password);
+    database = DatabaseFactory.make(tc,_url+databaseName,_driver,databaseName,userName,password);
     cacheKey = CacheKeyFactory.makeDatabaseKey(databaseName);
   }
 

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfacePostgreSQL.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfacePostgreSQL.java?rev=948843&r1=948842&r2=948843&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfacePostgreSQL.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/DBInterfacePostgreSQL.java Thu May 27 14:10:47 2010
@@ -26,6 +26,11 @@ public class DBInterfacePostgreSQL imple
 {
   public static final String _rcsid = "@(#)$Id$";
 
+  private static final String _url = "jdbc:postgresql://localhost/";
+  // private static final String _url = "jdbc:mysql://localhost/";
+  private static final String _driver = "org.postgresql.Driver";
+  // private static final String _driver = "org.gjt.mm.mysql.Driver";
+
   protected IThreadContext context;
   protected IDatabase database;
   protected String cacheKey;
@@ -45,7 +50,7 @@ public class DBInterfacePostgreSQL imple
     this.context = tc;
     if (databaseName == null)
       databaseName = "template1";
-    database = DatabaseFactory.make(tc,databaseName,userName,password);
+    database = DatabaseFactory.make(tc,_url+databaseName,_driver,databaseName,userName,password);
     cacheKey = CacheKeyFactory.makeDatabaseKey(databaseName);
   }
 

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/Database.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/Database.java?rev=948843&r1=948842&r2=948843&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/Database.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/database/Database.java Thu May 27 14:10:47 2010
@@ -38,6 +38,8 @@ public class Database implements IDataba
 
   protected ICacheManager cacheManager;
   protected IThreadContext context;
+  protected String jdbcUrl;
+  protected String jdbcDriverClass;
   protected String databaseName;
   protected String userName;
   protected String password;
@@ -51,10 +53,12 @@ public class Database implements IDataba
   protected final static String END_TRANSACTION = "COMMIT";
   protected final static String ROLLBACK_TRANSACTION = "ROLLBACK";
 
-  public Database(IThreadContext context, String databaseName, String userName, String password)
+  public Database(IThreadContext context, String jdbcUrl, String jdbcDriverClass, String databaseName, String userName, String password)
     throws LCFException
   {
     this.context = context;
+    this.jdbcUrl = jdbcUrl;
+    this.jdbcDriverClass = jdbcDriverClass;
     this.databaseName = databaseName;
     this.userName = userName;
     this.password = password;
@@ -196,7 +200,7 @@ public class Database implements IDataba
     // Get a semipermanent connection
     if (connection == null)
     {
-      connection = ConnectionFactory.getConnection(databaseName,userName,password);
+      connection = ConnectionFactory.getConnection(jdbcUrl,jdbcDriverClass,databaseName,userName,password);
       try
       {
         // Start a transaction
@@ -422,7 +426,7 @@ public class Database implements IDataba
     else
     {
       // Grab a connection
-      Connection tempConnection = ConnectionFactory.getConnection(databaseName,userName,password);
+      Connection tempConnection = ConnectionFactory.getConnection(jdbcUrl,jdbcDriverClass,databaseName,userName,password);
       try
       {
         return executeViaThread(tempConnection,query,params,bResults,maxResults,spec,returnLimit);

Modified: incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/DatabaseFactory.java
URL: http://svn.apache.org/viewvc/incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/DatabaseFactory.java?rev=948843&r1=948842&r2=948843&view=diff
==============================================================================
--- incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/DatabaseFactory.java (original)
+++ incubator/lcf/trunk/modules/framework/core/org/apache/lcf/core/interfaces/DatabaseFactory.java Thu May 27 14:10:47 2010
@@ -34,7 +34,7 @@ public class DatabaseFactory
 
   /** Grab or create the correct instance of a database manager.
   */
-  public static IDatabase make(IThreadContext context, String databaseName, String userName, String password)
+  public static IDatabase make(IThreadContext context, String jdbcUrl, String jdbcClass, String databaseName, String userName, String password)
     throws LCFException
   {
     String dbName = databaseInstancePrefix + databaseName;
@@ -42,7 +42,7 @@ public class DatabaseFactory
     if (x == null || !(x instanceof IDatabase))
     {
       // Create new database handle
-      x = new org.apache.lcf.core.database.Database(context,databaseName,userName,password);
+      x = new org.apache.lcf.core.database.Database(context,jdbcUrl,jdbcClass,databaseName,userName,password);
       context.save(dbName,x);
     }
     return (IDatabase)x;