Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright 2007 Daniel Spiewak
    * 
    * Licensed 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 net.java.ao;
  
  
  import org.slf4j.Logger;
  
  import static com.google.common.collect.Iterables.filter;
  
  import static com.google.common.collect.Iterables.concat;
  
  import static com.google.common.collect.Iterables.addAll;
  
  import static com.google.common.collect.Sets.union;
  
  
  import java.sql.Blob;
  import java.sql.Types;
  import java.util.Date;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Stack;
  
  import static com.google.common.base.Preconditions.*;
  import static com.google.common.collect.Iterables.transform;
  import static com.google.common.collect.Lists.newArrayList;
  import static net.java.ao.Common.*;

The superclass parent of all DatabaseProvider implementations. Various implementations allow for an abstraction around database-specific functionality (such as DDL). DatabaseProvider(s) also handle the creation of new java.sql.Connection instances and fully encapsulate the raw JDBC driver. Any database-specific code should be placed in the database provider, rather than embedded within the API logic.

This superclass contains a base-line, default implementation of most database-specific methods, thus requiring a minimum of work to implement a new database provider. For the sake of sanity (read: mine), this base-line implementation is basically specific to MySQL. Thus any DatabaseProvider implementations are really specifying the differences between the database in question and MySQL. To fully utilize the default implementations provided in this class, this fact should be kept in mind.

This class also handles the implementation details required to ensure that only one active java.sql.Connection instance is available per thread. This is in fact a very basic (and naive) form of connection pooling. It should not be relied upon for performance reasons. Instead one should enable connection pooling via the javax.sql.DataSource passed to instances. You can also use the net.java.ao.builder.EntityManagerBuilder builder to make it easier to configure the pooling. The purpose of the thread-locked connection pooling in this class is to satisfy transactions with external SQL statements.

