use of org.datanucleus.store.rdbms.mapping.column.ColumnMapping in project datanucleus-rdbms by datanucleus.
the class PersistableMapping method prepareColumnMapping.
/**
* Method to prepare the PC mapping and add its associated column mappings.
* @param clr The ClassLoaderResolver
*/
protected void prepareColumnMapping(ClassLoaderResolver clr) {
if (roleForMember == FieldRole.ROLE_COLLECTION_ELEMENT) {
// TODO Handle creation of columns in join table for collection of PCs
} else if (roleForMember == FieldRole.ROLE_ARRAY_ELEMENT) {
// TODO Handle creation of columns in join table for array of PCs
} else if (roleForMember == FieldRole.ROLE_MAP_KEY) {
// TODO Handle creation of columns in join table for map of PCs as keys
} else if (roleForMember == FieldRole.ROLE_MAP_VALUE) {
// TODO Handle creation of columns in join table for map of PCs as values
} else {
// Either one end of a 1-1 relation, or the N end of a N-1
AbstractClassMetaData refCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
JavaTypeMapping referenceMapping = null;
if (refCmd == null) {
// User stupidity
throw new NucleusUserException("You have a field " + mmd.getFullFieldName() + " that has type " + mmd.getTypeName() + " but this type has no known metadata. Your mapping is incorrect");
}
if (refCmd.getInheritanceMetaData() != null && refCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
// Find the actual tables storing the other end (can be multiple subclasses)
AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(refCmd, clr);
if (cmds != null && cmds.length > 0) {
if (cmds.length > 1) {
// TODO Only log this when it is really necessary. In some situations it is fine
NucleusLogger.PERSISTENCE.warn("Field " + mmd.getFullFieldName() + " represents either a 1-1 relation, " + "or a N-1 relation where the other end uses \"subclass-table\" inheritance strategy and more " + "than 1 subclasses with a table. This is not fully supported");
}
} else {
// TODO Throw an exception ?
return;
}
// TODO We need a mapping for each of the possible subclass tables
referenceMapping = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr).getIdMapping();
} else if (refCmd.getInheritanceMetaData() != null && refCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
// Find the other side of the relation
DatastoreClass refTable = null;
if (refCmd instanceof ClassMetaData && !((ClassMetaData) refCmd).isAbstract()) {
refTable = storeMgr.getDatastoreClass(refCmd.getFullClassName(), clr);
} else {
Collection<String> refSubclasses = storeMgr.getSubClassesForClass(refCmd.getFullClassName(), true, clr);
if (refSubclasses != null && !refSubclasses.isEmpty()) {
// if only 1 subclass then use that
String refSubclassName = refSubclasses.iterator().next();
refTable = storeMgr.getDatastoreClass(refSubclassName, clr);
if (refSubclasses.size() > 1) {
NucleusLogger.DATASTORE_SCHEMA.info("Field " + mmd.getFullFieldName() + " is a 1-1/N-1 relation and the other side had multiple possible classes " + "to which to create a foreign-key. Using first possible (" + refSubclassName + ")");
}
}
}
if (refTable != null) {
referenceMapping = refTable.getIdMapping();
} else {
throw new NucleusUserException("Field " + mmd.getFullFieldName() + " represents either a 1-1 relation, " + "or a N-1 relation where the other end uses \"complete-table\" inheritance strategy and either no table was found, or multiple possible tables!");
}
} else {
// Default is to use the ID of the related object
// TODO Add option to use a natural-id in the other class. Find the mapping using the targetColumnName
referenceMapping = storeMgr.getDatastoreClass(mmd.getType().getName(), clr).getIdMapping();
}
// Generate a mapping from the columns of the referenced object to this mapping's ColumnMetaData
CorrespondentColumnsMapper correspondentColumnsMapping = new CorrespondentColumnsMapper(mmd, table, referenceMapping, true);
// Find any related field where this is part of a bidirectional relation
RelationType relationType = mmd.getRelationType(clr);
boolean createColumnMappings = true;
if (relationType == RelationType.MANY_TO_ONE_BI) {
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
// TODO Cater for more than 1 related field
createColumnMappings = (relatedMmds[0].getJoinMetaData() == null);
} else if (// TODO If join table then don't need this
relationType == RelationType.ONE_TO_ONE_BI) {
// Put the FK at the end without "mapped-by"
createColumnMappings = (mmd.getMappedBy() == null);
}
if (mmd.getJoinMetaData() != null && (relationType == RelationType.MANY_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_BI)) {
if (relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_BI) {
throw new NucleusUserException("We do not currently support 1-1 relations via join table : " + mmd.getFullFieldName());
}
// create join table
storeMgr.newJoinTable(table, mmd, clr);
} else {
// Loop through the columns in the referenced class and create a column for each
for (int i = 0; i < referenceMapping.getNumberOfColumnMappings(); i++) {
ColumnMapping refColumnMapping = referenceMapping.getColumnMapping(i);
JavaTypeMapping mapping = storeMgr.getMappingManager().getMapping(refColumnMapping.getJavaTypeMapping().getJavaType());
this.addJavaTypeMapping(mapping);
// Create physical datastore columns where we require a FK link to the related table.
if (createColumnMappings) {
// Find the Column MetaData that maps to the referenced columncolumn
ColumnMetaData colmd = correspondentColumnsMapping.getColumnMetaDataByIdentifier(refColumnMapping.getColumn().getIdentifier());
if (colmd == null) {
throw new NucleusUserException(Localiser.msg("041038", refColumnMapping.getColumn().getIdentifier(), toString())).setFatal();
}
// Create a column to equate to the referenced classes column
MappingManager mmgr = storeMgr.getMappingManager();
Column col = mmgr.createColumn(mmd, table, mapping, colmd, refColumnMapping.getColumn(), clr);
// Add its column mapping
ColumnMapping colMapping = mmgr.createColumnMapping(mapping, col, refColumnMapping.getJavaTypeMapping().getJavaTypeForColumnMapping(i));
this.addColumnMapping(colMapping);
} else {
mapping.setReferenceMapping(referenceMapping);
}
}
}
}
}
use of org.datanucleus.store.rdbms.mapping.column.ColumnMapping in project datanucleus-rdbms by datanucleus.
the class MappingManagerImpl method createColumnMapping.
/**
* Method to create the column mapping for a particular column and java type.
* If the column is specified it is linked to the created column mapping.
* @param mapping The java mapping
* @param column The column (can be null)
* @param javaType The java type
* @return The column mapping
*/
@Override
public ColumnMapping createColumnMapping(JavaTypeMapping mapping, Column column, String javaType) {
Column col = column;
String jdbcType = null;
String sqlType = null;
if (col != null && col.getColumnMetaData() != null) {
// Utilise the jdbc and sql types if specified
jdbcType = col.getColumnMetaData().getJdbcTypeName();
sqlType = col.getColumnMetaData().getSqlType();
}
Class<? extends ColumnMapping> columnMappingClass = storeMgr.getDatastoreAdapter().getColumnMappingClass(javaType, jdbcType, sqlType, clr, null);
ColumnMapping columnMapping = ColumnMappingFactory.createMapping(columnMappingClass, mapping, storeMgr, column);
if (column != null) {
column.setColumnMapping(columnMapping);
}
return columnMapping;
}
use of org.datanucleus.store.rdbms.mapping.column.ColumnMapping in project datanucleus-rdbms by datanucleus.
the class SelectStatement method addOrderingColumnsToSelect.
/**
* Convenience method to add any necessary columns to the SELECT that are needed
* by the ordering constraint.
*/
protected void addOrderingColumnsToSelect() {
if (// Don't do this for subqueries, since we will be selecting just the necessary column(s)
orderingExpressions != null && parent == null) {
// Add any ordering columns to the SELECT
DatastoreAdapter dba = getDatastoreAdapter();
if (dba.supportsOption(DatastoreAdapter.ORDERBY_USING_SELECT_COLUMN_INDEX)) {
// Order using the indexes of the ordering columns in the SELECT
orderingColumnIndexes = new int[orderingExpressions.length];
// Add the ordering columns to the selected list, saving the positions
for (int i = 0; i < orderingExpressions.length; ++i) {
orderingColumnIndexes[i] = selectItem(orderingExpressions[i].toSQLText(), null, !aggregated);
if (unions != null && allowUnions) {
Iterator<SelectStatement> iterator = unions.iterator();
while (iterator.hasNext()) {
SelectStatement stmt = iterator.next();
stmt.selectItem(orderingExpressions[i].toSQLText(), null, !aggregated);
}
}
}
} else if (dba.supportsOption(DatastoreAdapter.INCLUDE_ORDERBY_COLS_IN_SELECT)) {
// Order using column aliases "NUCORDER{i}"
for (int i = 0; i < orderingExpressions.length; ++i) {
if (orderingExpressions[i] instanceof ResultAliasExpression) {
// Nothing to do since this is ordering by a result alias
} else if (orderingExpressions[i].getNumberOfSubExpressions() == 1 || aggregated) {
String orderExprAlias = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase("NUCORDER" + i);
if (unions != null && allowUnions) {
Iterator<SelectStatement> iterator = unions.iterator();
while (iterator.hasNext()) {
SelectStatement stmt = iterator.next();
stmt.selectItem(orderingExpressions[i].toSQLText(), aggregated ? null : orderExprAlias, !aggregated);
}
}
selectItem(orderingExpressions[i].toSQLText(), aggregated ? null : orderExprAlias, !aggregated);
} else {
JavaTypeMapping m = orderingExpressions[i].getJavaTypeMapping();
ColumnMapping[] mappings = m.getColumnMappings();
for (int j = 0; j < mappings.length; j++) {
String alias = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase("NUCORDER" + i + "_" + j);
DatastoreIdentifier aliasId = rdbmsMgr.getIdentifierFactory().newColumnIdentifier(alias);
SQLColumn col = new SQLColumn(orderingExpressions[i].getSQLTable(), mappings[j].getColumn(), aliasId);
selectItem(new SQLText(col.getColumnSelectString()), alias, !aggregated);
if (unions != null && allowUnions) {
Iterator<SelectStatement> iterator = unions.iterator();
while (iterator.hasNext()) {
SelectStatement stmt = iterator.next();
stmt.selectItem(new SQLText(col.getColumnSelectString()), alias, !aggregated);
}
}
}
}
}
}
}
}
use of org.datanucleus.store.rdbms.mapping.column.ColumnMapping in project datanucleus-rdbms by datanucleus.
the class SelectStatement method generateOrderingStatement.
/**
* Convenience method to generate the ordering statement to add to the overall query statement.
* @return The ordering statement
*/
protected SQLText generateOrderingStatement() {
SQLText orderStmt = null;
if (orderingExpressions != null && orderingExpressions.length > 0) {
DatastoreAdapter dba = getDatastoreAdapter();
if (dba.supportsOption(DatastoreAdapter.ORDERBY_USING_SELECT_COLUMN_INDEX)) {
// Order using the indexes of the ordering columns in the SELECT
orderStmt = new SQLText();
for (int i = 0; i < orderingExpressions.length; ++i) {
if (i > 0) {
orderStmt.append(',');
}
orderStmt.append(Integer.toString(orderingColumnIndexes[i]));
if (orderingDirections[i]) {
orderStmt.append(" DESC");
}
if (orderNullDirectives != null && orderNullDirectives[i] != null && dba.supportsOption(DatastoreAdapter.ORDERBY_NULLS_DIRECTIVES)) {
// Apply "NULLS [FIRST | LAST]" since supported by this datastore
orderStmt.append(" " + (orderNullDirectives[i] == NullOrderingType.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST"));
}
}
} else {
// Order using column aliases "NUCORDER{i}"
orderStmt = new SQLText();
boolean needsSelect = dba.supportsOption(DatastoreAdapter.INCLUDE_ORDERBY_COLS_IN_SELECT);
if (parent != null) {
// Don't select ordering columns with subqueries, since we will select just the required column(s)
needsSelect = false;
}
for (int i = 0; i < orderingExpressions.length; ++i) {
SQLExpression orderExpr = orderingExpressions[i];
boolean orderDirection = orderingDirections[i];
NullOrderingType orderNullDirective = (orderNullDirectives != null ? orderNullDirectives[i] : null);
if (i > 0) {
orderStmt.append(',');
}
if (needsSelect && !aggregated) {
if (orderExpr instanceof ResultAliasExpression) {
String orderStr = ((ResultAliasExpression) orderExpr).getResultAlias();
// make sure it is truncated for the datastore limits
orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierTruncatedToAdapterColumnLength(orderStr);
// put it in the case of the datastore
orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(orderStr);
addOrderComponent(orderStmt, orderStr, orderExpr, orderDirection, orderNullDirective, dba);
} else {
// Order by the "NUCORDER?" if we need them to be selected and it isn't an aggregate
String orderString = "NUCORDER" + i;
if (orderExpr.getNumberOfSubExpressions() == 1) {
String orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(orderString);
addOrderComponent(orderStmt, orderStr, orderExpr, orderDirection, orderNullDirective, dba);
} else {
ColumnMapping[] mappings = orderExpr.getJavaTypeMapping().getColumnMappings();
for (int j = 0; j < mappings.length; j++) {
String orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(orderString + "_" + j);
addOrderComponent(orderStmt, orderStr, orderExpr, orderDirection, orderNullDirective, dba);
if (j < mappings.length - 1) {
orderStmt.append(',');
}
}
}
}
} else {
if (orderExpr instanceof ResultAliasExpression) {
String orderStr = ((ResultAliasExpression) orderExpr).getResultAlias();
// make sure it is truncated for the datastore limits
orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierTruncatedToAdapterColumnLength(orderStr);
// put it in the case of the datastore
orderStr = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(orderStr);
addOrderComponent(orderStmt, orderStr, orderExpr, orderDirection, orderNullDirective, dba);
} else {
// Order by the "THIS.COLUMN" otherwise
addOrderComponent(orderStmt, orderExpr.toSQLText().toSQL(), orderExpr, orderDirection, orderNullDirective, dba);
}
}
}
}
}
return orderStmt;
}
use of org.datanucleus.store.rdbms.mapping.column.ColumnMapping in project datanucleus-rdbms by datanucleus.
the class ExpressionUtils method checkAndCorrectLiteralForConsistentMappingsForBooleanComparison.
protected static void checkAndCorrectLiteralForConsistentMappingsForBooleanComparison(SQLLiteral lit, SQLExpression expr) {
JavaTypeMapping litMapping = ((SQLExpression) lit).getJavaTypeMapping();
JavaTypeMapping exprMapping = expr.getJavaTypeMapping();
if (exprMapping == null || exprMapping.getNumberOfColumnMappings() == 0) {
return;
}
if (litMapping instanceof PersistableMapping && exprMapping instanceof ReferenceMapping) {
// Can compare implementation with reference
return;
}
if (litMapping instanceof SingleCollectionMapping) {
return;
}
boolean needsUpdating = false;
if (litMapping.getNumberOfColumnMappings() != exprMapping.getNumberOfColumnMappings()) {
needsUpdating = true;
} else {
for (int i = 0; i < litMapping.getNumberOfColumnMappings(); i++) {
ColumnMapping colMapping = litMapping.getColumnMapping(i);
if (colMapping == null || colMapping.getClass() != exprMapping.getColumnMapping(i).getClass()) {
needsUpdating = true;
break;
}
}
}
if (needsUpdating) {
// Make sure a change in mapping makes sense
// This embeds some type conversion rules and would be nice to avoid it
Class litMappingCls = litMapping.getJavaType();
Class mappingCls = exprMapping.getJavaType();
if (litMappingCls == Double.class || litMappingCls == Float.class || litMappingCls == BigDecimal.class) {
// Comparison between integral, and floating point parameter, so don't convert the param mapping
if (mappingCls == Integer.class || mappingCls == Long.class || mappingCls == Short.class || mappingCls == BigInteger.class || mappingCls == Byte.class) {
if (litMappingCls == BigDecimal.class) {
// BigDecimal seems to need to have the value put into SQL directly
// (see JDO TCK "Equality" test when comparing with integer-based field).
expr.getSQLStatement().getQueryGenerator().useParameterExpressionAsLiteral(lit);
}
needsUpdating = false;
}
}
if (litMappingCls == Byte.class && mappingCls != Byte.class) {
needsUpdating = false;
}
}
if (needsUpdating) {
NucleusLogger.QUERY.debug("Updating mapping of " + lit + " to be " + expr.getJavaTypeMapping());
((SQLExpression) lit).setJavaTypeMapping(expr.getJavaTypeMapping());
}
}
Aggregations