Search in sources :

Example 1 with ColumnMapping

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);
                }
            }
        }
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) Column(org.datanucleus.store.rdbms.table.Column) RelationType(org.datanucleus.metadata.RelationType) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) MappingManager(org.datanucleus.store.rdbms.mapping.MappingManager) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ClassMetaData(org.datanucleus.metadata.ClassMetaData) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping) CorrespondentColumnsMapper(org.datanucleus.store.rdbms.mapping.CorrespondentColumnsMapper)

Example 2 with ColumnMapping

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;
}
Also used : Column(org.datanucleus.store.rdbms.table.Column) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping)

Example 3 with 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);
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping)

Example 4 with ColumnMapping

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;
}
Also used : NullOrderingType(org.datanucleus.store.query.NullOrderingType) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping)

Example 5 with ColumnMapping

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());
    }
}
Also used : PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SingleCollectionMapping(org.datanucleus.store.rdbms.mapping.java.SingleCollectionMapping) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping) BigDecimal(java.math.BigDecimal)

Aggregations

ColumnMapping (org.datanucleus.store.rdbms.mapping.column.ColumnMapping)12 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)4 DatastoreIdentifier (org.datanucleus.store.rdbms.identifier.DatastoreIdentifier)4 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)4 Column (org.datanucleus.store.rdbms.table.Column)4 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)4 NucleusException (org.datanucleus.exceptions.NucleusException)3 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)3 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)3 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)3 SQLException (java.sql.SQLException)2 HashMap (java.util.HashMap)2 Iterator (java.util.Iterator)2 Map (java.util.Map)2 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)2 RelationType (org.datanucleus.metadata.RelationType)2 DatastoreAdapter (org.datanucleus.store.rdbms.adapter.DatastoreAdapter)2 ResultAliasExpression (org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression)2 BigDecimal (java.math.BigDecimal)1 BigInteger (java.math.BigInteger)1