Search in sources :

Example 16 with JoinTable

use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.

the class AbstractMapStore method updatedEmbeddedKey.

public boolean updatedEmbeddedKey(ObjectProvider op, Object key, int fieldNumber, Object newValue, JavaTypeMapping fieldMapping) {
    boolean modified;
    String stmt = getUpdateEmbeddedKeyStmt(fieldMapping, getOwnerMapping(), getKeyMapping(), getMapTable());
    try {
        ExecutionContext ec = op.getExecutionContext();
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, stmt, false);
            try {
                int jdbcPosition = 1;
                fieldMapping.setObject(ec, ps, MappingHelper.getMappingIndices(jdbcPosition, fieldMapping), key);
                jdbcPosition += fieldMapping.getNumberOfDatastoreMappings();
                jdbcPosition = BackingStoreHelper.populateOwnerInStatement(op, ec, ps, jdbcPosition, this);
                jdbcPosition = BackingStoreHelper.populateEmbeddedKeyFieldsInStatement(op, key, ps, jdbcPosition, (JoinTable) getMapTable(), this);
                sqlControl.executeStatementUpdate(ec, mconn, stmt, ps, true);
                modified = true;
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        NucleusLogger.DATASTORE_PERSIST.warn("Exception during backing store update", e);
        throw new NucleusDataStoreException(Localiser.msg("056010", stmt), e);
    }
    return modified;
}
Also used : NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) SQLException(java.sql.SQLException) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) PreparedStatement(java.sql.PreparedStatement) SQLController(org.datanucleus.store.rdbms.SQLController) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 17 with JoinTable

use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method selectMemberOfSourceInStatement.

/**
 * Method to select the specified member (field/property) of the source table in the passed SQL
 * statement. This populates the mappingDefinition with the column details for this member.
 * @param stmt The SQL statement
 * @param mappingDefinition Mapping definition for the results (will be populated by any
 *                          selected mappings if provided as input)
 * @param fetchPlan FetchPlan
 * @param sourceSqlTbl Table that has the member (or a super-table/secondary-table of this table)
 * @param mmd Meta-data for the field/property in the source that we are selecting
 * @param clr ClassLoader resolver
 * @param maxFetchPlanLimit Max fetch depth from this point to select (0 implies no other objects)
 * @param inputJoinType Optional join type to use for subobjects (otherwise decide join type internally)
 */