Author(s):
Daniel Spiewak
 
 public abstract class DatabaseProvider implements Disposable
 {
     protected final Logger logger = LoggerFactory.getLogger(this.getClass());
     protected final Logger sqlLogger = LoggerFactory.getLogger("net.java.ao.sql");
 
     private final Set<SqlListenersqlListeners;
 
     private final ThreadLocal<ConnectiontransactionThreadLocal = new ThreadLocal<Connection>();
     private final DisposableDataSource dataSource;
     protected final TypeManager typeManager;
 
     private final String schema;
 
     private AtomicReference<StringquoteRef = new AtomicReference<String>();
 
     private static final String ORDER_CLAUSE_STRING = "(?:IDENTIFIER_QUOTE_STRING(\\w+)IDENTIFIER_QUOTE_STRING\\.)?(?:IDENTIFIER_QUOTE_STRING(\\w+)IDENTIFIER_QUOTE_STRING)(?:\\s*(?i:(ASC|DESC)))?";
     private final Pattern ORDER_CLAUSE_PATTERN;
 
     protected DatabaseProvider(DisposableDataSource dataSourceString schemaTypeManager typeManager)
     {
         this. = checkNotNull(dataSource);
         this. = typeManager;
         this. = isBlank(schema) ? null : schema// can be null
         this. = new CopyOnWriteArraySet<SqlListener>();
         this..add(new LoggingSqlListener());
         loadQuoteString();
 
         // Exclude quote strings around table / column names in order by - some plugins like put the quote string in themselves.
         String identifierQuoteStringPattern = "";
         String quote = .get();
         if (quote != null && !quote.isEmpty())
         {
             identifierQuoteStringPattern = "(?:" + Pattern.quote(quote) + ")?";
         }
          = Pattern.compile(.replaceAll("IDENTIFIER_QUOTE_STRING", Matcher.quoteReplacement(identifierQuoteStringPattern)));
     }
 
     protected DatabaseProvider(DisposableDataSource dataSourceString schema)
     {
         this(dataSourceschemanew TypeManager.Builder().build());
     }
 
     public TypeManager getTypeManager()
     {
         return ;
     }
 
     public String getSchema()
     {
         return ;
     }
 
     private void loadQuoteString()
     {
         Connection conn = null;
         try
         {
             conn = .getConnection();
             if (conn == null)
             {
                 throw new IllegalStateException("Could not get connection to load quote String");
             }
             .set(conn.getMetaData().getIdentifierQuoteString().trim());
         }
         catch (SQLException e)
         {
             throw new RuntimeException("Unable to query the database"e);
         }
         finally
         {
             closeQuietly(conn);
         }
     }

    

Generates the DDL fragment required to specify an INTEGER field as auto-incremented. For databases which do not support such flags (which is just about every database exception MySQL), "" is an acceptable return value. This method should never return null as it would cause the field rendering method to throw a java.lang.NullPointerException.

 
     protected String renderAutoIncrement()
     {
         return "AUTO_INCREMENT";
     }

    
Top level delegating method for the process of rendering a database-agnostic net.java.ao.schema.ddl.DDLAction into the database-specific SQL actions. If the action is to create an entity, then each of the SQL actions may have a corresponding undo action to roll back creation of the entity if necessary.

 
     public final Iterable<SQLActionrenderAction(NameConverters nameConvertersDDLAction action)
     {
         switch (action.getActionType())
         {
             case :
                 return renderCreateTableActions(nameConvertersaction.getTable());
 
             case :
                 return renderDropTableActions(nameConvertersaction.getTable());
 
             case :
                 return renderAddColumnActions(nameConvertersaction.getTable(), action.getField());
 
             case :
                 return renderAlterTableChangeColumn(nameConvertersaction.getTable(), action.getOldField(), action.getField());
 
             case :
                 return renderDropColumnActions(nameConvertersaction.getTable(), action.getField());
 
             case :
                 return ImmutableList.of(renderAlterTableAddKey(action.getKey())
                                         .withUndoAction(renderAlterTableDropKey(action.getKey())));
 
             case :
                 return ImmutableList.of(renderAlterTableDropKey(action.getKey()));
 
             case :
                 return ImmutableList.of(renderCreateIndex(nameConverters.getIndexNameConverter(), action.getIndex())
                                         .withUndoAction(renderDropIndex(nameConverters.getIndexNameConverter(), action.getIndex())));
 
             case :
                 return ImmutableList.of(renderDropIndex(nameConverters.getIndexNameConverter(), action.getIndex()));
                 
             case :
                 return ImmutableList.of(renderInsert(action.getTable(), action.getValues()));
         }
         throw new IllegalArgumentException("unknown DDLAction type " + action.getActionType());
     }
 
     private Iterable<SQLActionrenderCreateTableActions(NameConverters nameConvertersDDLTable table)
     {
         ImmutableList.Builder<SQLActionret = ImmutableList.builder();
         
         ret.add(renderTable(nameConverterstable).withUndoAction(renderDropTableStatement(table)));
         
         ret.addAll(renderAccessories(nameConverterstable));
 
         for (DDLIndex index : table.getIndexes())
         {
             DDLAction newAction = new DDLAction(.);
             newAction.setIndex(index);
             ret.addAll(renderAction(nameConvertersnewAction));
         }
         
         return ret.build();
     }
     
     private Iterable<SQLActionrenderDropTableActions(NameConverters nameConvertersDDLTable table)
     {
         ImmutableList.Builder<SQLActionret = ImmutableList.builder();
         
         for (DDLIndex index : table.getIndexes())
         {
             final SQLAction sqlAction = renderDropIndex(nameConverters.getIndexNameConverter(), index);
             if (sqlAction != null)
             {
                 ret.add(sqlAction);
             }
         }
 
         ret.addAll(renderDropAccessories(nameConverterstable));
         ret.add(renderDropTableStatement(table));
         
         return ret.build();
     }
     
     private Iterable<SQLActionrenderAddColumnActions(NameConverters nameConvertersDDLTable tableDDLField field)
     {
         ImmutableList.Builder<SQLActionret = ImmutableList.builder();
         
         ret.addAll(renderAlterTableAddColumn(nameConverterstablefield));
         
         for (DDLIndex index : table.getIndexes())
         {
             if (index.getField().equals(field.getName()))
             {
                 DDLAction newAction = new DDLAction(.);
                 newAction.setIndex(index);
                 ret.addAll(renderAction(nameConvertersnewAction));
             }
         }
         
         return ret.build();
     }
     
     private Iterable<SQLActionrenderDropColumnActions(NameConverters nameConvertersDDLTable tableDDLField field)
     {
         ImmutableList.Builder<SQLActionret = ImmutableList.builder();
         
         for (DDLIndex index : table.getIndexes())
         {
             if (index.getField().equals(field.getName()))
             {
                 DDLAction newAction = new DDLAction(.);
                 newAction.setIndex(index);
                 ret.addAll(renderAction(nameConvertersnewAction));
             }
         }
 
         ret.addAll(renderAlterTableDropColumn(nameConverterstablefield));
         
         return ret.build();
     }
    
    

Top level delegating method for rendering a database-agnostic Query object into its (potentially) database-specific query statement. This method invokes the various renderQuery* methods to construct its output, thus it is doubtful that any subclasses will have to override it. Rather, one of the delegate methods should be considered.

An example of a database-specific query rendering would be the following Query:

Query.select().from(Person.class).limit(10)

On MySQL, this would render to SELECT id FROM people LIMIT 10 However, on SQL Server, this same Query would render as SELECT TOP 10 id FROM people

Parameters:
query The database-agnostic Query object to be rendered in a potentially database-specific way.
converter Used to convert Entity classes into table names.
count If true, render the Query as a SELECT COUNT(*) rather than a standard field-data query.
Returns:
A syntactically complete SQL statement potentially specific to the database.
See also:
renderQuerySelect(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean)
renderQueryJoins(net.java.ao.Query,net.java.ao.schema.TableNameConverter)
renderQueryWhere(net.java.ao.Query)
renderQueryGroupBy(net.java.ao.Query)
renderQueryOrderBy(net.java.ao.Query)
renderQueryLimit(net.java.ao.Query)
 
     public String renderQuery(Query queryTableNameConverter converterboolean count)
     {
         StringBuilder sql = new StringBuilder();
 
         sql.append(renderQuerySelect(queryconvertercount));
         sql.append(renderQueryJoins(queryconverter));
         sql.append(renderQueryWhere(query));
         sql.append(renderQueryGroupBy(query));
         sql.append(renderQueryOrderBy(query));
         sql.append(renderQueryLimit(query));
 
         return sql.toString();
     }

    

Parses the database-agnostic String value relevant to the specified SQL type in int form (as defined by java.sql.Types and returns the Java value which corresponds. This method is completely database-agnostic, as are all of all of its delegate methods.

WARNING: This method is being considered for removal to another class (perhaps net.java.ao.types.TypeManager?) as it is not a database-specific function and thus confuses the purpose of this class. Do not rely upon it heavily. (better yet, don't rely on it at all from external code. It's not designed to be part of the public API)

Parameters:
type The JDBC integer type of the database field against which to parse the value.
value The database-agnostic String value to parse into a proper Java object with respect to the specified SQL type.
Returns:
A Java value which corresponds to the specified String.
 
     public Object parseValue(int typeString value)
     {
         if (value == null || value.equals("NULL"))
         {
             return null;
         }
         try
         {
             switch (type)
             {
                 case .:
                     return Long.parseLong(value);
 
                 case .:
                     try
                     {
                         return Byte.parseByte(value) != 0;
                     }
                     catch (Throwable t)
                     {
                         return Boolean.parseBoolean(value);
                     }
                 case .:
                     try
                     {
                         return Integer.parseInt(value) != 0;
                     }
                     catch (Throwable t)
                     {
                         return Boolean.parseBoolean(value);
                     }
                 case .:
                     value.charAt(0);
                     break;
 
                 case .:
                     try
                     {
                         return new SimpleDateFormat(getDateFormat()).parse(value);
                     }
                     catch (ParseException e)
                     {
                         return null;
                     }
 
                 case .:
                     return Double.parseDouble(value);
 
                 case .:
                     return Double.parseDouble(value);
 
                 case .:
                     return Float.parseFloat(value);
 
                 case .:
                     return Integer.parseInt(value);
 
                 case .:
                     return Integer.parseInt(value);
 
                 case .:
                     return Double.parseDouble(value);
 
                 case .:
                     return Short.parseShort(value);
 
                 case .:
                     try
                     {
                         return new SimpleDateFormat(getDateFormat()).parse(value);
                     }
                     catch (ParseException e)
                     {
                         return null;
                     }
 
                 case .:
                     return Short.parseShort(value);
 
                 case .:
                     return value;
             }
         }
         catch (Throwable t)
         {
         }
         return null;
     }

    

Allows the provider to set database-specific options on a java.sql.Statement instance prior to its usage in a SELECT query. This is to allow things like emulation of the LIMIT feature on databases which don't support it within the SQL implementation.

This method is only called on SELECTs.

Parameters:
stmt The instance against which the properties should be set.
query The query which is being executed against the statement instance.
 
     public void setQueryStatementProperties(Statement stmtQuery querythrows SQLException
     {
     }

    
Allows the provider to set database-specific options on a java.sql.ResultSet instance prior to its use by the library. This allows for features such as row offsetting even on databases that don't support it (such as Oracle, Derby, etc).

Parameters:
res The ResultSet to modify.
query The query instance which was run to produce the result set.
 
     public void setQueryResultSetProperties(ResultSet resQuery querythrows SQLException
     {
     }

    

Returns a result set of all of the tables (and associated meta) in the database. The fields of the result set must correspond with those specified in the DatabaseMetaData#getTables(String, String, String, String[]) method. In fact, the default implementation merely calls this method passing (null, null, "", null). For databases (such as PostgreSQL) where this is unsuitable, different parameters can be specified to the getTables method in the override, or an entirely new implementation written, as long as the result set corresponds in fields to the JDBC spec.

Parameters:
conn The connection to use in retrieving the database tables.
Returns:
A result set of tables (and meta) corresponding in fields to the JDBC specification.
See also:
java.sql.DatabaseMetaData.getTables(java.lang.String,java.lang.String,java.lang.String,java.lang.String[])
 
     public ResultSet getTables(Connection connthrows SQLException
     {
         return conn.getMetaData().getTables(null"%"new String[]{"TABLE"});
     }
 
     public ResultSet getSequences(Connection connthrows SQLException
     {
         return conn.getMetaData().getTables(null"%"new String[]{"SEQUENCE"});
     }
 
     public ResultSet getIndexes(Connection connString tableNamethrows SQLException
     {
         return conn.getMetaData().getIndexInfo(nulltableNamefalsefalse);
     }
 
     public ResultSet getImportedKeys(Connection connectionString tableNamethrows SQLException
     {
         return connection.getMetaData().getImportedKeys(nulltableName);
     }

    

Renders the SELECT portion of a given Query instance in the manner required by the database-specific SQL implementation. Usually, this is as simple as "SELECT id FROM table" or "SELECT DISTINCT * FROM table". However, some databases require the limit and offset parameters to be specified as part of the SELECT clause. For example, on HSQLDB, a Query for the "id" field limited to 10 rows would render SELECT like this: SELECT TOP 10 id FROM table.

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the SELECT properties.
converter The name converter to allow conversion of the query entity interface into a proper table name.
count Whether or not the query should be rendered as a SELECT COUNT(*).
Returns:
The database-specific SQL rendering of the SELECT portion of the query.
 
     protected String renderQuerySelect(Query queryTableNameConverter converterboolean count)
     {
         StringBuilder sql = new StringBuilder();
         switch (query.getType())
         {
             case :
                 sql.append("SELECT ");
                 if (query.isDistinct())
                 {
                     sql.append("DISTINCT ");
                 }
 
                 if (count)
                 {
                     sql.append("COUNT(*)");
                 }
                 else
                 {
                     sql.append(querySelectFields(queryconverter));
                 }
                 sql.append(" FROM ").append(queryTableName(queryconverter));
                 break;
         }
 
         return sql.toString();
     }
 
     protected final String queryTableName(Query queryTableNameConverter converter)
     {
         final String queryTable = query.getTable();
         final String tableName = queryTable != null ? queryTable : converter.getName(query.getTableType());
 
         final StringBuilder queryTableName = new StringBuilder().append(withSchema(tableName));
         if (query.getAlias(query.getTableType()) != null)
         {
             queryTableName.append(" ").append(query.getAlias(query.getTableType()));
         }
         return queryTableName.toString();
     }
 
     protected final String querySelectFields(final Query queryfinal TableNameConverter converter)
     {
         return Joiner.on(',').join(transform(query.getFields(), new Function<StringString>()
         {
             @Override
             public String apply(String fieldName)
             {
                 return withAlias(queryfieldNameconverter);
             }
         }));
     }
 
     private String withAlias(Query queryString fieldfinal TableNameConverter converter)
     {
         final StringBuilder withAlias = new StringBuilder();
         if (query.getAlias(query.getTableType()) != null)
         {
             withAlias.append(query.getAlias(query.getTableType())).append(".");
         } else if (!query.getJoins().isEmpty())
         {
             String queryTable = query.getTable();
             withAlias.append((queryTable != null ? queryTable : converter.getName(query.getTableType()))).append(".");
         }
         return withAlias.append(processID(field)).toString();
     }

    

Renders the JOIN portion of the query in the database-specific SQL dialect. Very few databases deviate from the standard in this matter, thus the default implementation is usually sufficient.

An example return value: " JOIN table1 ON table.id = table1.value"

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the JOIN properties.
converter The name converter to allow conversion of the query entity interface into a proper table name.
Returns:
The database-specific SQL rendering of the JOIN portion of the query.
 
     protected String renderQueryJoins(Query queryTableNameConverter converter)
     {
         final StringBuilder sql = new StringBuilder();
 
         for (Map.Entry<Class<? extends RawEntity<?>>, StringjoinEntry : query.getJoins().entrySet())
         {
             sql.append(" JOIN ").append(withSchema(converter.getName(joinEntry.getKey())));
             if (query.getAlias(joinEntry.getKey()) != null)
             {
                 sql.append(" ").append(query.getAlias(joinEntry.getKey()));
             }
             if (joinEntry.getValue() != null)
             {
                 sql.append(" ON ").append(processOnClause(joinEntry.getValue()));
             }
         }
         return sql.toString();
     }

    

Renders the WHERE portion of the query in the database-specific SQL dialect. Very few databases deviate from the standard in this matter, thus the default implementation is usually sufficient.

An example return value: " WHERE name = ? OR age < 20"

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the WHERE properties.
Returns:
The database-specific SQL rendering of the WHERE portion of the query.
 
     protected String renderQueryWhere(Query query)
     {
         StringBuilder sql = new StringBuilder();
 
         String whereClause = query.getWhereClause();
         if (whereClause != null)
         {
             sql.append(" WHERE ");
             sql.append(processWhereClause(whereClause));
         }
 
         return sql.toString();
     }

    

Renders the GROUP BY portion of the query in the database-specific SQL dialect. Very few databases deviate from the standard in this matter, thus the default implementation is usually sufficient.

An example return value: " GROUP BY name"

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the GROUP BY properties.
Returns:
The database-specific SQL rendering of the GROUP BY portion of the query.
 
     protected String renderQueryGroupBy(Query query)
     {
         StringBuilder sql = new StringBuilder();
 
         String groupClause = query.getGroupClause();
         if (groupClause != null)
         {
             sql.append(" GROUP BY ");
             sql.append(processGroupByClause(groupClause));
         }
 
         return sql.toString();
     }
 
     private String processGroupByClause(String groupBy)
     {
         return SqlUtils.processGroupByClause(groupBynew Function<StringString>()
         {
             @Override
             public String apply(String field)
             {
                 return processID(field);
             }
         });
     }

    

Renders the ORDER BY portion of the query in the database-specific SQL dialect. Very few databases deviate from the standard in this matter, thus the default implementation is usually sufficient.

An example return value: " ORDER BY name ASC"

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the ORDER BY properties.
Returns:
The database-specific SQL rendering of the ORDER BY portion of the query.
 
     protected String renderQueryOrderBy(Query query)
     {
         StringBuilder sql = new StringBuilder();
 
         String orderClause = query.getOrderClause();
         if (orderClause != null)
         {
             sql.append(" ORDER BY ");
             sql.append(processOrderClause(orderClause));
         }
 
         return sql.toString();
     }
 
     public final String processOrderClause(String order)
     {
         final Matcher matcher = .matcher(order);
         final StringBuffer sql = new StringBuffer();
         while(matcher.find())
         {
             final StringBuilder repl = new StringBuilder();
 
             // $1 signifies the (optional) table name to potentially quote
             if (matcher.group(1) != null)
             {
                 repl.append(processID("$1"));
                 repl.append(".");
             }
 
             // $2 signifies the (mandatory) column name to potentially quote
             repl.append(processID("$2"));
 
             // $3 signifies the (optional) ASC/DESC option
             if (matcher.group(3) != null)
             {
                 repl.append(" $3");
             }
 
             matcher.appendReplacement(sqlrepl.toString());
         }
         matcher.appendTail(sql);
         return sql.toString();
     }

    

Renders the LIMIT portion of the query in the database-specific SQL dialect. There is wide variety in database implementations of this particular SQL clause. In fact, many database do not support it at all.

Unfortunately, we live in the real world of proprietary database implementations that requires us to use database specific keywords or semantics to achieve these outcomes. Appropriate methods should be overridden in such cases.

An example return value: " LIMIT 10,2"

There is usually no need to call this method directly. Under normal operations it functions as a delegate for renderQuery(net.java.ao.Query,net.java.ao.schema.TableNameConverter,boolean).

Parameters:
query The Query instance from which to determine the LIMIT properties.
Returns:
The database-specific SQL rendering of the LIMIT portion of the query.
 
     protected String renderQueryLimit(Query query)
     {
         StringBuilder sql = new StringBuilder();
 
         int limit = query.getLimit();
         if (limit >= 0)
         {
             sql.append(" LIMIT ");
             sql.append(limit);
         }
 
         int offset = query.getOffset();
         if (offset > 0)
         {
             sql.append(" OFFSET ").append(offset);
         }
 
         return sql.toString();
     }

    

Retrieves a JDBC java.sql.Connection instance which corresponds to the database represented by the provider instance. This Connection can be used to execute arbitrary JDBC operations against the database. Also, this is the method used by the whole of ActiveObjects itself to get database connections when required.

All java.sql.Connection instances are pooled internally by thread. Thus, there is never more than one connection per thread. This is necessary to allow arbitrary JDBC operations within a transaction without breaking transaction integrity. Developers using this method should bear this fact in mind and consider the java.sql.Connection instance immutable. The only exception is if one is absolutely certain that the JDBC code in question is not being executed within a transaction.

Despite the fact that there is only a single connection per thread, the java.sql.Connection instances returned from this method should still be treated as bona fide JDBC connections. They can and should be closed when their usage is complete. This is especially important when actual connection pooling is in use and non-disposal of connections can lead to a crash as the connection pool runs out of resources. The developer need not concern themselves with the single-connection-per-thread issue when closing the connection as the call to close() will be intercepted and ignored if necessary.

Returns:
A new connection to the database
 
     public final Connection getConnection() throws SQLException
     {
         Connection c = .get();
         if (c != null)
         {
             if (!c.isClosed())
             {
                 return c;
             }
             else
             {
                 .remove(); // remove the reference to the connection
             }
         }
 
         final Connection connectionImpl = .getConnection();
         if (connectionImpl == null)
         {
             throw new SQLException("Unable to create connection");
         }
 
         c = DelegateConnectionHandler.newInstance(connectionImpl);
         setPostConnectionProperties(c);
         return c;
     }
 
     public final Connection startTransaction() throws SQLException
     {
         final Connection c = getConnection();
 
         setCloseable(cfalse);
         c.setAutoCommit(false);
 
         .set(c);
 
         return c;
     }
 
     public final Connection commitTransaction(Connection cthrows SQLException
     {
         checkState(c == .get(), "There are two concurrently open transactions!");
         checkState(c != null"Tried to commit a transaction that is not started!");
 
         c.commit();
 
         .remove();
         return c;
     }
 
     public final void rollbackTransaction(Connection cthrows SQLException
     {
         checkState(c == .get(), "There are two concurrently open transactions!");
         checkState(c != null"Tried to rollback a transaction that is not started!");
 
         c.rollback();
     }
 
     void setCloseable(Connection connectionboolean closeable)
     {
         if (connection != null && connection instanceof DelegateConnection)
         {
             ((DelegateConnectionconnection).setCloseable(closeable);
         }
     }

    
Frees any resources held by the database provider or delegate libraries (such as connection pools). This method should be once usage of the provider is complete to ensure that all connections are committed and closed.
 
     public void dispose()
     {
         .dispose();
     }

    
Called to make any post-creation modifications to a new java.sql.Connection instance. This is used for databases such as Derby which require the schema to be set after the connection is created.

Parameters:
conn The connection to modify according to the database requirements.
 
     protected void setPostConnectionProperties(Connection connthrows SQLException
     {
     }

    
Renders the foreign key constraints in database-specific DDL for the table in question. Actually, this method only loops through the foreign keys and renders indentation and line-breaks. The actual rendering is done in a second delegate method.

Parameters:
uniqueNameConverter
table The database-agnostic DDL representation of the table in question.
Returns:
The String rendering of all of the foreign keys for the table.
See also:
renderForeignKey(net.java.ao.schema.ddl.DDLForeignKey)
 
     protected String renderConstraintsForTable(UniqueNameConverter uniqueNameConverterDDLTable table)
     {
         StringBuilder back = new StringBuilder();
 
         for (DDLForeignKey key : table.getForeignKeys())
         {
             back.append("    ").append(renderForeignKey(key)).append(",\n");
         }
 
         return back.toString();
     }

    
Renders the specified foreign key representation into the database-specific DDL. The implementation must name the foreign key according to the DDLForeignKey#getFKName() value otherwise migrations will no longer function appropriately.

Parameters:
key The database-agnostic foreign key representation.
Returns:
The database-pecific DDL fragment corresponding to the foreign key in question.
 
     protected String renderForeignKey(DDLForeignKey key)
     {
         StringBuilder back = new StringBuilder();
 
         back.append("CONSTRAINT ").append(processID(key.getFKName()));
         back.append(" FOREIGN KEY (").append(processID(key.getField())).append(") REFERENCES ");
         back.append(withSchema(key.getTable())).append('(').append(processID(key.getForeignField())).append(")");
        return back.toString();
    }

    
Converts the specified type into the database-specific DDL String value. By default, this delegates to the DatabaseType#getDefaultName() method. Subclass implementations should be sure to make a super call in order to ensure that both default naming and future special cases are handled appropriately.

Parameters:
type The type instance to convert to a DDL string.
Returns:
The database-specific DDL representation of the type (e.g. "VARCHAR").
    protected String convertTypeToString(TypeInfo<?> type)
    {
        return type.getSqlTypeIdentifier();
    }

    
Renders the specified table representation into the corresponding database-specific DDL statement. For legacy reasons, this only allows single-statement table creation. Additional statements (triggers, functions, etc) must be created in one of the other delegate methods for DDL creation. This method does a great deal of delegation to other DatabaseProvider methods for functions such as field rendering, foreign key rendering, etc.

Parameters:
nameConverters
table The database-agnostic table representation.
Returns:
The database-specific DDL statements which correspond to the specified table creation.
    protected final SQLAction renderTable(NameConverters nameConvertersDDLTable table)
    {
        StringBuilder back = new StringBuilder("CREATE TABLE ");
        back.append(withSchema(table.getName()));
        back.append(" (\n");
        List<StringprimaryKeys = new LinkedList<String>();
        StringBuilder append = new StringBuilder();
        for (DDLField field : table.getFields())
        {
            back.append("    ").append(renderField(nameConverterstablefieldnew RenderFieldOptions(truetruetrue))).append(",\n");
            if (field.isPrimaryKey())
            {
                primaryKeys.add(field.getName());
            }
        }
        append.append(renderConstraintsForTable(nameConverters.getUniqueNameConverter(), table));
        back.append(append);
        if (primaryKeys.size() > 1)
        {
            throw new RuntimeException("Entities may only have one primary key");
        }
        if (primaryKeys.size() > 0)
        {
            back.append(renderPrimaryKey(table.getName(), primaryKeys.get(0)));
        }
        back.append(")");
        String tailAppend = renderAppend();
        if (tailAppend != null)
        {
            back.append(' ');
            back.append(tailAppend);
        }
        return SQLAction.of(back);
    }
    protected String renderPrimaryKey(String tableNameString pkFieldName)
    {
        StringBuilder b = new StringBuilder();
        b.append("    PRIMARY KEY(");
        b.append(processID(pkFieldName));
        b.append(")\n");
        return b.toString();
    }
    protected SQLAction renderInsert(DDLTable ddlTableDDLValue[] ddlValues)
    {
        final StringBuilder columns = new StringBuilder();
        final StringBuilder values = new StringBuilder();
        for (DDLValue v : ddlValues)
        {
            columns.append(processID(v.getField().getName())).append(",");
            values.append(renderValue(v.getValue())).append(",");
        }
        columns.deleteCharAt(columns.length() - 1);
        values.deleteCharAt(values.length() - 1);
        return SQLAction.of(new StringBuilder()
                .append("INSERT INTO ").append(withSchema(ddlTable.getName()))
                .append("(").append(columns).append(")")
                .append(" VALUES (").append(values).append(")"));
    }

    
Generates the appropriate database-specific DDL statement to drop the specified table representation. The default implementation is merely "DROP TABLE tablename". This is suitable for every database that I am aware of. Any dependent database objects (such as triggers, functions, etc) must be rendered in one of the other delegate methods (such as renderDropTriggers(DDLTable)).

Parameters:
table The table representation which is to be dropped.
Returns:
A database-specific DDL statement which drops the specified table.
    protected SQLAction renderDropTableStatement(DDLTable table)
    {
        return SQLAction.of("DROP TABLE " + withSchema(table.getName()));
    }

    

Generates the database-specific DDL statements required to create all of the functions, sequences, and triggers necessary for the given table, by calling renderAccessoriesForField(net.java.ao.schema.NameConverters,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField) for each of the table's fields. Each returned net.java.ao.schema.ddl.SQLAction has a correspondingundo action that deletes the corresponding function, sequence, or trigger.

Parameters:
nameConverters
table The table for which the objects must be generated.
Returns:
An ordered list of net.java.ao.schema.ddl.SQLActions.
    protected final Iterable<SQLActionrenderAccessories(final NameConverters nameConvertersfinal DDLTable table)
    {
        return renderFields(
                table,
                Predicates.<DDLField>alwaysTrue(),
                new Function<DDLFieldIterable<SQLAction>>()
                {
                    @Override
                    public Iterable<SQLActionapply(DDLField field)
                    {
                        return renderAccessoriesForField(nameConverterstablefield);
                    }
                });
    }

    

Generates the database-specific DDL statements required to drop all of the functions, sequences, and triggers associated with the given table, by calling renderDropAccessoriesForField(net.java.ao.schema.NameConverters,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField) for each of the table's fields.

Parameters:
nameConverters
table The table for which the objects must be dropped.
Returns:
An ordered list of net.java.ao.schema.ddl.SQLActions.
    protected final Iterable<SQLActionrenderDropAccessories(final NameConverters nameConvertersfinal DDLTable table)
    {
        return renderFields(
                table,
                Predicates.<DDLField>alwaysTrue(),
                new Function<DDLFieldIterable<SQLAction>>()
                {
                    @Override
                    public Iterable<SQLActionapply(DDLField field)
                    {
                        return renderDropAccessoriesForField(nameConverterstablefield);
                    }
                });
    }

    
Generates database-specific DDL statements required to create any functions, sequences, or triggers required for the given field. Each returned net.java.ao.schema.ddl.SQLAction should have a corresponding undo action that deletes the corresponding function, sequence, or trigger. The default implementation returns an empty list.

Parameters:
nameConverters
table
field
Returns:
an ordered list of net.java.ao.schema.ddl.SQLActions
    protected Iterable<SQLActionrenderAccessoriesForField(NameConverters nameConvertersDDLTable tableDDLField field)
    {
        return ImmutableList.of();
    }

    
Generates database-specific DDL statements required to drop any functions, sequences, or triggers associated with the given field. The default implementation returns an empty list.

Parameters:
nameConverters
table
field
Returns:
an ordered list of net.java.ao.schema.ddl.SQLActions
    protected Iterable<SQLActionrenderDropAccessoriesForField(NameConverters nameConvertersDDLTable tableDDLField field)
    {
        return ImmutableList.of();
    }
    
    protected final Iterable<SQLActionrenderFields(DDLTable tablePredicate<DDLFieldfilterFunction<DDLFieldIterable<SQLAction>> render)
    {
        final Iterable<DDLFieldfields = Lists.newArrayList(table.getFields());
        return concat(transform(filter(fieldsfilter), render));
    }

    
Generates the database-specific DDL statements required to add a column to an existing table. Included in the return value should be the statements required to add all necessary functions and triggers to ensure that the column acts appropriately. For example, if the field is tagged with an @OnUpdate annotation, chances are there will be a trigger and possibly a function along with the ALTER statement. These "extra" functions are properly ordered and will only be appended if their values are not null. Because of this, very few database providers will need to override this method.

Each net.java.ao.schema.ddl.SQLAction should have a corresponding undo action; these will be executed in reverse order if the action needs to be rolled back.

    protected Iterable<SQLActionrenderAlterTableAddColumn(NameConverters nameConvertersDDLTable tableDDLField field)
    {
        ImmutableList.Builder<SQLActionback = ImmutableList.builder();
        back.add(renderAlterTableAddColumnStatement(nameConverterstablefield)
                 .withUndoAction(renderAlterTableDropColumnStatement(tablefield)));
        for (DDLForeignKey foreignKey : findForeignKeysForField(tablefield))
        {
            back.add(renderAlterTableAddKey(foreignKey).withUndoAction(renderAlterTableDropKey(foreignKey)));
        }
        back.addAll(renderAccessoriesForField(nameConverterstablefield));
        return back.build();
    }

    
Generates the database-specific DDL statement for adding a column, but not including any corresponding sequences, triggers, etc.

Parameters:
nameConverters
table The table which should receive the new column.
field The column to add to the specified table.
Returns:
A DDL statements to execute.
    protected SQLAction renderAlterTableAddColumnStatement(NameConverters nameConvertersDDLTable tableDDLField field)
    {
        String addStmt = "ALTER TABLE " + withSchema(table.getName()) + " ADD COLUMN " + renderField(nameConverterstablefieldnew RenderFieldOptions(truetruetrue));
        return SQLAction.of(addStmt);
    }
    
    

Generates the database-specific DDL statements required to change the given column from its old specification to the given DDL value. This method will also generate the appropriate statements to remove old triggers and functions, as well as add new ones according to the requirements of the new field definition.

The default implementation of this method functions in the manner specified by the MySQL database. Some databases will have to perform more complicated actions (such as dropping and re-adding the field) in order to satesfy the same use-case. Such databases should print a warning to stderr to ensure that the end-developer is aware of such restrictions.

Thus, the specification for this method allows for data loss. Nevertheless, if the database supplies a mechanism to accomplish the task without data loss, it should be applied.

For maximum flexibility, the default implementation of this method only deals with the dropping and addition of functions and triggers. The actual generation of the ALTER TABLE statement is done in the renderAlterTableChangeColumnStatement(net.java.ao.schema.NameConverters,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField,net.java.ao.schema.ddl.DDLField,net.java.ao.DatabaseProvider.RenderFieldOptions) method.

    protected Iterable<SQLActionrenderAlterTableChangeColumn(NameConverters nameConvertersDDLTable tableDDLField oldFieldDDLField field)
    {
        final ImmutableList.Builder<SQLActionback = ImmutableList.builder();
        back.addAll(renderDropAccessoriesForField(nameConverterstableoldField));
        back.add(renderAlterTableChangeColumnStatement(nameConverterstableoldFieldfieldrenderFieldOptionsInAlterColumn()));
        back.addAll(renderAccessoriesForField(nameConverterstablefield));
        return back.build();
    }
    {
        return new RenderFieldOptions(truetruetruetrue);
    }

    
Generates the database-specific DDL statement only for altering a table and changing a column. This method must only generate a single statement as it does not need to concern itself with functions or triggers associated with the column. This method is only to be called as a delegate for the renderAlterTableChangeColumn(net.java.ao.schema.NameConverters,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField,net.java.ao.schema.ddl.DDLField) method, for which it is a primary delegate. The default implementation of this method functions according to the MySQL specification.

Parameters:
nameConverters
table The table containing the column to change.
oldField The old column definition.
field The new column definition (defining the resultant DDL).
options
Returns:
A single DDL statement which is to be executed.
See also:
renderField(net.java.ao.schema.NameConverters,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField,net.java.ao.DatabaseProvider.RenderFieldOptions)
    protected SQLAction renderAlterTableChangeColumnStatement(NameConverters nameConvertersDDLTable tableDDLField oldFieldDDLField fieldRenderFieldOptions options)
    {
        StringBuilder current = new StringBuilder();
        current.append("ALTER TABLE ").append(withSchema(table.getName())).append(" CHANGE COLUMN ");
        current.append(processID(oldField.getName())).append(' ');
        current.append(renderField(nameConverterstablefieldoptions));
        return SQLAction.of(current);
    }

    
Generates the database-specific DDL statements required to remove the specified column from the given table. This should also generate the necessary statements to drop all triggers and functions associated with the column in question. If the database being implemented has a non-standard syntax for dropping functions and/or triggers, it may be required to override this method, even if the syntax to drop columns is standard.

Parameters:
nameConverters
table The table from which to drop the column.
field The column definition to remove from the table.
Returns:
An array of DDL statements to be executed.
See also:
getTriggerNameForField(net.java.ao.schema.TriggerNameConverter,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField)
getFunctionNameForField(net.java.ao.schema.TriggerNameConverter,net.java.ao.schema.ddl.DDLTable,net.java.ao.schema.ddl.DDLField)
    protected Iterable<SQLActionrenderAlterTableDropColumn(NameConverters nameConvertersDDLTable tableDDLField field)
    {
        ImmutableList.Builder<SQLActionback = ImmutableList.builder();
        
        for (DDLForeignKey foreignKey : findForeignKeysForField(tablefield))
        {
            back.add(renderAlterTableDropKey(foreignKey));
        }
        back.addAll(renderDropAccessoriesForField(nameConverterstablefield));
        back.add(renderAlterTableDropColumnStatement(tablefield));
        return back.build();
    }
    {
        String dropStmt = "ALTER TABLE " + withSchema(table.getName()) + " DROP COLUMN " + processID(field.getName());
        return SQLAction.of(dropStmt);
    }
    
    
Generates the database-specific DDL statement required to add a foreign key to a table. For databases which do not support such a statement, a warning should be printed to stderr and a null value returned.

Parameters:
key The foreign key to be added. As this instance contains all necessary data (such as domestic table, field, etc), no additional parameters are required.
Returns:
A DDL statement to be executed, or null.
See also:
renderForeignKey(net.java.ao.schema.ddl.DDLForeignKey)
    {
        return SQLAction.of("ALTER TABLE " + withSchema(key.getDomesticTable()) + " ADD " + renderForeignKey(key));
    }

    
Generates the database-specific DDL statement required to remove a foreign key from a table. For databases which do not support such a statement, a warning should be printed to stderr and a null value returned. This method assumes that the renderForeignKey(net.java.ao.schema.ddl.DDLForeignKey) method properly names the foreign key according to the net.java.ao.schema.ddl.DDLForeignKey.getFKName() method.

Parameters:
key The foreign key to be removed. As this instance contains all necessary data (such as domestic table, field, etc), no additional parameters are required.
Returns:
A DDL statement to be executed, or null.
    {
        return SQLAction.of("ALTER TABLE " + withSchema(key.getDomesticTable()) + " DROP FOREIGN KEY " + processID(key.getFKName()));
    }

    
Generates the database-specific DDL statement required to create a new index. The syntax for this operation is highly standardized and thus it is unlikely this method will be overridden. If the database in question does not support indexes, a warning should be printed to stderr and null returned.

Parameters:
indexNameConverter
index The index to create. This single instance contains all of the data necessary to create the index, thus no separate parameters (such as a DDLTable) are required.
Returns:
A DDL statement to be executed.
    protected SQLAction renderCreateIndex(IndexNameConverter indexNameConverterDDLIndex index)
    {
        return SQLAction.of("CREATE INDEX " + withSchema(indexNameConverter.getName(shorten(index.getTable()), shorten(index.getField())))
                                   + " ON " + withSchema(index.getTable()) + "(" + processID(index.getField()) + ")");
    }

    
Generates the database-specific DDL statement required to drop an index. The syntax for this operation is highly standardized and thus it is unlikely this method will be overridden. If the database in question does not support indexes, a warning should be printed to stderr and null returned.

Parameters:
indexNameConverter
index The index to drop. This single instance contains all of the data necessary to drop the index, thus no separate parameters (such as a DDLTable) are required.
Returns:
A DDL statement to be executed, or null.
    protected SQLAction renderDropIndex(IndexNameConverter indexNameConverterDDLIndex index)
    {
        final String indexName = getExistingIndexName(indexNameConverterindex);
        final String tableName = index.getTable();
        if (hasIndex(tableName,indexName))
        {
            return SQLAction.of("DROP INDEX " + withSchema(indexName) + " ON " + withSchema(tableName));
        }
        else
        {
            return null;
        }
    }
    protected boolean hasIndex(IndexNameConverter indexNameConverterDDLIndex index)
    {
        final String indexName = indexNameConverter.getName(shorten(index.getTable()), shorten(index.getField()));
        return hasIndex(index.getTable(),indexName);
    }
    protected String getExistingIndexName(IndexNameConverter indexNameConverterDDLIndex index)
    {
        if (index.getIndexName() != null)
        {
            return index.getIndexName();
        }
        else
        {
            return indexNameConverter.getName(shorten(