/*
* Copyright (c) 2010, Stanislav Muhametsin. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.qi4j.index.sql.support.skeletons;
import static org.qi4j.index.sql.support.common.DBNames.ALL_QNAMES_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ALL_QNAMES_TABLE_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.APP_VERSION_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.APP_VERSION_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_APPLICATION_VERSION_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_IDENTITY_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_MODIFIED_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TABLE_VERSION_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TYPES_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TYPES_TABLE_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENTITY_TYPES_TABLE_TYPE_NAME_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENUM_LOOKUP_TABLE_ENUM_VALUE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENUM_LOOKUP_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.ENUM_LOOKUP_TABLE_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.QNAME_TABLE_ASSOCIATION_INDEX_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.QNAME_TABLE_COLLECTION_PATH_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.QNAME_TABLE_NAME_PREFIX;
import static org.qi4j.index.sql.support.common.DBNames.QNAME_TABLE_PARENT_QNAME_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.QNAME_TABLE_VALUE_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_CLASSES_TABLE_CLASS_NAME_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_CLASSES_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_CLASSES_TABLE_PK_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_QNAMES_TABLE_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_QNAMES_TABLE_QNAME_COLUMN_NAME;
import static org.qi4j.index.sql.support.common.DBNames.USED_QNAMES_TABLE_TABLE_NAME_COLUMN_NAME;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.qi4j.api.common.QualifiedName;
import org.qi4j.api.configuration.Configuration;
import org.qi4j.api.entity.Identity;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.This;
import org.qi4j.api.service.Activatable;
import org.qi4j.api.service.ServiceComposite;
import org.qi4j.api.structure.Application;
import org.qi4j.index.reindexer.Reindexer;
import org.qi4j.index.sql.support.api.SQLAppStartup;
import org.qi4j.index.sql.support.api.SQLTypeInfo;
import org.qi4j.index.sql.support.common.DBNames;
import org.qi4j.index.sql.support.common.EntityTypeInfo;
import org.qi4j.index.sql.support.common.QNameInfo;
import org.qi4j.index.sql.support.common.QNameInfo.QNameType;
import org.qi4j.index.sql.support.common.ReindexingStrategy;
import org.qi4j.library.sql.common.SQLConfiguration;
import org.qi4j.library.sql.common.SQLUtil;
import org.qi4j.library.sql.ds.DataSourceService;
import org.qi4j.spi.entity.EntityDescriptor;
import org.qi4j.spi.entity.association.AssociationDescriptor;
import org.qi4j.spi.property.PropertyDescriptor;
import org.qi4j.spi.structure.ApplicationSPI;
import org.qi4j.spi.structure.DescriptorVisitor;
import org.qi4j.spi.value.ValueDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sql.generation.api.grammar.builders.definition.TableElementListBuilder;
import org.sql.generation.api.grammar.common.datatypes.SQLDataType;
import org.sql.generation.api.grammar.definition.table.ConstraintCharacteristics;
import org.sql.generation.api.grammar.definition.table.ReferentialAction;
import org.sql.generation.api.grammar.definition.table.UniqueSpecification;
import org.sql.generation.api.grammar.factories.DataTypeFactory;
import org.sql.generation.api.grammar.factories.DefinitionFactory;
import org.sql.generation.api.grammar.factories.LiteralFactory;
import org.sql.generation.api.grammar.factories.ModificationFactory;
import org.sql.generation.api.grammar.factories.QueryFactory;
import org.sql.generation.api.grammar.factories.TableReferenceFactory;
import org.sql.generation.api.grammar.manipulation.DropBehaviour;
import org.sql.generation.api.grammar.manipulation.ObjectType;
import org.sql.generation.api.grammar.modification.DeleteBySearch;
import org.sql.generation.api.grammar.query.QueryExpression;
import org.sql.generation.api.vendor.SQLVendor;
/**
*
* @author Stanislav Muhametsin
*/
public abstract class AbstractSQLStartup
implements SQLAppStartup, Activatable
{
private interface SQLTypeCustomizer
{
SQLDataType customizeType( Type propertyType, SQLTypeInfo sqlTypeInfo );
}
public static final String DEFAULT_SCHEMA_NAME = "qi4j";
private static final Logger _log = LoggerFactory.getLogger( AbstractSQLStartup.class.getName() );
@This
private SQLDBState _state;
@This
private ServiceComposite _myselfAsService;
@This
private Configuration<SQLConfiguration> _configuration;
@Service
private ReindexingStrategy _reindexingStrategy;
@Service
private DataSourceService _dataSource;
@Service
private Reindexer _reindexer;
@Structure
private Application _app;
private SQLVendor _vendor;
private Map<Class<?>, SQLTypeCustomizer> _customizableTypes;
private Map<Class<?>, SQLDataType> _primitiveTypes;
public void activate()
throws Exception
{
this._vendor = this._myselfAsService.metaInfo( SQLVendor.class );
this.setVendor( this._vendor );
this.initTypes();
this.modifyPrimitiveTypes( this._primitiveTypes, this._state.javaTypes2SQLTypes().get() );
}
public void passivate()
throws Exception
{
}
public void initConnection()
throws SQLException
{
Connection connection = this._dataSource.getDataSource().getConnection();
connection.setAutoCommit( false );
String schemaName = this._configuration.configuration().schemaName().get();
if( schemaName == null )
{
schemaName = DEFAULT_SCHEMA_NAME;
}
else
{
this.checkSchemaName( schemaName );
}
this._state.schemaName().set( schemaName );
this._state.tablePKs().set( new HashMap<String, Long>() );
this._state.usedClassesPKs().set( new HashMap<String, Integer>() );
this._state.entityTypeInfos().set( new HashMap<String, EntityTypeInfo>() );
this._state.entityUsedQNames().set( new HashMap<String, Set<QualifiedName>>() );
this._state.qNameInfos().set( new HashMap<QualifiedName, QNameInfo>() );
this._state.enumPKs().set( new HashMap<String, Integer>() );
Boolean wasAutoCommit = connection.getAutoCommit();
connection.setAutoCommit( true );
try
{
this.syncDB();
}
finally
{
connection.setAutoCommit( wasAutoCommit );
}
}
private void initTypes()
{
DataTypeFactory dt = this._vendor.getDataTypeFactory();
this._primitiveTypes = new HashMap<Class<?>, SQLDataType>();
this._primitiveTypes.put( Boolean.class, dt.sqlBoolean() );
this._primitiveTypes.put( Byte.class, dt.smallInt() );
this._primitiveTypes.put( Short.class, dt.smallInt() );
this._primitiveTypes.put( Integer.class, dt.integer() );
this._primitiveTypes.put( Long.class, dt.bigInt() );
this._primitiveTypes.put( Float.class, dt.real() );
this._primitiveTypes.put( Double.class, dt.doublePrecision() );
this._primitiveTypes.put( Date.class, dt.timeStamp( true ) );
this._primitiveTypes.put( Character.class, dt.integer() );
this._primitiveTypes.put( String.class, dt.sqlVarChar( 5000 ) );
this._primitiveTypes.put( BigInteger.class, dt.decimal() );
this._primitiveTypes.put( BigDecimal.class, dt.decimal() );
Map<Class<?>, Integer> jdbcTypes = new HashMap<Class<?>, Integer>();
jdbcTypes.put( Boolean.class, Types.BOOLEAN );
jdbcTypes.put( Byte.class, Types.SMALLINT );
jdbcTypes.put( Short.class, Types.SMALLINT );
jdbcTypes.put( Integer.class, Types.INTEGER );
jdbcTypes.put( Long.class, Types.BIGINT );
jdbcTypes.put( Float.class, Types.REAL );
jdbcTypes.put( Double.class, Types.DOUBLE );
jdbcTypes.put( Date.class, Types.TIMESTAMP );
jdbcTypes.put( Character.class, Types.INTEGER );
jdbcTypes.put( String.class, Types.VARCHAR );
jdbcTypes.put( BigInteger.class, Types.NUMERIC );
jdbcTypes.put( BigDecimal.class, Types.NUMERIC );
this._state.javaTypes2SQLTypes().set( jdbcTypes );
this._customizableTypes = new HashMap<Class<?>, SQLTypeCustomizer>();
this._customizableTypes.put( //
String.class, //
new SQLTypeCustomizer()
{
public SQLDataType customizeType( Type propertyType, SQLTypeInfo sqlTypeInfo )
{
return _vendor.getDataTypeFactory().sqlVarChar( sqlTypeInfo.maxLength() );
}
} //
);
this._customizableTypes.put( //
BigInteger.class, //
new SQLTypeCustomizer()
{
public SQLDataType customizeType( Type propertyType, SQLTypeInfo sqlTypeInfo )
{
return _vendor.getDataTypeFactory().decimal( sqlTypeInfo.maxLength() );
}
} //
);
this._customizableTypes.put( //
BigDecimal.class, //
new SQLTypeCustomizer()
{
public SQLDataType customizeType( Type propertyType, SQLTypeInfo sqlTypeInfo )
{
return _vendor.getDataTypeFactory().decimal( sqlTypeInfo.maxLength() );
}
} //
);
}
protected void checkSchemaName( String schemaName )
{
// By default, we accept alphanumeric strings with underscores in them
if( !Pattern.matches( "^\\p{L}(\\_|\\p{L}|\\p{N})*$", schemaName ) )
{
throw new IllegalStateException( "Illegal schema name: " + schemaName + "." );
}
}
private Boolean syncDB()
throws SQLException
{
Connection connection = this._dataSource.getDataSource().getConnection();
String schemaName = this._state.schemaName().get();
ResultSet rs = connection.getMetaData().getSchemas();
Boolean schemaFound = false;
try
{
while( rs.next() && !schemaFound )
{
schemaFound = rs.getString( 1 ).equals( schemaName );
}
}
finally
{
rs.close();
}
Map<String, EntityDescriptor> entityDescriptors = new HashMap<String, EntityDescriptor>();
Set<String> usedClassNames = new HashSet<String>();
Set<String> enumValues = new HashSet<String>();
Boolean reindexingRequired = this.isReindexingNeeded( schemaFound, entityDescriptors, usedClassNames,
enumValues );
if( schemaFound && !reindexingRequired )
{
this.testRequiredCapabilities();
this.readAppMetadataFromDB( entityDescriptors );
}
else
{
this.createSchema( schemaFound );
this.writeAppMetadataToDB( entityDescriptors, usedClassNames, enumValues );
if( reindexingRequired )
{
this.performReindex( connection );
}
}
return reindexingRequired;
}
private void createSchema( Boolean schemaFound )
throws SQLException
{
Connection connection = this._dataSource.getDataSource().getConnection();
String schemaName = this._state.schemaName().get();
SQLVendor vendor = this._vendor;
DefinitionFactory d = vendor.getDefinitionFactory();
TableReferenceFactory t = vendor.getTableReferenceFactory();
Statement stmt = connection.createStatement();
// @formatter:off
try
{
if( !schemaFound )
{
stmt.execute(
vendor.toString(
d
.createSchemaDefinitionBuilder()
.setSchemaName( schemaName )
.createExpression()
)
);
}
this.testRequiredCapabilities();
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, USED_CLASSES_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( USED_CLASSES_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( USED_CLASSES_TABLE_CLASS_NAME_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( USED_CLASSES_TABLE_PK_COLUMN_NAME )
.createExpression()
) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.UNIQUE )
.addColumns( USED_CLASSES_TABLE_CLASS_NAME_COLUMN_NAME )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
this._state.tablePKs().get().put( USED_CLASSES_TABLE_NAME, 0L );
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, ENTITY_TYPES_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( ENTITY_TYPES_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TYPES_TABLE_TYPE_NAME_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ENTITY_TYPES_TABLE_PK_COLUMN_NAME )
.createExpression()
) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.UNIQUE )
.addColumns( ENTITY_TYPES_TABLE_TYPE_NAME_COLUMN_NAME )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
this._state.tablePKs().get().put( ENTITY_TYPES_TABLE_NAME, 0L );
ResultSet rs = null;
try
{
rs = connection.getMetaData().getTables( null, schemaName, ENTITY_TABLE_NAME, new String[]
{
"TABLE"
} );
if( !rs.next() )
{
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, ENTITY_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Long.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TYPES_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_IDENTITY_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_MODIFIED_COLUMN_NAME, this._primitiveTypes.get( Date.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_VERSION_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_APPLICATION_VERSION_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ENTITY_TABLE_PK_COLUMN_NAME )
.createExpression()
) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.UNIQUE )
.addColumns( ENTITY_TABLE_IDENTITY_COLUMN_NAME )
.createExpression()
) )
.addTableElement( d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( ENTITY_TYPES_TABLE_PK_COLUMN_NAME )
.setTargetTableName( t.tableName( schemaName, ENTITY_TYPES_TABLE_NAME ) )
.addTargetColumns( ENTITY_TYPES_TABLE_PK_COLUMN_NAME )
.setOnDelete( ReferentialAction.RESTRICT )
.setOnUpdate( ReferentialAction.CASCADE )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
this._state.tablePKs().get().put( ENTITY_TABLE_NAME, 0L );
}
else
{
this._state
.tablePKs()
.get()
.put(
ENTITY_TABLE_NAME,
this.getNextPK( stmt, schemaName, ENTITY_TABLE_PK_COLUMN_NAME,
ENTITY_TABLE_NAME, 0L ) );
}
}
finally
{
SQLUtil.closeQuietly( rs );
}
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, ENUM_LOOKUP_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( ENUM_LOOKUP_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( ENUM_LOOKUP_TABLE_ENUM_VALUE_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ENUM_LOOKUP_TABLE_PK_COLUMN_NAME )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
this._state.tablePKs().get().put( ENUM_LOOKUP_TABLE_NAME, 0L );
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, USED_QNAMES_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( USED_QNAMES_TABLE_QNAME_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createColumnDefinition( USED_QNAMES_TABLE_TABLE_NAME_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( USED_QNAMES_TABLE_QNAME_COLUMN_NAME, USED_QNAMES_TABLE_TABLE_NAME_COLUMN_NAME )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, ALL_QNAMES_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( ALL_QNAMES_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Long.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.createExpression()
) )
.addTableElement( d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( ENTITY_TABLE_PK_COLUMN_NAME )
.setTargetTableName( t.tableName( schemaName, ENTITY_TABLE_NAME ) )
.addTargetColumns( ENTITY_TABLE_PK_COLUMN_NAME )
.setOnUpdate( ReferentialAction.CASCADE )
.setOnDelete( ReferentialAction.CASCADE )
.createExpression(), ConstraintCharacteristics.INITIALLY_DEFERRED_DEFERRABLE
) )
.createExpression()
)
.createExpression()
)
);
this._state.tablePKs().get().put( ALL_QNAMES_TABLE_NAME, 0L );
stmt.execute(
vendor.toString(
d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, APP_VERSION_TABLE_NAME ) )
.setTableContentsSource(
d.createTableElementListBuilder()
.addTableElement( d.createColumnDefinition( APP_VERSION_PK_COLUMN_NAME, this._primitiveTypes.get( String.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( APP_VERSION_PK_COLUMN_NAME )
.createExpression()
) )
.createExpression()
)
.createExpression()
)
);
ModificationFactory m = vendor.getModificationFactory();
PreparedStatement ps = connection.prepareStatement(
vendor.toString(
m.insert()
.setTableName( t.tableName( schemaName, APP_VERSION_TABLE_NAME ) )
.setColumnSource(
m.columnSourceByValues()
.addValues( vendor.getLiteralFactory().param() )
.createExpression()
)
.createExpression()
)
);
ps.setString( 1, this._app.version() );
ps.execute();
// TODO INDICES!!!!
}
finally
{
stmt.close();
}
// @formatter:on
}
private void performReindex( Connection connection )
throws SQLException
{
_log.info( "Performing reindexing..." );
// @formatter:off
// First delete all entity data
DeleteBySearch clearEntityData = this._vendor.getModificationFactory().deleteBySearch()
.setTargetTable(
this._vendor.getModificationFactory().createTargetTable(
this._vendor.getTableReferenceFactory().tableName(
this._state.schemaName().get(),
ENTITY_TABLE_NAME
)
)
).createExpression();
connection.prepareStatement( this._vendor.toString( clearEntityData ) ).execute();
// @formatter:on
this._reindexer.reindex();
_log.info( "Reindexing complete." );
}
private void readAppMetadataFromDB( Map<String, EntityDescriptor> entityDescriptors )
throws SQLException
{
String schemaName = this._state.schemaName().get();
Connection connection = this._dataSource.getDataSource().getConnection();
Statement stmt = connection.createStatement();
SQLVendor vendor = this._vendor;
QueryFactory q = vendor.getQueryFactory();
TableReferenceFactory t = vendor.getTableReferenceFactory();
try
{
// @formatter:off
Map<String, Long> pks = this._state.tablePKs().get();
pks.put( ENTITY_TABLE_NAME, this.getNextPK( stmt, schemaName,
DBNames.ENTITY_TABLE_PK_COLUMN_NAME, DBNames.ENTITY_TABLE_NAME, 0L ) );
q.simpleQueryBuilder()
.select( ENTITY_TYPES_TABLE_PK_COLUMN_NAME, ENTITY_TYPES_TABLE_TYPE_NAME_COLUMN_NAME )
.from( t.tableName( schemaName, ENTITY_TYPES_TABLE_NAME ) )
.createExpression();
ResultSet rs = stmt.executeQuery(
vendor.toString(
q.simpleQueryBuilder()
.select( ENTITY_TYPES_TABLE_PK_COLUMN_NAME, ENTITY_TYPES_TABLE_TYPE_NAME_COLUMN_NAME )
.from( t.tableName( schemaName, ENTITY_TYPES_TABLE_NAME ) )
.createExpression()
)
);
long pk = 0L;
while( rs.next() )
{
pk = rs.getInt( 1 );
String entityTypeName = rs.getString( 2 );
this._state.entityTypeInfos().get()
.put( entityTypeName, new EntityTypeInfo( entityDescriptors.get( entityTypeName ), (int) pk ) );
if( !this._state.tablePKs().get().containsKey( ENTITY_TYPES_TABLE_NAME )
|| this._state.tablePKs().get().get( ENTITY_TYPES_TABLE_NAME ) <= pk )
{
this._state.tablePKs().get().put( ENTITY_TYPES_TABLE_NAME, pk + 1 );
}
}
rs = stmt.executeQuery(
vendor.toString(
q.simpleQueryBuilder()
.select( USED_CLASSES_TABLE_PK_COLUMN_NAME, USED_CLASSES_TABLE_CLASS_NAME_COLUMN_NAME )
.from( t.tableName( schemaName, USED_CLASSES_TABLE_NAME ) )
.createExpression()
)
);
while( rs.next() )
{
pk = rs.getInt( 1 );
String className = rs.getString( 2 );
if( !this._state.tablePKs().get().containsKey( USED_CLASSES_TABLE_NAME )
|| this._state.tablePKs().get().get( USED_CLASSES_TABLE_NAME ) <= pk )
{
this._state.tablePKs().get().put( USED_CLASSES_TABLE_NAME, pk + 1 );
}
this._state.usedClassesPKs().get().put( className, (int) pk );
}
rs = stmt.executeQuery(
vendor.toString(
q.simpleQueryBuilder()
.select( ENUM_LOOKUP_TABLE_PK_COLUMN_NAME, ENUM_LOOKUP_TABLE_ENUM_VALUE_NAME )
.from( t.tableName( schemaName, ENUM_LOOKUP_TABLE_NAME ) )
.createExpression()
)
);
while( rs.next() )
{
pk = rs.getInt( 1 );
String enumName = rs.getString( 2 );
if( !this._state.tablePKs().get().containsKey( ENUM_LOOKUP_TABLE_NAME )
|| this._state.tablePKs().get().get( ENUM_LOOKUP_TABLE_NAME ) <= pk )
{
this._state.tablePKs().get().put( ENUM_LOOKUP_TABLE_NAME, pk + 1 );
}
this._state.enumPKs().get().put( enumName, (int) pk );
}
// @formatter:on
}
finally
{
SQLUtil.closeQuietly( stmt );
}
}
private void writeAppMetadataToDB( Map<String, EntityDescriptor> entityDescriptors, Set<String> usedClassNames,
Set<String> allEnums )
throws SQLException
{
Connection connection = this._dataSource.getDataSource().getConnection();
String schemaName = this._state.schemaName().get();
SQLVendor vendor = this._vendor;
ModificationFactory m = vendor.getModificationFactory();
TableReferenceFactory t = vendor.getTableReferenceFactory();
LiteralFactory l = vendor.getLiteralFactory();
// @formatter:off
PreparedStatement ps = connection.prepareStatement(
vendor.toString(
m.insert()
.setTableName( t.tableName( schemaName, ENTITY_TYPES_TABLE_NAME ) )
.setColumnSource( m.columnSourceByValues()
.addValues( l.param(), l.param() )
.createExpression()
)
.createExpression()
)
);
try
{
for( EntityDescriptor descriptor : entityDescriptors.values() )
{
String entityTypeName = descriptor.type().getName();
long pk = this._state.tablePKs().get().get( ENTITY_TYPES_TABLE_NAME );
ps.setInt( 1, (int) pk );
ps.setString( 2, entityTypeName );
ps.executeUpdate();
this._state.entityTypeInfos().get().put( entityTypeName, new EntityTypeInfo( descriptor, (int) pk ) );
this._state.tablePKs().get().put( ENTITY_TYPES_TABLE_NAME, pk + 1 );
}
}
finally
{
ps.close();
}
ps = connection.prepareStatement(
vendor.toString(
m.insert()
.setTableName( t.tableName( schemaName, USED_CLASSES_TABLE_NAME ) )
.setColumnSource( m.columnSourceByValues()
.addValues( l.param(), l.param() )
.createExpression()
)
.createExpression()
)
);
try
{
for( String usedClass : usedClassNames )
{
long pk = this._state.tablePKs().get().get( USED_CLASSES_TABLE_NAME );
ps.setInt( 1, (int) pk );
ps.setString( 2, usedClass );
ps.executeUpdate();
this._state.usedClassesPKs().get().put( usedClass, (int) pk );
this._state.tablePKs().get().put( USED_CLASSES_TABLE_NAME, pk + 1 );
}
}
finally
{
ps.close();
}
ps = connection.prepareStatement(
vendor.toString(
m.insert()
.setTableName( t.tableName( schemaName, ENUM_LOOKUP_TABLE_NAME ) )
.setColumnSource( m.columnSourceByValues()
.addValues( l.param(), l.param() )
.createExpression()
)
.createExpression()
)
);
try
{
for( String enumValue : allEnums )
{
long pk = this._state.tablePKs().get().get( ENUM_LOOKUP_TABLE_NAME );
ps.setInt( 1, (int) pk );
ps.setString( 2, enumValue );
ps.executeUpdate();
this._state.enumPKs().get().put( enumValue, (int) pk );
this._state.tablePKs().get().put( ENUM_LOOKUP_TABLE_NAME, pk + 1 );
}
}
finally
{
ps.close();
}
Statement stmt = connection.createStatement();
ps = connection.prepareStatement(
vendor.toString(
m.insert()
.setTableName( t.tableName( schemaName, USED_QNAMES_TABLE_NAME ) )
.setColumnSource( m.columnSourceByValues()
.addValues( l.param(), l.param() )
.createExpression()
)
.createExpression()
)
);
try
{
DefinitionFactory d = vendor.getDefinitionFactory();
for( QNameInfo qNameInfo : this._state.qNameInfos().get().values() )
{
QNameType type = qNameInfo.getQNameType();
TableElementListBuilder builder = d.createTableElementListBuilder();
builder
.addTableElement( d.createColumnDefinition( ALL_QNAMES_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ))
.addTableElement( d.createColumnDefinition( ENTITY_TABLE_PK_COLUMN_NAME, this._primitiveTypes.get( Long.class ), false ));
if( type.equals( QNameType.PROPERTY ) )
{
builder.addTableElement( d.createColumnDefinition( QNAME_TABLE_PARENT_QNAME_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), true ) );
if( qNameInfo.getCollectionDepth() > 0 )
{
builder.addTableElement( d.createColumnDefinition( QNAME_TABLE_COLLECTION_PATH_COLUMN_NAME, this.getCollectionPathDataType(), false ) );
}
this.appendColumnDefinitionsForProperty( builder, qNameInfo );
builder.addTableElement( d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( QNAME_TABLE_PARENT_QNAME_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.setTargetTableName( t.tableName( schemaName, ALL_QNAMES_TABLE_NAME ) )
.addTargetColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.setOnUpdate( ReferentialAction.CASCADE )
.setOnDelete( ReferentialAction.CASCADE )
.createExpression(), ConstraintCharacteristics.INITIALLY_DEFERRED_DEFERRABLE
) );
}
else
{
if( type.equals( QNameType.ASSOCIATION ) )
{
builder
.addTableElement( d.createColumnDefinition( QNAME_TABLE_VALUE_COLUMN_NAME, this._primitiveTypes.get( Long.class ), false ))
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.createExpression()
) );
}
else if( type.equals( QNameType.MANY_ASSOCIATION ) )
{
builder
.addTableElement( d.createColumnDefinition( QNAME_TABLE_ASSOCIATION_INDEX_COLUMN_NAME, this._primitiveTypes.get( Integer.class ), false ) )
.addTableElement( d.createColumnDefinition( QNAME_TABLE_VALUE_COLUMN_NAME, this._primitiveTypes.get( Long.class ), false ) )
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.createExpression()
) );
}
else
{
throw new IllegalArgumentException( "Did not how to create table for qName type: " + type + "." );
}
builder
.addTableElement( d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( QNAME_TABLE_VALUE_COLUMN_NAME )
.setTargetTableName( t.tableName( schemaName, ENTITY_TABLE_NAME ) )
.addTargetColumns( ENTITY_TABLE_PK_COLUMN_NAME )
.setOnUpdate( ReferentialAction.CASCADE )
.setOnDelete( ReferentialAction.CASCADE )
.createExpression(), ConstraintCharacteristics.INITIALLY_DEFERRED_DEFERRABLE
)
);
this._state.tablePKs().get().put( qNameInfo.getTableName(), 0L );
}
builder
.addTableElement(
d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.setTargetTableName( t.tableName( schemaName, ALL_QNAMES_TABLE_NAME ) )
.addTargetColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.setOnUpdate( ReferentialAction.CASCADE )
.setOnDelete( ReferentialAction.CASCADE )
.createExpression(), ConstraintCharacteristics.INITIALLY_DEFERRED_DEFERRABLE
)
);
stmt.execute( this._vendor.toString( d.createTableDefinitionBuilder()
.setTableName( t.tableName( schemaName, qNameInfo.getTableName() ) )
.setTableContentsSource( builder.createExpression() )
.createExpression()
) );
// stmt.execute( "COMMENT ON TABLE " + schemaName + "." + qNameInfo.getTableName() + " IS '"
// + qNameInfo.getQName() + "'" );
ps.setString( 1, qNameInfo.getQName().toString() );
ps.setString( 2, qNameInfo.getTableName() );
ps.execute();
}
}
finally
{
stmt.close();
ps.close();
}
// @formatter:off
}
private void appendColumnDefinitionsForProperty( TableElementListBuilder builder, QNameInfo qNameInfo )
{
Type finalType = qNameInfo.getFinalType();
if( finalType instanceof ParameterizedType )
{
finalType = ((ParameterizedType) finalType).getRawType();
}
Class<?> finalClass = (Class<?>) finalType;
SQLDataType sqlType = null;
String valueRefTableName = null;
String valueRefTablePKColumnName = null;
if( qNameInfo.isFinalTypePrimitive() )
{
if( this._customizableTypes.keySet().contains( finalClass )
&& qNameInfo.getPropertyDescriptor().accessor().isAnnotationPresent( SQLTypeInfo.class ) )
{
sqlType = this._customizableTypes.get( finalClass ).customizeType( finalClass,
qNameInfo.getPropertyDescriptor().accessor().getAnnotation( SQLTypeInfo.class ) );
}
else if( Enum.class.isAssignableFrom( finalClass ) )
{
// Enum - reference the lookup table
sqlType = this._primitiveTypes.get( Integer.class );
valueRefTableName = ENUM_LOOKUP_TABLE_NAME;
valueRefTablePKColumnName = ENUM_LOOKUP_TABLE_PK_COLUMN_NAME;
}
else
{
// Primitive type, default sqlType
sqlType = this._primitiveTypes.get( finalClass );
}
if( sqlType == null )
{
throw new InternalError( "Could not find sql type for java type [" + finalType + "]" );
}
}
else
{
// Value composite - just need used class
sqlType = this._primitiveTypes.get( Integer.class );
valueRefTableName = USED_CLASSES_TABLE_NAME;
valueRefTablePKColumnName = USED_CLASSES_TABLE_PK_COLUMN_NAME;
}
SQLVendor vendor = this._vendor;
DefinitionFactory d = vendor.getDefinitionFactory();
TableReferenceFactory t = vendor.getTableReferenceFactory();
builder
.addTableElement( d.createColumnDefinition( QNAME_TABLE_VALUE_COLUMN_NAME, sqlType, qNameInfo.getCollectionDepth() > 0 ))
.addTableElement( d.createTableConstraintDefinition( d.createUniqueConstraintBuilder()
.setUniqueness( UniqueSpecification.PRIMARY_KEY )
.addColumns( ALL_QNAMES_TABLE_PK_COLUMN_NAME, ENTITY_TABLE_PK_COLUMN_NAME )
.createExpression()
) );
if( valueRefTableName != null && valueRefTablePKColumnName != null )
{
builder
.addTableElement( d.createTableConstraintDefinition( d.createForeignKeyConstraintBuilder()
.addSourceColumns( QNAME_TABLE_VALUE_COLUMN_NAME )
.setTargetTableName( t.tableName( this._state.schemaName().get(), valueRefTableName ) )
.addTargetColumns( valueRefTablePKColumnName )
.setOnUpdate( ReferentialAction.CASCADE )
.setOnDelete( ReferentialAction.RESTRICT )
.createExpression(), ConstraintCharacteristics.NOT_DEFERRABLE
) );
}
}
protected Long getNextPK( Statement stmt, String schemaName, String columnName,
String tableName, Long defaultPK )
throws SQLException
{
ResultSet rs = null;
Long result = defaultPK;
try
{
SQLVendor vendor = this._vendor;
QueryFactory q = vendor.getQueryFactory();
// Let's cheat a bit on SQL functions, so we won't need to use heavy query builder.
// Also, currently there are no arithmetic statements
rs = stmt.executeQuery(
vendor.toString(
q.simpleQueryBuilder()
.select( "COUNT(" + columnName + ")", "MAX(" + columnName + ") + 1" )
.from( vendor.getTableReferenceFactory().tableName( schemaName, tableName ) )
.createExpression()
)
);
if( rs.next() )
{
Long count = rs.getLong( 1 );
if( count > 0 )
{
result = rs.getLong( 2 );
}
}
}
finally
{
SQLUtil.closeQuietly( rs );
}
return result;
}
private Boolean isReindexingNeeded( Boolean schemaExists, Map<String, EntityDescriptor> entityDescriptors,
Set<String> usedClassNames, Set<String> enumValues )
throws SQLException
{
Boolean result = true;
if( schemaExists )
{
Connection connection = this._dataSource.getDataSource().getConnection();
String schemaName = this._state.schemaName().get();
Statement stmt = connection.createStatement();
try
{
QueryExpression getAppVersionQuery = this._vendor.getQueryFactory().simpleQueryBuilder()
.select( APP_VERSION_PK_COLUMN_NAME )
.from( this._vendor.getTableReferenceFactory().tableName( schemaName, APP_VERSION_TABLE_NAME ) )
.createExpression();
ResultSet rs = null;
try
{
rs = stmt.executeQuery( this._vendor.toString( getAppVersionQuery ) );
} catch (SQLException sqle)
{
// Sometimes meta data claims table exists, even when it really doesn't exist
}
if (rs != null)
{
result = !rs.next();
if( !result )
{
String dbAppVersion = rs.getString( 1 );
if( this._reindexingStrategy != null )
{
result = this._reindexingStrategy.reindexingNeeded( dbAppVersion, this._app.version() );
}
}
}
}
finally
{
SQLUtil.closeQuietly( stmt );
}
}
this.constructApplicationInfo( entityDescriptors, usedClassNames, enumValues, !result );
if( schemaExists && result )
{
this.clearSchema();
}
return result;
}
private void clearSchema()
throws SQLException
{
Connection connection = this._dataSource.getDataSource().getConnection();
String schemaName = this._state.schemaName().get();
DatabaseMetaData metaData = connection.getMetaData();
Statement stmt = connection.createStatement();
try
{
// Don't drop all entities table.
this.dropTablesIfExist( metaData, schemaName, ALL_QNAMES_TABLE_NAME, stmt );
this.dropTablesIfExist( metaData, schemaName, APP_VERSION_TABLE_NAME, stmt );
this.dropTablesIfExist( metaData, schemaName, ENTITY_TYPES_TABLE_NAME, stmt );
this.dropTablesIfExist( metaData, schemaName, ENUM_LOOKUP_TABLE_NAME, stmt );
this.dropTablesIfExist( metaData, schemaName, USED_CLASSES_TABLE_NAME, stmt );
this.dropTablesIfExist( metaData, schemaName, USED_QNAMES_TABLE_NAME, stmt );
Integer x = 0;
while (this.dropTablesIfExist( metaData, schemaName, DBNames.QNAME_TABLE_NAME_PREFIX + x, stmt ))
{
++x;
}
}
finally
{
stmt.close();
}
}
private void constructApplicationInfo( final Map<String, EntityDescriptor> entityDescriptors,
Set<String> usedClassNames, Set<String> enumValues, Boolean setQNameTableNameToNull )
throws SQLException
{
final List<ValueDescriptor> valueDescriptors = new ArrayList<ValueDescriptor>();
ApplicationSPI appSPI = (ApplicationSPI) this._app;
appSPI.visitDescriptor( new DescriptorVisitor<RuntimeException>()
{
@Override
public void visit( EntityDescriptor entityDescriptor )
{
if( entityDescriptor.entityType().queryable() )
{
entityDescriptors.put( entityDescriptor.type().getName(), entityDescriptor );
}
}
@Override
public void visit( ValueDescriptor valueDescriptor )
{
valueDescriptors.add( valueDescriptor );
}
} );
Set<String> usedVCClassNames = new HashSet<String>();
for( EntityDescriptor descriptor : entityDescriptors.values() )
{
Set<QualifiedName> newQNames = new HashSet<QualifiedName>();
this.extractPropertyQNames( descriptor, this._state.qNameInfos().get(), newQNames, valueDescriptors,
usedVCClassNames, enumValues, setQNameTableNameToNull );
this.extractAssociationQNames( descriptor, this._state.qNameInfos().get(), newQNames,
setQNameTableNameToNull );
this.extractManyAssociationQNames( descriptor, this._state.qNameInfos().get(), newQNames,
setQNameTableNameToNull );
this._state.entityUsedQNames().get().put( descriptor.type().getName(), newQNames );
}
usedClassNames.addAll( usedVCClassNames );
}
private void processPropertyTypeForQNames( PropertyDescriptor pType, Map<QualifiedName, QNameInfo> qNameInfos,
Set<QualifiedName> newQNames, List<ValueDescriptor> vDescriptors, Set<String> usedVCClassNames,
Set<String> enumValues, Boolean setQNameTableNameToNull )
{
QualifiedName qName = pType.qualifiedName();
if( !newQNames.contains( qName ) && !qName.typeName().name().equals( Identity.class.getName() ) )
{
newQNames.add( qName );
// System.out.println("QName: " + qName + ", hc: " + qName.hashCode());
QNameInfo info = qNameInfos.get( qName );
if( info == null )
{
info = QNameInfo.fromProperty( //
qName, //
setQNameTableNameToNull ? null : (QNAME_TABLE_NAME_PREFIX + qNameInfos.size()), //
pType//
);
qNameInfos.put( qName, info );
}
Type vType = info.getFinalType();
while( vType instanceof ParameterizedType )
{
vType = ((ParameterizedType) vType).getRawType();
}
if( vType instanceof Class<?> ) //
{
if( ((Class<?>) vType).isInterface() )
{
for( ValueDescriptor vDesc : vDescriptors )
{
String vcTypeName = vDesc.type().getName();
// TODO this doesn't understand, say, Map<String, String>, or indeed, any other Serializable
if( ((Class<?>) vType).isAssignableFrom( vDesc.type() ) )
{
usedVCClassNames.add( vcTypeName );
for( PropertyDescriptor subPDesc : vDesc.state().properties() )
{
this.processPropertyTypeForQNames( //
subPDesc, //
qNameInfos, //
newQNames, //
vDescriptors, //
usedVCClassNames, //
enumValues, //
setQNameTableNameToNull //
);
}
}
}
}
else if( Enum.class.isAssignableFrom( (Class<?>) vType ) )
{
for( Object value : ((Class<?>) vType).getEnumConstants() )
{
enumValues.add( QualifiedName.fromClass( (Class<?>) vType, value.toString() ).toString() );
}
}
}
}
}
private void extractPropertyQNames( EntityDescriptor entityDesc, Map<QualifiedName, QNameInfo> qNameInfos,
Set<QualifiedName> newQNames, List<ValueDescriptor> vDescriptors, Set<String> usedVCClassNames,
Set<String> enumValues, Boolean setQNameTableNameToNull )
{
for( PropertyDescriptor pDesc : entityDesc.state().properties() )
{
if( SQLUtil.isQueryable( pDesc.accessor() ) )
{
this.processPropertyTypeForQNames( //
pDesc, //
qNameInfos, //
newQNames, //
vDescriptors, //
usedVCClassNames, //
enumValues, //
setQNameTableNameToNull //
);
}
}
}
private void extractAssociationQNames( EntityDescriptor entityDesc, Map<QualifiedName, QNameInfo> extractedQNames,
Set<QualifiedName> newQNames, Boolean setQNameTableNameToNull )
{
for( AssociationDescriptor assoDesc : entityDesc.state().associations() )
{
if( SQLUtil.isQueryable( assoDesc.accessor() ) )
{
QualifiedName qName = assoDesc.qualifiedName();
if( !extractedQNames.containsKey( qName ) )
{
extractedQNames.put( qName,//
QNameInfo.fromAssociation( //
qName, //
setQNameTableNameToNull ? null : (QNAME_TABLE_NAME_PREFIX + extractedQNames.size()), //
assoDesc //
) //
);
newQNames.add( qName );
}
}
}
}
private void extractManyAssociationQNames( EntityDescriptor entityDesc,
Map<QualifiedName, QNameInfo> extractedQNames, Set<QualifiedName> newQNames, Boolean setQNameTableNameToNull )
{
for( AssociationDescriptor mAssoDesc : entityDesc.state().manyAssociations() )
{
QualifiedName qName = mAssoDesc.qualifiedName();
if( SQLUtil.isQueryable( mAssoDesc.accessor() ) )
{
if( !extractedQNames.containsKey( qName ) )
{
extractedQNames.put( //
qName, //
QNameInfo.fromManyAssociation( //
qName, //
setQNameTableNameToNull ? null : (QNAME_TABLE_NAME_PREFIX + extractedQNames.size()), //
mAssoDesc //
) //
);
newQNames.add( qName );
}
}
}
}
protected abstract void testRequiredCapabilities()
throws SQLException;
protected boolean dropTablesIfExist( DatabaseMetaData metaData, String schemaName, String tableName, Statement stmt )
throws SQLException
{
boolean result = false;
try
{
stmt.execute( this._vendor.toString( this._vendor.getManipulationFactory()
.createDropTableOrViewStatement(
this._vendor.getTableReferenceFactory().tableName( schemaName, tableName ), ObjectType.TABLE, DropBehaviour.CASCADE
) ) );
result = true;
} catch (SQLException sqle)
{
// Ignore
}
return result;
}
protected abstract void modifyPrimitiveTypes( Map<Class<?>, SQLDataType> primitiveTypes, Map<Class<?>, Integer> jdbcTypes );
protected abstract SQLDataType getCollectionPathDataType();
protected abstract void setVendor(SQLVendor vendor);
}