Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » tool » hbm2ddl » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.tool.hbm2ddl;
   26   
   27   import java.io.BufferedReader;
   28   import java.io.File;
   29   import java.io.FileInputStream;
   30   import java.io.FileWriter;
   31   import java.io.IOException;
   32   import java.io.InputStream;
   33   import java.io.InputStreamReader;
   34   import java.io.Reader;
   35   import java.io.Writer;
   36   import java.sql.Connection;
   37   import java.sql.SQLException;
   38   import java.sql.SQLWarning;
   39   import java.sql.Statement;
   40   import java.util.ArrayList;
   41   import java.util.List;
   42   import java.util.Properties;
   43   
   44   import org.slf4j.Logger;
   45   import org.slf4j.LoggerFactory;
   46   
   47   import org.hibernate.HibernateException;
   48   import org.hibernate.JDBCException;
   49   import org.hibernate.cfg.Configuration;
   50   import org.hibernate.cfg.Environment;
   51   import org.hibernate.cfg.NamingStrategy;
   52   import org.hibernate.cfg.Settings;
   53   import org.hibernate.dialect.Dialect;
   54   import org.hibernate.jdbc.util.FormatStyle;
   55   import org.hibernate.jdbc.util.Formatter;
   56   import org.hibernate.jdbc.util.SQLStatementLogger;
   57   import org.hibernate.util.ConfigHelper;
   58   import org.hibernate.util.JDBCExceptionReporter;
   59   import org.hibernate.util.PropertiesHelper;
   60   import org.hibernate.util.ReflectHelper;
   61   
   62   /**
   63    * Commandline tool to export table schema to the database. This class may also be called from inside an application.
   64    *
   65    * @author Daniel Bradby
   66    * @author Gavin King
   67    */
   68   public class SchemaExport {
   69   
   70   	private static final Logger log = LoggerFactory.getLogger( SchemaExport.class );
   71   
   72   	private ConnectionHelper connectionHelper;
   73   	private String[] dropSQL;
   74   	private String[] createSQL;
   75   	private String outputFile = null;
   76   	private String importFile = "/import.sql";
   77   	private Dialect dialect;
   78   	private String delimiter;
   79   	private final List exceptions = new ArrayList();
   80   	private boolean haltOnError = false;
   81   	private Formatter formatter;
   82   	private SQLStatementLogger sqlStatementLogger;
   83   
   84   	/**
   85   	 * Create a schema exporter for the given Configuration
   86   	 *
   87   	 * @param cfg The configuration from which to build a schema export.
   88   	 * @throws HibernateException Indicates problem preparing for schema export.
   89   	 */
   90   	public SchemaExport(Configuration cfg) throws HibernateException {
   91   		this( cfg, cfg.getProperties() );
   92   	}
   93   
   94   	/**
   95   	 * Create a schema exporter for the given Configuration and given settings
   96   	 *
   97   	 * @param cfg The configuration from which to build a schema export.
   98   	 * @param settings The 'parsed' settings.
   99   	 * @throws HibernateException Indicates problem preparing for schema export.
  100   	 */
  101   	public SchemaExport(Configuration cfg, Settings settings) throws HibernateException {
  102   		dialect = settings.getDialect();
  103   		connectionHelper = new SuppliedConnectionProviderConnectionHelper( settings.getConnectionProvider() );
  104   		dropSQL = cfg.generateDropSchemaScript( dialect );
  105   		createSQL = cfg.generateSchemaCreationScript( dialect );
  106   		sqlStatementLogger = settings.getSqlStatementLogger();
  107   		formatter = ( sqlStatementLogger.isFormatSql() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
  108   	}
  109   
  110   	/**
  111   	 * Create a schema exporter for the given Configuration, with the given
  112   	 * database connection properties.
  113   	 *
  114   	 * @param cfg The configuration from which to build a schema export.
  115   	 * @param properties The properties from which to configure connectivity etc.
  116   	 * @throws HibernateException Indicates problem preparing for schema export.
  117   	 *
  118   	 * @deprecated properties may be specified via the Configuration object
  119   	 */
  120   	public SchemaExport(Configuration cfg, Properties properties) throws HibernateException {
  121   		dialect = Dialect.getDialect( properties );
  122   
  123   		Properties props = new Properties();
  124   		props.putAll( dialect.getDefaultProperties() );
  125   		props.putAll( properties );
  126   
  127   		connectionHelper = new ManagedProviderConnectionHelper( props );
  128   		dropSQL = cfg.generateDropSchemaScript( dialect );
  129   		createSQL = cfg.generateSchemaCreationScript( dialect );
  130   
  131   		formatter = ( PropertiesHelper.getBoolean( Environment.FORMAT_SQL, props ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
  132   	}
  133   
  134   	/**
  135   	 * Create a schema exporter for the given Configuration, using the supplied connection for connectivity.
  136   	 *
  137   	 * @param cfg The configuration to use.
  138   	 * @param connection The JDBC connection to use.
  139   	 * @throws HibernateException Indicates problem preparing for schema export.
  140   	 */
  141   	public SchemaExport(Configuration cfg, Connection connection) throws HibernateException {
  142   		this.connectionHelper = new SuppliedConnectionHelper( connection );
  143   		dialect = Dialect.getDialect( cfg.getProperties() );
  144   		dropSQL = cfg.generateDropSchemaScript( dialect );
  145   		createSQL = cfg.generateSchemaCreationScript( dialect );
  146   		formatter = ( PropertiesHelper.getBoolean( Environment.FORMAT_SQL, cfg.getProperties() ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
  147   	}
  148   
  149   	/**
  150   	 * For generating a export script file, this is the file which will be written.
  151   	 *
  152   	 * @param filename The name of the file to which to write the export script.
  153   	 * @return this
  154   	 */
  155   	public SchemaExport setOutputFile(String filename) {
  156   		outputFile = filename;
  157   		return this;
  158   	}
  159   
  160   	/**
  161   	 * An import file, containing raw SQL statements to be executed.
  162   	 *
  163   	 * @param filename The import file name.
  164   	 * @return this
  165   	 */
  166   	public SchemaExport setImportFile(String filename) {
  167   		importFile = filename;
  168   		return this;
  169   	}
  170   
  171   	/**
  172   	 * Set the end of statement delimiter
  173   	 *
  174   	 * @param delimiter The delimiter
  175   	 * @return this
  176   	 */
  177   	public SchemaExport setDelimiter(String delimiter) {
  178   		this.delimiter = delimiter;
  179   		return this;
  180   	}
  181   
  182   	/**
  183   	 * Should we format the sql strings?
  184   	 *
  185   	 * @param format Should we format SQL strings
  186   	 * @return this
  187   	 */
  188   	public SchemaExport setFormat(boolean format) {
  189   		this.formatter = ( format ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
  190   		return this;
  191   	}
  192   
  193   	/**
  194   	 * Should we stop once an error occurs?
  195   	 *
  196   	 * @param haltOnError True if export should stop after error.
  197   	 * @return this
  198   	 */
  199   	public SchemaExport setHaltOnError(boolean haltOnError) {
  200   		this.haltOnError = haltOnError;
  201   		return this;
  202   	}
  203   
  204   	/**
  205   	 * Run the schema creation script.
  206   	 *
  207   	 * @param script print the DDL to the console
  208   	 * @param export export the script to the database
  209   	 */
  210   	public void create(boolean script, boolean export) {
  211   		execute( script, export, false, false );
  212   	}
  213   
  214   	/**
  215   	 * Run the drop schema script.
  216   	 *
  217   	 * @param script print the DDL to the console
  218   	 * @param export export the script to the database
  219   	 */
  220   	public void drop(boolean script, boolean export) {
  221   		execute( script, export, true, false );
  222   	}
  223   
  224   	public void execute(boolean script, boolean export, boolean justDrop, boolean justCreate) {
  225   
  226   		log.info( "Running hbm2ddl schema export" );
  227   
  228   		Connection connection = null;
  229   		Writer outputFileWriter = null;
  230   		Reader importFileReader = null;
  231   		Statement statement = null;
  232   
  233   		exceptions.clear();
  234   
  235   		try {
  236   
  237   			try {
  238   				InputStream stream = ConfigHelper.getResourceAsStream( importFile );
  239   				importFileReader = new InputStreamReader( stream );
  240   			}
  241   			catch ( HibernateException e ) {
  242   				log.debug( "import file not found: " + importFile );
  243   			}
  244   
  245   			if ( outputFile != null ) {
  246   				log.info( "writing generated schema to file: " + outputFile );
  247   				outputFileWriter = new FileWriter( outputFile );
  248   			}
  249   
  250   			if ( export ) {
  251   				log.info( "exporting generated schema to database" );
  252   				connectionHelper.prepare( true );
  253   				connection = connectionHelper.getConnection();
  254   				statement = connection.createStatement();
  255   			}
  256   
  257   			if ( !justCreate ) {
  258   				drop( script, export, outputFileWriter, statement );
  259   			}
  260   
  261   			if ( !justDrop ) {
  262   				create( script, export, outputFileWriter, statement );
  263   				if ( export && importFileReader != null ) {
  264   					importScript( importFileReader, statement );
  265   				}
  266   			}
  267   
  268   			log.info( "schema export complete" );
  269   
  270   		}
  271   
  272   		catch ( Exception e ) {
  273   			exceptions.add( e );
  274   			log.error( "schema export unsuccessful", e );
  275   		}
  276   
  277   		finally {
  278   
  279   			try {
  280   				if ( statement != null ) {
  281   					statement.close();
  282   				}
  283   				if ( connection != null ) {
  284   					connectionHelper.release();
  285   				}
  286   			}
  287   			catch ( Exception e ) {
  288   				exceptions.add( e );
  289   				log.error( "Could not close connection", e );
  290   			}
  291   
  292   			try {
  293   				if ( outputFileWriter != null ) {
  294   					outputFileWriter.close();
  295   				}
  296   				if ( importFileReader != null ) {
  297   					importFileReader.close();
  298   				}
  299   			}
  300   			catch ( IOException ioe ) {
  301   				exceptions.add( ioe );
  302   				log.error( "Error closing output file: " + outputFile, ioe );
  303   			}
  304   
  305   		}
  306   	}
  307   
  308   	private void importScript(Reader importFileReader, Statement statement)
  309   			throws IOException {
  310   		log.info( "Executing import script: " + importFile );
  311   		BufferedReader reader = new BufferedReader( importFileReader );
  312   		long lineNo = 0;
  313   		for ( String sql = reader.readLine(); sql != null; sql = reader.readLine() ) {
  314   			try {
  315   				lineNo++;
  316   				String trimmedSql = sql.trim();
  317   				if ( trimmedSql.length() == 0 ||
  318   				     trimmedSql.startsWith( "--" ) ||
  319   				     trimmedSql.startsWith( "//" ) ||
  320   				     trimmedSql.startsWith( "/*" ) ) {
  321   					continue;
  322   				}
  323   				else {
  324   					if ( trimmedSql.endsWith( ";" ) ) {
  325   						trimmedSql = trimmedSql.substring( 0, trimmedSql.length() - 1 );
  326   					}
  327   					log.debug( trimmedSql );
  328   					statement.execute( trimmedSql );
  329   				}
  330   			}
  331   			catch ( SQLException e ) {
  332   				throw new JDBCException( "Error during import script execution at line " + lineNo, e );
  333   			}
  334   		}
  335   	}
  336   
  337   	private void create(boolean script, boolean export, Writer fileOutput, Statement statement)
  338   			throws IOException {
  339   		for ( int j = 0; j < createSQL.length; j++ ) {
  340   			try {
  341   				execute( script, export, fileOutput, statement, createSQL[j] );
  342   			}
  343   			catch ( SQLException e ) {
  344   				if ( haltOnError ) {
  345   					throw new JDBCException( "Error during DDL export", e );
  346   				}
  347   				exceptions.add( e );
  348   				log.error( "Unsuccessful: " + createSQL[j] );
  349   				log.error( e.getMessage() );
  350   			}
  351   		}
  352   	}
  353   
  354   	private void drop(boolean script, boolean export, Writer fileOutput, Statement statement)
  355   			throws IOException {
  356   		for ( int i = 0; i < dropSQL.length; i++ ) {
  357   			try {
  358   				execute( script, export, fileOutput, statement, dropSQL[i] );
  359   			}
  360   			catch ( SQLException e ) {
  361   				exceptions.add( e );
  362   				log.debug( "Unsuccessful: " + dropSQL[i] );
  363   				log.debug( e.getMessage() );
  364   			}
  365   		}
  366   	}
  367   
  368   	private void execute(boolean script, boolean export, Writer fileOutput, Statement statement, final String sql)
  369   			throws IOException, SQLException {
  370   		String formatted = formatter.format( sql );
  371   		if ( delimiter != null ) {
  372   			formatted += delimiter;
  373   		}
  374   		if ( script ) {
  375   			System.out.println( formatted );
  376   		}
  377   		log.debug( formatted );
  378   		if ( outputFile != null ) {
  379   			fileOutput.write( formatted + "\n" );
  380   		}
  381   		if ( export ) {
  382   
  383   			statement.executeUpdate( sql );
  384   			try {
  385   				SQLWarning warnings = statement.getWarnings();
  386   				if ( warnings != null) {
  387   					JDBCExceptionReporter.logAndClearWarnings( connectionHelper.getConnection() );
  388   				}
  389   			}
  390   			catch( SQLException sqle ) {
  391   				log.warn( "unable to log SQLWarnings : " + sqle );
  392   			}
  393   		}
  394   
  395   		
  396   	}
  397   
  398   	public static void main(String[] args) {
  399   		try {
  400   			Configuration cfg = new Configuration();
  401   
  402   			boolean script = true;
  403   			boolean drop = false;
  404   			boolean create = false;
  405   			boolean halt = false;
  406   			boolean export = true;
  407   			String outFile = null;
  408   			String importFile = "/import.sql";
  409   			String propFile = null;
  410   			boolean format = false;
  411   			String delim = null;
  412   
  413   			for ( int i = 0; i < args.length; i++ ) {
  414   				if ( args[i].startsWith( "--" ) ) {
  415   					if ( args[i].equals( "--quiet" ) ) {
  416   						script = false;
  417   					}
  418   					else if ( args[i].equals( "--drop" ) ) {
  419   						drop = true;
  420   					}
  421   					else if ( args[i].equals( "--create" ) ) {
  422   						create = true;
  423   					}
  424   					else if ( args[i].equals( "--haltonerror" ) ) {
  425   						halt = true;
  426   					}
  427   					else if ( args[i].equals( "--text" ) ) {
  428   						export = false;
  429   					}
  430   					else if ( args[i].startsWith( "--output=" ) ) {
  431   						outFile = args[i].substring( 9 );
  432   					}
  433   					else if ( args[i].startsWith( "--import=" ) ) {
  434   						importFile = args[i].substring( 9 );
  435   					}
  436   					else if ( args[i].startsWith( "--properties=" ) ) {
  437   						propFile = args[i].substring( 13 );
  438   					}
  439   					else if ( args[i].equals( "--format" ) ) {
  440   						format = true;
  441   					}
  442   					else if ( args[i].startsWith( "--delimiter=" ) ) {
  443   						delim = args[i].substring( 12 );
  444   					}
  445   					else if ( args[i].startsWith( "--config=" ) ) {
  446   						cfg.configure( args[i].substring( 9 ) );
  447   					}
  448   					else if ( args[i].startsWith( "--naming=" ) ) {
  449   						cfg.setNamingStrategy(
  450   								( NamingStrategy ) ReflectHelper.classForName( args[i].substring( 9 ) )
  451   										.newInstance()
  452   						);
  453   					}
  454   				}
  455   				else {
  456   					String filename = args[i];
  457   					if ( filename.endsWith( ".jar" ) ) {
  458   						cfg.addJar( new File( filename ) );
  459   					}
  460   					else {
  461   						cfg.addFile( filename );
  462   					}
  463   				}
  464   
  465   			}
  466   
  467   			if ( propFile != null ) {
  468   				Properties props = new Properties();
  469   				props.putAll( cfg.getProperties() );
  470   				props.load( new FileInputStream( propFile ) );
  471   				cfg.setProperties( props );
  472   			}
  473   
  474   			SchemaExport se = new SchemaExport( cfg )
  475   					.setHaltOnError( halt )
  476   					.setOutputFile( outFile )
  477   					.setImportFile( importFile )
  478   					.setDelimiter( delim );
  479   			if ( format ) {
  480   				se.setFormat( true );
  481   			}
  482   			se.execute( script, export, drop, create );
  483   
  484   		}
  485   		catch ( Exception e ) {
  486   			log.error( "Error creating schema ", e );
  487   			e.printStackTrace();
  488   		}
  489   	}
  490   
  491   	/**
  492   	 * Returns a List of all Exceptions which occured during the export.
  493   	 *
  494   	 * @return A List containig the Exceptions occured during the export
  495   	 */
  496   	public List getExceptions() {
  497   		return exceptions;
  498   	}
  499   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » tool » hbm2ddl » [javadoc | source]