public static void selectMemberOfSourceInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JoinType inputJoinType) {
    boolean selectSubobjects = false;
    if (maxFetchPlanLimit > 0) {
        selectSubobjects = true;
    }
    // Set table-group name for any related object we join to (naming based on member name)
    String tableGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
    JavaTypeMapping m = sourceSqlTbl.getTable().getMemberMapping(mmd);
    if (m != null && m.includeInFetchStatement()) {
        RelationType relationType = mmd.getRelationType(clr);
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
        if (!dba.validToSelectMappingInStatement(stmt, m)) {
            // Not valid to select this mapping for this statement so return
            return;
        }
        MetaDataManager mmgr = storeMgr.getMetaDataManager();
        StatementMappingIndex stmtMapping = new StatementMappingIndex(m);
        if (m.getNumberOfDatastoreMappings() > 0) {
            // Select of fields with columns in source table(s)
            // Adds inner/outer join to any required superclass/secondary tables
            SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, m);
            boolean selectFK = true;
            if (selectSubobjects && (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) && !mmd.isSerialized() && !mmd.isEmbedded()) {
                // Related object with FK at this side
                selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
            } else if (selectSubobjects && (!mmd.isEmbedded() && !mmd.isSerialized()) && relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // TODO Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName, true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                // TODO Join to 1 side from join table?
                } else {
                    // N-1 bidirectional FK relation
                    // Related object with FK at this side, so join/select related object as required
                    selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
                }
            }
            if (selectFK) {
                int[] colNumbers = stmt.select(sqlTbl, m, null);
                stmtMapping.setColumnPositions(colNumbers);
            }
        } else {
            // Select of related objects with FK in other table
            if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
                // 1-1 bidirectional relation with FK in related table
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                AbstractMemberMetaData relatedMmd = relatedMmds[0];
                String[] clsNames = null;
                if (mmd.getType().isInterface()) {
                    if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) {
                        // Use field-type since only one class specified
                        Class fldTypeCls = clr.classForName(mmd.getFieldTypes()[0]);
                        if (fldTypeCls.isInterface()) {
                            // User has specified an interface, so find its implementations
                            clsNames = mmgr.getClassesImplementingInterface(mmd.getFieldTypes()[0], clr);
                        } else {
                            // Use user-provided field-type
                            clsNames = new String[] { mmd.getFieldTypes()[0] };
                        }
                    }
                    if (clsNames == null) {
                        clsNames = mmgr.getClassesImplementingInterface(mmd.getTypeName(), clr);
                    }
                } else {
                    String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
                    clsNames = new String[] { typeName };
                }
                DatastoreClass relatedTbl = storeMgr.getDatastoreClass(clsNames[0], clr);
                JavaTypeMapping relatedMapping = relatedTbl.getMemberMapping(relatedMmd);
                JavaTypeMapping relatedDiscrimMapping = relatedTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
                Object[] discrimValues = null;
                JavaTypeMapping relatedTypeMapping = null;
                AbstractClassMetaData relatedCmd = relatedMmd.getAbstractClassMetaData();
                if (relatedDiscrimMapping != null && (relatedCmd.getSuperAbstractClassMetaData() != null || !relatedCmd.getFullClassName().equals(mmd.getTypeName()))) {
                    // Related table has a discriminator and the field can store other types
                    List discValueList = null;
                    for (String clsName : clsNames) {
                        List values = getDiscriminatorValuesForMember(clsName, relatedDiscrimMapping, storeMgr, clr);
                        if (discValueList == null) {
                            discValueList = values;
                        } else {
                            discValueList.addAll(values);
                        }
                    }
                    if (discValueList != null) {
                        discrimValues = discValueList.toArray(new Object[discValueList.size()]);
                    }
                } else if (relatedTbl != relatedMapping.getTable()) {
                    // The relation is to a base class table, and the type stored is a sub-class
                    relatedTypeMapping = relatedTbl.getIdMapping();
                }
                SQLTable relatedSqlTbl = null;
                if (relatedTypeMapping == null) {
                    // Join the 1-1 relation
                    JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                    if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                        inputJoinType = joinType;
                    }
                    relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relatedTbl, null, discrimValues, tableGroupName, joinType);
                    // Select the id mapping in the related table
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                } else {
                    DatastoreClass relationTbl = (DatastoreClass) relatedMapping.getTable();
                    if (relatedTbl != relatedMapping.getTable()) {
                        if (relatedMapping.isNullable()) {
                            // Nullable - left outer join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        } else {
                            // Not nullable - inner join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        }
                    } else {
                        // Join the 1-1 relation
                        JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                        if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                            inputJoinType = joinType;
                        }
                        relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relationTbl, null, null, tableGroupName, joinType);
                    }
                    // Select the id mapping in the subclass of the related table
                    // Note this adds an inner join from relatedTable to its subclass
                    relatedSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, relatedSqlTbl, relatedTbl.getIdMapping());
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
                if (selectSubobjects && !mmd.isSerialized() && !mmd.isEmbedded()) {
                    // Select the fetch-plan fields of the related object
                    StatementClassMapping subMappingDefinition = new StatementClassMapping(null, mmd.getName());
                    selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedMmd.getAbstractClassMetaData(), maxFetchPlanLimit - 1, inputJoinType);
                    if (mappingDefinition != null) {
                        mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
                    }
                }
            } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        if (referenceMapping instanceof ReferenceMapping) {
                            // Join table has a reference mapping pointing to our table, so get the submapping for the implementation
                            ReferenceMapping refMap = (ReferenceMapping) referenceMapping;
                            Class implType = clr.classForName(mmd.getClassName(true));
                            referenceMapping = refMap.getJavaTypeMappingForType(implType);
                        }
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName + "_JOIN", true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
            // TODO Select fetch plan fields of this related object
            } else if (relationType == RelationType.MANY_TO_ONE_UNI) {
                // Add left outer join from {sourceTable}.ID to {joinTable}.OWNER_FK
                PersistableJoinTable joinTable = (PersistableJoinTable) storeMgr.getTable(mmd);
                SQLTable joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), joinTable, null, joinTable.getOwnerMapping(), null, tableGroupName + "_JOIN", true);
                int[] colNumbers = stmt.select(joinSqlTbl, joinTable.getRelatedMapping(), null);
                stmtMapping.setColumnPositions(colNumbers);
            // TODO Select fetch plan fields of this related object
            }
        }
        if (mappingDefinition != null) {
            mappingDefinition.addMappingForMember(mmd.getAbsoluteFieldNumber(), stmtMapping);
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) RelationType(org.datanucleus.metadata.RelationType) List(java.util.List) ArrayList(java.util.ArrayList) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) DatastoreElementContainer(org.datanucleus.store.rdbms.table.DatastoreElementContainer) MetaDataManager(org.datanucleus.metadata.MetaDataManager) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 18 with JoinTable

