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