All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.j256.ormlite.table.TableUtils Maven / Gradle / Ivy

package com.j256.ormlite.table;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.sql.DataSource;

import com.j256.ormlite.db.DatabaseType;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.logger.Logger;
import com.j256.ormlite.logger.LoggerFactory;
import com.j256.ormlite.misc.SqlExceptionUtil;

/**
 * Couple utility methods for the creating, dropping, and maintenance of tables.
 * 
 * @author graywatson
 */
public class TableUtils {

	private static Logger logger = LoggerFactory.getLogger(TableUtils.class);

	/**
	 * For static methods only.
	 */
	private TableUtils() {
	}

	/**
	 * Issue the database statements to create the table associated with a class. Most likely this will be done
	 * only when a database is configured or in unit tests.
	 * 
	 * @param databaseType
	 *            Our database type.
	 * @param dataSource
	 *            Associated {@link DataSource}.
	 * @param dataClass
	 *            The class for which a table will be created.
	 * @return The number of statements executed to do so.
	 */
	public static  int createTable(DatabaseType databaseType, DataSource dataSource, Class dataClass)
			throws SQLException {
		return createTable(databaseType, dataSource, DatabaseTableConfig.fromClass(databaseType, dataClass));
	}

	/**
	 * Issue the database statements to create the table associated with a class. Most likely this will be done
	 * only when a database is configured or in unit tests.
	 * 
	 * @param databaseType
	 *            Our database type.
	 * @param dataSource
	 *            Associated {@link DataSource}.
	 * @param tableConfig
	 *            Hand or spring wired table configuration. If null then the class must have {@link DatabaseField}
	 *            annotations.
	 * @return The number of statements executed to do so.
	 */
	public static  int createTable(DatabaseType databaseType, DataSource dataSource,
			DatabaseTableConfig tableConfig) throws SQLException {
		TableInfo tableInfo = new TableInfo(databaseType, tableConfig);
		logger.debug("creating table '{}'", tableInfo.getTableName());
		List statements = new ArrayList();
		List queriesAfter = new ArrayList();
		createTableStatements(databaseType, tableInfo, statements, queriesAfter);
		int stmtC = 0;
		Connection connection = dataSource.getConnection();
		for (String statement : statements) {
			int rowC;
			PreparedStatement prepStmt = null;
			try {
				logger.debug("executing create table statement: {}", statement);
				prepStmt = connection.prepareStatement(statement);
				rowC = prepStmt.executeUpdate();
			} catch (SQLException e) {
				// we do this to make sure that the statement is in the exception
				throw SqlExceptionUtil.create("SQL statement failed: " + statement, e);
			} finally {
				if (prepStmt != null) {
					prepStmt.close();
				}
			}
			// sanity check
			if (rowC < 0) {
				throw new SQLException("SQL statement updated " + rowC + " rows, we were expecting >= 0: " + statement);
			} else if (rowC > 0 && databaseType.isCreateTableReturnsZero()) {
				throw new SQLException("SQL statement updated " + rowC + " rows, we were expecting == 0: " + statement);
			}

			stmtC++;
		}
		// now execute any test queries which test the newly created table
		for (String query : queriesAfter) {
			PreparedStatement prepStmt = null;
			ResultSet resultSet = null;
			try {
				prepStmt = connection.prepareStatement(query);
				resultSet = prepStmt.executeQuery();
				int rowC = 0;
				// count the results
				while (resultSet.next()) {
					rowC++;
				}
				logger.debug("executing create table after-query got {} results: {}", rowC, query);
			} catch (SQLException e) {
				// we do this to make sure that the statement is in the exception
				throw SqlExceptionUtil.create("executing create table after-query failed: " + query, e);
			} finally {
				// result set is closed by the statement being closed
				if (prepStmt != null) {
					prepStmt.close();
				}
			}
			stmtC++;
		}
		return stmtC;
	}

	/**
	 * Return an ordered collection of SQL statements that need to be run to create a table. To do the work of creating,
	 * you should call {@link #createTable}.
	 * 
	 * @param databaseType
	 *            Our database type.
	 * @param dataClass
	 *            The class for which a table will be created.
	 * @return The collection of table create statements.
	 */
	public static  List getCreateTableStatements(DatabaseType databaseType, Class dataClass)
			throws SQLException {
		return getCreateTableStatements(databaseType, DatabaseTableConfig.fromClass(databaseType, dataClass));
	}

