Database

Purpose

liquibase.database.Database implementations are the facade Liquibase uses to access the database.  They contain methods to execute SqlStatements, as well as to standardize database metadata and smooth out cross-database differences. Even non-"databases" such as Hibernate mapping configurations can be exposed to Liquibase via a Database implementation.

Examples

  • Add support for a new database type
  • Modify the way an existing database implementation exposes or interprets metadata

How to Create

The easiest way to create a new liquibase.database.Database implementation is to extend liquibase.database.AbstractDatabase.  If you extend AbstractDatabase, you must implement the following methods:

public boolean isCorrectDatabaseImplementation(Connection conn) throws JDBCException

Returns true if the database implementation is correct for the given connection. 

public String getShortName()

Return a short, lowercase description of the database (e.g. "mysql", "oracle").  Used in error messages, "dbms" attribute, database type preconditions, etc.

public String getDefaultDriver(String url)

If the given URL is understood by your Database, return a default driver.  Used to find the correct JDBC Driver in cases where just a database URL is passed to Liquibase.  If your implementation does not have a driver for the given url, return null.

public abstract DatabaseSnapshot createDatabaseSnapshot(String schema, Set<DiffStatusListener> statusListeners) throws JDBCException

Return a liquibase.structure.DatabaseSnapshot implentation for the given schema.

public String getCurrentDateTimeFunction()

Return a string that can be used to generate the current date time (e.g. "NOW()", "SYSDATE").

public boolean supportsInitiallyDeferrableColumns()

Return true if your database supports deferrable and/or initially deferrable foreign key constraints.  Causes changes that add foreign key constraints marked as deferrable to fail validation.

public boolean supportsTablespaces()   

Return true if your database supports the concept of "tablespaces". Causes changes that specify a tablespace to fail validation.

public DataType getBooleanType()   
public DataType getCurrencyType()   
public DataType getUUIDType()   
public DataType getClobType()   
public DataType getBlobType()   
public DataType getDateTimeType()

Return the correct liquibase.database.DataType instance for the given data type. Used for converting to/from standard data types.

Additional liquibase.database.Database methods available for overriding

Beyond the methods required by AbstractDatabase for implentation, there are many more methods on Database that you may find value in overriding.  See the Javadoc on methods to control object escaping, commit/rollback, and executing SqlStatements.

Registering Custom Databases

There are two ways to register a custom Database:

  1. Create the class in the package "liquibase.database.ext".  Liquibase automatically registers Databases it finds in that package
  2. Call liquibase.database.DatabaseFactory.getInstance().register(yourDatabase)

Threading/Singleton notes

Database implementations should be created thread safe.  Once an instance of a Database is registered, DatabaseFactory will continue to use the return instance.