use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method getSQLTableForMappingOfTable.

/**
 * Method to return the SQLTable where the specified mapping (in the same table group as the provided
 * SQLTable) is defined. If the statement doesn't currently join to the required table then a join will
 * be added. If the required table is a superclass table then the join will be INNER. If the required
 * table is a secondary table then the join will be defined by the meta-data for the secondary table.
 * If this table group is NOT the candidate table group then LEFT OUTER JOIN will be used.
 * @param stmt The statement
 * @param sqlTbl SQLTable to start from for the supplied mapping (may be in super-table, or secondary-table of this)
 * @param mapping The mapping
 * @return The SQLTable for this mapping (may have been added to the statement during this method)
 */
public static SQLTable getSQLTableForMappingOfTable(SQLStatement stmt, SQLTable sqlTbl, JavaTypeMapping mapping) {
    Table table = sqlTbl.getTable();
    if (table instanceof SecondaryDatastoreClass || table instanceof JoinTable) {
        // Secondary/join tables have no inheritance so ought to be correct
        if (mapping.getTable() != null) {
            // Check there is no better table already present in the TableGroup for this mapping
            // This can happen when we do a select of a join table and the element table is in the
            // same table group, so hence already is present
            SQLTable mappingSqlTbl = stmt.getTable(mapping.getTable(), sqlTbl.getGroupName());
            if (mappingSqlTbl != null) {
                return mappingSqlTbl;
            }
        }
        return sqlTbl;
    }
    DatastoreClass sourceTbl = (DatastoreClass) sqlTbl.getTable();
    DatastoreClass mappingTbl = null;
    if (mapping.getTable() != null) {
        mappingTbl = (DatastoreClass) mapping.getTable();
    } else {
        mappingTbl = sourceTbl.getBaseDatastoreClassWithMember(mapping.getMemberMetaData());
    }
    if (mappingTbl == sourceTbl) {
        return sqlTbl;
    }
    // Try to find this datastore table in the same table group
    SQLTable mappingSqlTbl = stmt.getTable(mappingTbl, sqlTbl.getGroupName());
    if (mappingSqlTbl == null) {
        boolean forceLeftOuter = false;
        SQLTableGroup tableGrp = stmt.getTableGroup(sqlTbl.getGroupName());
        if (tableGrp.getJoinType() == JoinType.LEFT_OUTER_JOIN) {
            // This group isn't the candidate group, and we joined to the candidate group using
            // a left outer join originally, so use the same type for this table
            forceLeftOuter = true;
        }
        if (mappingTbl instanceof SecondaryDatastoreClass) {
            // Secondary table, so add inner/outer based on metadata
            boolean innerJoin = true;
            JoinMetaData joinmd = ((SecondaryDatastoreClass) mappingTbl).getJoinMetaData();
            if (joinmd != null && joinmd.isOuter() && !forceLeftOuter) {
                innerJoin = false;
            }
            if (innerJoin && !forceLeftOuter) {
                // Add join from {sourceTbl}.ID to {secondaryTbl}.ID
                mappingSqlTbl = stmt.join(JoinType.INNER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
            } else {
                // Add join from {sourceTbl}.ID to {secondaryTbl}.ID
                mappingSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
            }
        } else {
            if (forceLeftOuter) {
                // Add join from {sourceTbl}.ID to {superclassTbl}.ID
                mappingSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
            } else {
                // Add join from {sourceTbl}.ID to {superclassTbl}.ID
                mappingSqlTbl = stmt.join(JoinType.INNER_JOIN, sqlTbl, sqlTbl.getTable().getIdMapping(), mappingTbl, null, mappingTbl.getIdMapping(), null, sqlTbl.getGroupName());
            }
        }
    }
    return mappingSqlTbl;
}
Also used : PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) JoinMetaData(org.datanucleus.metadata.JoinMetaData) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 19 with JoinTable

use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.

the class MapContainsEntryMethod method containsAsSubquery.

/**
 * Method to return an expression for Map.containsEntry using a subquery "EXISTS".
 * This is for use when there are "!contains" or "OR" operations in the filter.
 * Creates the following SQL,
 * <ul>
 * <li><b>Map using join table</b>
 * <pre>
 * SELECT 1 FROM JOIN_TBL A0_SUB
 * WHERE A0_SUB.JOIN_OWN_ID = A0.ID
 * AND A0_SUB.JOIN_VAL_ID = {valExpr}
 * AND Ao_SUB.JOIN_KEY_ID = {keyExpr}
 * </pre>
 * </li>
 * <li><b>Map with key stored in value</b>
 * <pre>
 * SELECT 1 FROM VAL_TABLE A0_SUB
 * WHERE B0.JOIN_OWN_ID = A0.ID
 * AND A0_SUB.ID = {valExpr}
 * AND A0_SUB.KEY_ID = {keyExpr}
 * </pre>
 * </li>
 * <li><b>Map of value stored in key</b>
 * <pre>
 * SELECT 1 FROM KEY_TABLE A0_SUB
 * WHERE A0_SUB.OWN_ID = A0.ID
 * AND A0_SUB.VAL_ID = {valExpr}
 * AND A0_SUB.ID = {keyExpr}
 * </pre>
 * </li>
 * </ul>
 * and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param keyExpr Expression for the key
 * @param valExpr Expression for the value
 * @return Contains expression
 */
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, SQLExpression valExpr) {
    boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
    String keyVarName = null;
    if (keyIsUnbound) {
        keyVarName = ((UnboundExpression) keyExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + keyVarName + " using SUBQUERY");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    boolean valIsUnbound = (valExpr instanceof UnboundExpression);
    String valVarName = null;
    if (valIsUnbound) {
        valVarName = ((UnboundExpression) valExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + valVarName + " using SUBQUERY");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
    AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
    MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
    SelectStatement subStmt = null;
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // JoinTable Map
        subStmt = new SelectStatement(stmt, storeMgr, joinTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to collection owner
        JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getValueMapping());
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value TODO Add join to valueTbl if present
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key TODO Add join to keyTbl if present
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // Key stored in value table
        DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
        AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
        subStmt = new SelectStatement(stmt, storeMgr, valTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to map owner (on value table)
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getMemberMapping(valKeyMmd));
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key TODO Add join to keyTbl if present
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
        subStmt = new SelectStatement(stmt, storeMgr, keyTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to map owner (on key table)
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getMemberMapping(keyValMmd));
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value TODO Add join to valTbl if present
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        JavaTypeMapping keyMapping = keyTbl.getIdMapping();
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    }
    return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) MapTable(org.datanucleus.store.rdbms.table.MapTable) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 20 with JoinTable

use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.

the class MapSizeMethod method getExpression.

/* (non-Javadoc)
     * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
     */
public SQLExpression getExpression(SQLStatement stmt, SQLExpression expr, List<SQLExpression> args) {
    if (args != null && args.size() > 0) {
        throw new NucleusException(Localiser.msg("060015", "size", "MapExpression"));
    }
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    if (expr instanceof MapLiteral) {
        // Just return the map length since we have the value
        Map map = (Map) ((MapLiteral) expr).getValue();
        return exprFactory.newLiteral(stmt, exprFactory.getMappingForType(int.class, false), Integer.valueOf(map.size()));
    }
    AbstractMemberMetaData ownerMmd = expr.getJavaTypeMapping().getMemberMetaData();
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    // TODO Allow for interface keys/values, etc
    JavaTypeMapping ownerMapping = null;
    Table mapTbl = null;
    if (ownerMmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // JoinTable
        mapTbl = storeMgr.getTable(ownerMmd);
        ownerMapping = ((JoinTable) mapTbl).getOwnerMapping();
    } else if (ownerMmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // ForeignKey from value table to key
        AbstractClassMetaData valueCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(ownerMmd.getMap().getValueType(), clr);
        mapTbl = storeMgr.getDatastoreClass(ownerMmd.getMap().getValueType(), clr);
        if (ownerMmd.getMappedBy() != null) {
            ownerMapping = mapTbl.getMemberMapping(valueCmd.getMetaDataForMember(ownerMmd.getMappedBy()));
        } else {
            ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(ownerMmd, MappingType.EXTERNAL_FK);
        }
    } else if (ownerMmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        // ForeignKey from key table to value
        AbstractClassMetaData keyCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(ownerMmd.getMap().getKeyType(), clr);
        mapTbl = storeMgr.getDatastoreClass(ownerMmd.getMap().getKeyType(), clr);
        if (ownerMmd.getMappedBy() != null) {
            ownerMapping = mapTbl.getMemberMapping(keyCmd.getMetaDataForMember(ownerMmd.getMappedBy()));
        } else {
            ownerMapping = ((DatastoreClass) mapTbl).getExternalMapping(ownerMmd, MappingType.EXTERNAL_FK);
        }
    } else {
        throw new NucleusException("Invalid map for " + expr + " in size() call");
    }
    SelectStatement subStmt = new SelectStatement(stmt, storeMgr, mapTbl, null, null);
    subStmt.setClassLoaderResolver(clr);
    JavaTypeMapping mapping = storeMgr.getMappingManager().getMappingWithDatastoreMapping(String.class, false, false, clr);
    SQLExpression countExpr = exprFactory.newLiteral(subStmt, mapping, "COUNT(*)");
    ((StringLiteral) countExpr).generateStatementWithoutQuotes();
    subStmt.select(countExpr, null);
    SQLExpression elementOwnerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
    SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, expr.getSQLTable(), expr.getSQLTable().getTable().getIdMapping());
    subStmt.whereAnd(elementOwnerExpr.eq(ownerIdExpr), true);
    JavaTypeMapping subqMapping = exprFactory.getMappingForType(Integer.class, false);
    SQLExpression subqExpr = new NumericSubqueryExpression(stmt, subStmt);
    subqExpr.setJavaTypeMapping(subqMapping);
    return subqExpr;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) MapLiteral(org.datanucleus.store.rdbms.sql.expression.MapLiteral) StringLiteral(org.datanucleus.store.rdbms.sql.expression.StringLiteral) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException) Map(java.util.Map) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

JoinTable (org.datanucleus.store.rdbms.table.JoinTable)21 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)14 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)12 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)11 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)11 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)10 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)10 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)9 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)9 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)8 Table (org.datanucleus.store.rdbms.table.Table)8 NucleusException (org.datanucleus.exceptions.NucleusException)7 SQLException (java.sql.SQLException)6 ExecutionContext (org.datanucleus.ExecutionContext)6 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)6 PreparedStatement (java.sql.PreparedStatement)5 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)5 SQLController (org.datanucleus.store.rdbms.SQLController)5 BooleanSubqueryExpression (org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression)5 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)5