	/**
	 * Return an ordered collection of SQL statements that need to be run to create a table. To do the work of creating,
	 * you should call {@link #createTable}.
	 * 
	 * @param databaseType
	 *            Our database type.
	 * @param tableConfig
	 *            Hand or spring wired table configuration. If null then the class must have {@link DatabaseField}
	 *            annotations.
	 * @return The collection of table create statements.
	 */
	public static  List getCreateTableStatements(DatabaseType databaseType,
			DatabaseTableConfig tableConfig) throws SQLException {
		TableInfo tableInfo = new TableInfo(databaseType, tableConfig);
		List statements = new ArrayList();
		List queriesAfter = new ArrayList();
		createTableStatements(databaseType, tableInfo, statements, queriesAfter);
		return statements;
	}
	/**
	 * Issue the database statements to create the table associated with a class. Most likely this will be done
	 * only in unit tests.
	 * 
	 * 

* WARNING: This is [obviously] very destructive and unrecoverable. *

* * @param databaseType * Our database type. * @param dataSource * Associated {@link DataSource}. * @param dataClass * The class for which a table will be created. * @param ignoreErrors * If set to true then try each statement regardless of {@link SQLException} thrown previously. * @return The number of statements executed to do so. */ public static int dropTable(DatabaseType databaseType, DataSource dataSource, Class dataClass, boolean ignoreErrors) throws SQLException { return dropTable(databaseType, dataSource, DatabaseTableConfig.fromClass(databaseType, dataClass), ignoreErrors); } /** * Issue the database statements to create the table associated with a class. Most likely this will be done * only in unit tests. * *

* WARNING: This is [obviously] very destructive and unrecoverable. *

* * @param databaseType * Our database type. * @param dataSource * Associated {@link DataSource}. * @param tableConfig * Hand or spring wired table configuration. If null then the class must have {@link DatabaseField} * annotations. * @param ignoreErrors * If set to true then try each statement regardless of {@link SQLException} thrown previously. * @return The number of statements executed to do so. */ public static int dropTable(DatabaseType databaseType, DataSource dataSource, DatabaseTableConfig tableConfig, boolean ignoreErrors) throws SQLException { TableInfo tableInfo = new TableInfo(databaseType, tableConfig); logger.debug("dropping table '{}'", tableInfo.getTableName()); Collection statements = dropTableStatements(databaseType, tableInfo); int stmtC = 0; Connection connection = dataSource.getConnection(); for (String statement : statements) { int rowC = 0; PreparedStatement prepStmt = null; try { logger.debug("executing drop table statement: {}", statement); prepStmt = connection.prepareStatement(statement); rowC = prepStmt.executeUpdate(); } catch (SQLException e) { if (!ignoreErrors) { throw e; } } finally { if (prepStmt != null) { prepStmt.close(); } } // sanity check if (rowC < 0) { throw new SQLException("SQL statement " + statement + " updated " + rowC + " rows, we were expecting >= 0"); } stmtC++; } return stmtC; } /** * Generate and return the list of statements to create a database table and any associated features. */ private static void createTableStatements(DatabaseType databaseType, TableInfo tableInfo, List statements, List queriesAfter) { StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE "); databaseType.appendEscapedEntityName(sb, tableInfo.getTableName()); sb.append(" ("); List additionalArgs = new ArrayList(); List statementsBefore = new ArrayList(); List statementsAfter = new ArrayList(); // our statement will be set here later boolean first = true; for (FieldType fieldType : tableInfo.getFieldTypes()) { if (first) { first = false; } else { sb.append(", "); } // we have to call back to the database type for the specific create syntax databaseType.appendColumnArg(sb, fieldType, additionalArgs, statementsBefore, statementsAfter, queriesAfter); } for (String arg : additionalArgs) { // we will have spat out one argument already so we don't have to do the first dance sb.append(", ").append(arg); } sb.append(") "); databaseType.appendCreateTableSuffix(sb); statements.addAll(statementsBefore); statements.add(sb.toString()); statements.addAll(statementsAfter); } /** * Generate and return the list of statements to drop a database table. */ private static Collection dropTableStatements(DatabaseType databaseType, TableInfo tableInfo) { List statementsBefore = new ArrayList(); List statementsAfter = new ArrayList(); for (FieldType fieldType : tableInfo.getFieldTypes()) { databaseType.dropColumnArg(fieldType, statementsBefore, statementsAfter); } StringBuilder sb = new StringBuilder(); sb.append("DROP TABLE "); databaseType.appendEscapedEntityName(sb, tableInfo.getTableName()); sb.append(' '); List statements = new ArrayList(); statements.addAll(statementsBefore); statements.add(sb.toString()); statements.addAll(statementsAfter); return statements; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy