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

com.j256.ormlite.db.BaseDatabaseType Maven / Gradle / Ivy

package com.j256.ormlite.db;

import java.sql.Driver;
import java.sql.SQLException;
import java.util.List;
import java.util.Locale;

import com.j256.ormlite.field.DataPersister;
import com.j256.ormlite.field.FieldConverter;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.logger.Logger;
import com.j256.ormlite.logger.LoggerFactory;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.DatabaseTableConfig;

/**
 * Base class for all of the {@link DatabaseType} classes that provide the per-database type functionality to create
 * tables and build queries.
 *
 * 

* Here's a good page which shows some of the differences between SQL * databases. *

* * @author graywatson */ public abstract class BaseDatabaseType implements DatabaseType { protected static String DEFAULT_SEQUENCE_SUFFIX = "_id_seq"; protected Driver driver; protected Logger logger = LoggerFactory.getLogger(getClass()); /** * @deprecated Use {@link #getDriverClassNames()}. */ @Deprecated protected String getDriverClassName() { // default is none to let the SPI or other mechanism do the load return null; } /** * Return the name of the driver(s) class associated with this database type. They will be tried in order until one * class is found. */ protected String[] getDriverClassNames() { String className = getDriverClassName(); if (className == null) { return new String[0]; } else { return new String[] { className }; } } @Override public boolean loadDriver() { for (String className : getDriverClassNames()) { if (className == null) { continue; } // this instantiates the driver class which wires in the JDBC glue try { Class.forName(className); return true; } catch (ClassNotFoundException e) { // print warning if a class has not been loaded logger.warn("Driver class was not found for " + getDatabaseName() + " database. Class not found: " + className, e); } } return false; } @Override public void setDriver(Driver driver) { this.driver = driver; } @Override public void appendColumnArg(String tableName, StringBuilder sb, FieldType fieldType, List additionalArgs, List statementsBefore, List statementsAfter, List queriesAfter) throws SQLException { appendEscapedEntityName(sb, fieldType.getColumnName()); sb.append(' '); DataPersister dataPersister = fieldType.getDataPersister(); // first try the per-field width int fieldWidth = fieldType.getWidth(); if (fieldWidth == 0) { // next try the per-data-type width fieldWidth = dataPersister.getDefaultWidth(); } switch (dataPersister.getSqlType()) { case STRING: appendStringType(sb, fieldType, fieldWidth); break; case LONG_STRING: appendLongStringType(sb, fieldType, fieldWidth); break; case BOOLEAN: appendBooleanType(sb, fieldType, fieldWidth); break; case DATE: appendDateType(sb, fieldType, fieldWidth); break; case CHAR: appendCharType(sb, fieldType, fieldWidth); break; case BYTE: appendByteType(sb, fieldType, fieldWidth); break; case BYTE_ARRAY: appendByteArrayType(sb, fieldType, fieldWidth); break; case SHORT: appendShortType(sb, fieldType, fieldWidth); break; case INTEGER: appendIntegerType(sb, fieldType, fieldWidth); break; case LONG: appendLongType(sb, fieldType, fieldWidth); break; case FLOAT: appendFloatType(sb, fieldType, fieldWidth); break; case DOUBLE: appendDoubleType(sb, fieldType, fieldWidth); break; case SERIALIZABLE: appendSerializableType(sb, fieldType, fieldWidth); break; case BIG_DECIMAL: appendBigDecimalNumericType(sb, fieldType, fieldWidth); break; case UUID: appendUuidNativeType(sb, fieldType, fieldWidth); break; case OTHER: String sqlOtherType = dataPersister.getSqlOtherType(); if (sqlOtherType != null) { sb.append(sqlOtherType); } break; case UNKNOWN: default: // shouldn't be able to get here unless we have a missing case throw new IllegalArgumentException("Unknown SQL-type " + dataPersister.getSqlType()); } sb.append(' '); /* * NOTE: the configure id methods must be in this order since isGeneratedIdSequence is also isGeneratedId and * isId. isGeneratedId is also isId. */ if (fieldType.isGeneratedIdSequence() && !fieldType.isSelfGeneratedId()) { configureGeneratedIdSequence(sb, fieldType, statementsBefore, additionalArgs, queriesAfter); } else if (fieldType.isGeneratedId() && !fieldType.isSelfGeneratedId()) { configureGeneratedId(tableName, sb, fieldType, statementsBefore, statementsAfter, additionalArgs, queriesAfter); } else if (fieldType.isId()) { configureId(sb, fieldType, statementsBefore, additionalArgs, queriesAfter); } // if we have a generated-id then neither the not-null nor the default make sense and cause syntax errors if (!fieldType.isGeneratedId()) { Object defaultValue = fieldType.getDefaultValue(); if (defaultValue != null) { sb.append("DEFAULT "); appendDefaultValue(sb, fieldType, defaultValue); sb.append(' '); } if (fieldType.isCanBeNull()) { appendCanBeNull(sb, fieldType); } else { sb.append("NOT NULL "); } if (fieldType.isUnique()) { addSingleUnique(sb, fieldType, additionalArgs, statementsAfter); } } } /** * Output the SQL type for a Java String. */ protected void appendStringType(StringBuilder sb, FieldType fieldType, int fieldWidth) { if (isVarcharFieldWidthSupported()) { sb.append("VARCHAR(").append(fieldWidth).append(')'); } else { sb.append("VARCHAR"); } } /** * Output the SQL type for a Java UUID. This is used to support specific sub-class database types which support the * UUID type. */ protected void appendUuidNativeType(StringBuilder sb, FieldType fieldType, int fieldWidth) { throw new UnsupportedOperationException("UUID is not supported by this database type"); } /** * Output the SQL type for a Java Long String. */ protected void appendLongStringType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("TEXT"); } /** * Output the SQL type for a Java Date. */ protected void appendDateType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("TIMESTAMP"); } /** * Output the SQL type for a Java boolean. */ protected void appendBooleanType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("BOOLEAN"); } /** * Output the SQL type for a Java char. */ protected void appendCharType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("CHAR"); } /** * Output the SQL type for a Java byte. */ protected void appendByteType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("TINYINT"); } /** * Output the SQL type for a Java short. */ protected void appendShortType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("SMALLINT"); } /** * Output the SQL type for a Java integer. */ protected void appendIntegerType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("INTEGER"); } /** * Output the SQL type for a Java long. */ protected void appendLongType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("BIGINT"); } /** * Output the SQL type for a Java float. */ protected void appendFloatType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("FLOAT"); } /** * Output the SQL type for a Java double. */ protected void appendDoubleType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("DOUBLE PRECISION"); } /** * Output the SQL type for either a serialized Java object or a byte[]. */ protected void appendByteArrayType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("BLOB"); } /** * Output the SQL type for a serialized Java object. */ protected void appendSerializableType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("BLOB"); } /** * Output the SQL type for a BigDecimal object. */ protected void appendBigDecimalNumericType(StringBuilder sb, FieldType fieldType, int fieldWidth) { sb.append("NUMERIC"); } /** * Output the SQL type for the default value for the type. */ private void appendDefaultValue(StringBuilder sb, FieldType fieldType, Object defaultValue) { if (fieldType.isEscapedDefaultValue()) { appendEscapedWord(sb, defaultValue.toString()); } else { sb.append(defaultValue); } } /** * Output the SQL necessary to configure a generated-id column. This may add to the before statements list or * additional arguments later. * * NOTE: Only one of configureGeneratedIdSequence, configureGeneratedId, or configureId will be called. */ protected void configureGeneratedIdSequence(StringBuilder sb, FieldType fieldType, List statementsBefore, List additionalArgs, List queriesAfter) throws SQLException { throw new SQLException( "GeneratedIdSequence is not supported by database " + getDatabaseName() + " for field " + fieldType); } /** * Output the SQL necessary to configure a generated-id column. This may add to the before statements list or * additional arguments later. * * NOTE: Only one of configureGeneratedIdSequence, configureGeneratedId, or configureId will be called. */ protected void configureGeneratedId(String tableName, StringBuilder sb, FieldType fieldType, List statementsBefore, List statementsAfter, List additionalArgs, List queriesAfter) { throw new IllegalStateException( "GeneratedId is not supported by database " + getDatabaseName() + " for field " + fieldType); } /** * Output the SQL necessary to configure an id column. This may add to the before statements list or additional * arguments later. * * NOTE: Only one of configureGeneratedIdSequence, configureGeneratedId, or configureId will be called. */ protected void configureId(StringBuilder sb, FieldType fieldType, List statementsBefore, List additionalArgs, List queriesAfter) { // default is noop since we do it at the end in appendPrimaryKeys() } @Override public void addPrimaryKeySql(FieldType[] fieldTypes, List additionalArgs, List statementsBefore, List statementsAfter, List queriesAfter) { StringBuilder sb = null; for (FieldType fieldType : fieldTypes) { if (fieldType.isGeneratedId() && !generatedIdSqlAtEnd() && !fieldType.isSelfGeneratedId()) { // don't add anything } else if (fieldType.isId()) { if (sb == null) { sb = new StringBuilder(48); sb.append("PRIMARY KEY ("); } else { sb.append(','); } appendEscapedEntityName(sb, fieldType.getColumnName()); } } if (sb != null) { sb.append(") "); additionalArgs.add(sb.toString()); } } /** * Return true if we should add generated-id SQL in the {@link #addPrimaryKeySql} method at the end. If false then * it needs to be done by hand inline. */ protected boolean generatedIdSqlAtEnd() { return true; } @Override public void addUniqueComboSql(FieldType[] fieldTypes, List additionalArgs, List statementsBefore, List statementsAfter, List queriesAfter) { StringBuilder sb = null; for (FieldType fieldType : fieldTypes) { if (fieldType.isUniqueCombo()) { if (sb == null) { sb = new StringBuilder(48); sb.append("UNIQUE ("); } else { sb.append(','); } appendEscapedEntityName(sb, fieldType.getColumnName()); } } if (sb != null) { sb.append(") "); additionalArgs.add(sb.toString()); } } @Override public void dropColumnArg(FieldType fieldType, List statementsBefore, List statementsAfter) { // by default this is a noop } @Override public void appendEscapedWord(StringBuilder sb, String word) { sb.append('\'').append(word).append('\''); } @Override public void appendEscapedEntityName(StringBuilder sb, String name) { sb.append('`'); int dotPos = name.indexOf('.'); if (dotPos > 0) { sb.append(name.substring(0, dotPos)); sb.append("`.`"); sb.append(name.substring(1 + dotPos)); } else { sb.append(name); } sb.append('`'); } @Override public String generateIdSequenceName(String tableName, FieldType idFieldType) { String name = tableName + DEFAULT_SEQUENCE_SUFFIX; if (isEntityNamesMustBeUpCase()) { return upCaseEntityName(name); } else { return name; } } @Override public String getCommentLinePrefix() { return "-- "; } @Override public DataPersister getDataPersister(DataPersister defaultPersister, FieldType fieldType) { // default is noop return defaultPersister; } @Override public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { // default is to use the dataPersister itself return dataPersister; } @Override public boolean isIdSequenceNeeded() { return false; } @Override public boolean isVarcharFieldWidthSupported() { return true; } @Override public boolean isLimitSqlSupported() { return true; } @Override public boolean isOffsetSqlSupported() { return true; } @Override public boolean isOffsetLimitArgument() { return false; } @Override public boolean isLimitAfterSelect() { return false; } @Override public void appendLimitValue(StringBuilder sb, long limit, Long offset) { sb.append("LIMIT ").append(limit).append(' '); } @Override public void appendOffsetValue(StringBuilder sb, long offset) { sb.append("OFFSET ").append(offset).append(' '); } @Override public void appendSelectNextValFromSequence(StringBuilder sb, String sequenceName) { // noop by default. } @Override public void appendCreateTableSuffix(StringBuilder sb) { // noop by default. } @Override public void appendCreateSchemaSuffix(StringBuilder sb) { // noop by default. } @Override public boolean isCreateTableReturnsZero() { return true; } @Override public boolean isCreateSchemaReturnsZero() { return true; } @Override public boolean isCreateTableReturnsNegative() { return false; } @Override public boolean isCreateSchemaReturnsNegative() { return false; } @Override public boolean isEntityNamesMustBeUpCase() { return false; } @Override public String upCaseEntityName(String entityName) { return upCaseString(entityName, true); } @Override public String upCaseString(String string, boolean forceEnglish) { if (forceEnglish) { /* * We are forcing the ENGLISH locale because of language capitalization issues. In a couple of languages, * the capital version of many letters is a letter that is incompatible with many SQL libraries. For * example, in Turkish (Locale.forLanguageTag("tr-TR")), "i".toUpperCase() returns "İ" which is a dotted * uppercase i. */ return string.toUpperCase(Locale.ENGLISH); } else { /* * When we are trying to match certain methods, sometimes we need to check for the default locale case and * then check for the English variant. */ return string.toUpperCase(); } } @Override public String downCaseString(String string, boolean forceEnglish) { /* * See upCaseString(...) for details about the complexities here. */ if (forceEnglish) { return string.toLowerCase(Locale.ENGLISH); } else { return string.toLowerCase(); } } @Override public boolean isNestedSavePointsSupported() { return true; } @Override public String getPingStatement() { return "SELECT 1"; } @Override public boolean isBatchUseTransaction() { return false; } @Override public boolean isTruncateSupported() { return false; } @Override public boolean isCreateIfNotExistsSupported() { return false; } @Override public boolean isCreateIndexIfNotExistsSupported() { return isCreateIfNotExistsSupported(); } @Override public boolean isCreateSchemaIfNotExistsSupported() { return isCreateIfNotExistsSupported(); } @Override public boolean isSelectSequenceBeforeInsert() { return false; } @Override public boolean isAllowGeneratedIdInsertSupported() { return true; } /** * @throws SQLException * for sub classes. */ @Override public DatabaseTableConfig extractDatabaseTableConfig(ConnectionSource connectionSource, Class clazz) throws SQLException { // default is no default extractor return null; } @Override public void appendInsertNoColumns(StringBuilder sb) { sb.append("() VALUES ()"); } /** * If the field can be nullable, do we need to add some sort of NULL SQL for the create table. By default it is a * noop. This is necessary because MySQL has a auto default value for the TIMESTAMP type that required a default * value otherwise it would stick in the current date automagically. */ private void appendCanBeNull(StringBuilder sb, FieldType fieldType) { // default is a noop } /** * Add SQL to handle a unique=true field. THis is not for uniqueCombo=true. */ private void addSingleUnique(StringBuilder sb, FieldType fieldType, List additionalArgs, List statementsAfter) { StringBuilder alterSb = new StringBuilder(); alterSb.append(" UNIQUE ("); appendEscapedEntityName(alterSb, fieldType.getColumnName()); alterSb.append(')'); additionalArgs.add(alterSb.toString()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy