Search in sources :

Example 1 with BooleanSubqueryExpression

use of org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression in project datanucleus-rdbms by datanucleus.

the class BulkFetchExistsHandler method getStatementToBulkFetchField.

/**
 * Convenience method to generate a bulk-fetch statement for the specified multi-valued field of the owning query.
 * @param candidateCmd Metadata for the candidate
 * @param parameters Parameters for the query
 * @param mmd Metadata for the multi-valued field
 * @param datastoreCompilation The datastore compilation of the query
 * @param mapperOptions Any options for the query to SQL mapper
 * @return The bulk-fetch statement for retrieving this multi-valued field.
 */
public IteratorStatement getStatementToBulkFetchField(AbstractClassMetaData candidateCmd, AbstractMemberMetaData mmd, Query query, Map parameters, RDBMSQueryCompilation datastoreCompilation, Set<String> mapperOptions) {
    IteratorStatement iterStmt = null;
    ExecutionContext ec = query.getExecutionContext();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager();
    Store backingStore = storeMgr.getBackingStoreForField(clr, mmd, null);
    if (backingStore instanceof JoinSetStore || backingStore instanceof JoinListStore || backingStore instanceof JoinArrayStore) {
        // Set/List/array using join-table : Generate an iterator query of the form
        if (backingStore instanceof JoinSetStore) {
            iterStmt = ((JoinSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else if (backingStore instanceof JoinListStore) {
            iterStmt = ((JoinListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
        } else if (backingStore instanceof JoinArrayStore) {
            iterStmt = ((JoinArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else {
            throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
        }
        // SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM JOIN_TBL INNER_JOIN ELEM_TBL WHERE JOIN_TBL.ELEMENT_ID = ELEM_TBL.ID
        // AND EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND JOIN_TBL.OWNER_ID = OWNER_TBL.ID)
        SelectStatement sqlStmt = iterStmt.getSelectStatement();
        JoinTable joinTbl = (JoinTable) sqlStmt.getPrimaryTable().getTable();
        JavaTypeMapping joinOwnerMapping = joinTbl.getOwnerMapping();
        // Generate the EXISTS subquery (based on the JDOQL/JPQL query)
        SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
        Set<String> options = new HashSet<>();
        if (mapperOptions != null) {
            options.addAll(mapperOptions);
        }
        options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
        sqlMapper.compile();
        // Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
        // ORDER BY in EXISTS is forbidden by some RDBMS
        existsStmt.setOrdering(null, null);
        BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
        sqlStmt.whereAnd(existsExpr, true);
        // Join to outer statement so we restrict to collection elements for the query candidates
        SQLExpression joinTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), joinOwnerMapping);
        SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
        existsStmt.whereAnd(joinTblOwnerExpr.eq(existsOwnerExpr), true);
        // Select the owner candidate so we can separate the collection elements out to their owner
        int[] ownerColIndexes = sqlStmt.select(joinTblOwnerExpr, null);
        StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
        ownerMapIdx.setColumnPositions(ownerColIndexes);
        iterStmt.setOwnerMapIndex(ownerMapIdx);
    } else if (backingStore instanceof FKSetStore || backingStore instanceof FKListStore || backingStore instanceof FKArrayStore) {
        if (backingStore instanceof FKSetStore) {
            iterStmt = ((FKSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else if (backingStore instanceof FKListStore) {
            iterStmt = ((FKListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
        } else if (backingStore instanceof FKArrayStore) {
            iterStmt = ((FKArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else {
            throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
        }
        // Set/List/array using foreign-key : Generate an iterator query of the form
        // SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM ELEM_TBL
        // WHERE EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND ELEM_TBL.OWNER_ID = OWNER_TBL.ID)
        SelectStatement sqlStmt = iterStmt.getSelectStatement();
        // Generate the EXISTS subquery (based on the JDOQL/JPQL query)
        SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
        Set<String> options = new HashSet<>();
        if (mapperOptions != null) {
            options.addAll(mapperOptions);
        }
        options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
        sqlMapper.compile();
        // Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
        // ORDER BY in EXISTS is forbidden by some RDBMS
        existsStmt.setOrdering(null, null);
        BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
        sqlStmt.whereAnd(existsExpr, true);
        // Join to outer statement so we restrict to collection elements for the query candidates
        SQLExpression elemTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), ((BaseContainerStore) backingStore).getOwnerMapping());
        SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
        existsStmt.whereAnd(elemTblOwnerExpr.eq(existsOwnerExpr), true);
        // Select the owner candidate so we can separate the collection elements out to their owner
        int[] ownerColIndexes = sqlStmt.select(elemTblOwnerExpr, null);
        StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
        ownerMapIdx.setColumnPositions(ownerColIndexes);
        iterStmt.setOwnerMapIndex(ownerMapIdx);
    }
    return iterStmt;
}
Also used : JoinArrayStore(org.datanucleus.store.rdbms.scostore.JoinArrayStore) HashSet(java.util.HashSet) Set(java.util.Set) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) IteratorStatement(org.datanucleus.store.rdbms.scostore.IteratorStatement) BaseContainerStore(org.datanucleus.store.rdbms.scostore.BaseContainerStore) JoinArrayStore(org.datanucleus.store.rdbms.scostore.JoinArrayStore) FKArrayStore(org.datanucleus.store.rdbms.scostore.FKArrayStore) JoinSetStore(org.datanucleus.store.rdbms.scostore.JoinSetStore) JoinListStore(org.datanucleus.store.rdbms.scostore.JoinListStore) FKListStore(org.datanucleus.store.rdbms.scostore.FKListStore) FKSetStore(org.datanucleus.store.rdbms.scostore.FKSetStore) Store(org.datanucleus.store.types.scostore.Store) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) JoinSetStore(org.datanucleus.store.rdbms.scostore.JoinSetStore) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) FKArrayStore(org.datanucleus.store.rdbms.scostore.FKArrayStore) BaseContainerStore(org.datanucleus.store.rdbms.scostore.BaseContainerStore) HashSet(java.util.HashSet) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) JoinListStore(org.datanucleus.store.rdbms.scostore.JoinListStore) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) ExecutionContext(org.datanucleus.ExecutionContext) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) FKSetStore(org.datanucleus.store.rdbms.scostore.FKSetStore) FKListStore(org.datanucleus.store.rdbms.scostore.FKListStore) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 2 with BooleanSubqueryExpression

use of org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression in project datanucleus-rdbms by datanucleus.

the class DeleteStatement method getSQLText.

public synchronized SQLText getSQLText() {
    if (sql != null) {
        return sql;
    }
    sql = new SQLText(rdbmsMgr.getDatastoreAdapter().getDeleteTableStatement(primaryTable));
    if (joins != null) {
        // Joins present so convert to "DELETE FROM MYTABLE WHERE EXISTS (SELECT * FROM OTHER_TBL ...)"
        Iterator<SQLJoin> joinIter = joins.iterator();
        // Create sub-statement selecting the first joined table, joining back to the outer statement
        SQLJoin subJoin = joinIter.next();
        SQLStatement subStmt = new SelectStatement(this, rdbmsMgr, subJoin.getTargetTable().getTable(), subJoin.getTargetTable().getAlias(), subJoin.getTargetTable().getGroupName());
        subStmt.whereAnd(subJoin.getCondition(), false);
        if (where != null) {
            // Move the WHERE clause to the sub-statement
            subStmt.whereAnd(where, false);
        }
        // Put any remaining joins into the sub-statement
        while (joinIter.hasNext()) {
            SQLJoin join = joinIter.next();
            subStmt.joins.add(join);
        }
        // Set WHERE clause of outer statement to "EXISTS (sub-statement)"
        BooleanExpression existsExpr = new BooleanSubqueryExpression(this, "EXISTS", subStmt);
        where = existsExpr;
    }
    if (where != null) {
        sql.append(" WHERE ").append(where.toSQLText());
    }
    return sql;
}
Also used : BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression)

Example 3 with BooleanSubqueryExpression

use of org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression in project datanucleus-rdbms by datanucleus.

the class UpdateStatement method getSQLText.

public synchronized SQLText getSQLText() {
    if (sql != null) {
        return sql;
    }
    // Generate the SET component of the statement since some need it to formulate the basic UPDATE component
    SQLText setSQL = new SQLText("SET ");
    if (updates != null && updates.length > 0) {
        for (int i = 0; i < updates.length; i++) {
            if (updates[i] != null) {
                if (i != 0) {
                    setSQL.append(",");
                }
                setSQL.append(updates[i].toSQLText());
            }
        }
    }
    sql = rdbmsMgr.getDatastoreAdapter().getUpdateTableStatement(primaryTable, setSQL);
    if (joins != null) {
        // Joins present so convert to "... WHERE EXISTS (SELECT * FROM OTHER_TBL ...)"
        Iterator<SQLJoin> joinIter = joins.iterator();
        // Create sub-statement selecting the first joined table, joining back to the outer statement
        SQLJoin subJoin = joinIter.next();
        SQLStatement subStmt = new SelectStatement(this, rdbmsMgr, subJoin.getTargetTable().getTable(), subJoin.getTargetTable().getAlias(), subJoin.getTargetTable().getGroupName());
        subStmt.whereAnd(subJoin.getCondition(), false);
        if (where != null) {
            // Move the WHERE clause to the sub-statement
            subStmt.whereAnd(where, false);
        }
        // Put any remaining joins into the sub-statement
        while (joinIter.hasNext()) {
            SQLJoin join = joinIter.next();
            subStmt.joins.add(join);
        }
        // Set WHERE clause of outer statement to "EXISTS (sub-statement)"
        BooleanExpression existsExpr = new BooleanSubqueryExpression(this, "EXISTS", subStmt);
        where = existsExpr;
    }
    if (where != null) {
        sql.append(" WHERE ").append(where.toSQLText());
    }
    return sql;
}
Also used : BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression)

Example 4 with BooleanSubqueryExpression

use of org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression in project datanucleus-rdbms by datanucleus.

the class MapContainsKeyMethod method containsAsSubquery.

/**
 * Method to return an expression for Map.containsKey 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_KEY_ID = {keyExpr}
 * </pre>
 * </li>
 * <li><b>Map with key stored in value</b>
 * <pre>
 * SELECT 1 FROM KEY_TABLE A0_SUB INNER JOIN VALUE_TBL B0 ON ...
 * WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.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.ID = {keyExpr}
 * </pre>
 * </li>
 * </ul>
 * and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param keyExpr Expression for the key
 * @return Contains expression
 */
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr) {
    boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
    String varName = null;
    if (keyIsUnbound) {
        varName = ((UnboundExpression) keyExpr).getVariableName();
        NucleusLogger.QUERY.debug("map.containsKey binding unbound variable " + varName + " 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);
    MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
    SelectStatement subStmt = null;
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // JoinTable Map
        if (keyCmd == null) {
            // Map<Non-PC, ?>
            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 map 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);
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
                stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
                subStmt.whereAnd(elemIdExpr.eq(keyExpr), true);
            }
        } else {
            // Map<PC, ?>
            DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
            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);
            // Join to join table
            SQLTable joinSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), keyTbl.getIdMapping(), joinTbl, null, joinTbl.getKeyMapping(), null, null, true);
            // Restrict to map owner
            JavaTypeMapping ownerMapping = joinTbl.getOwnerMapping();
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
                subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // Key stored in value table
        AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
        DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
        if (keyCmd == null) {
            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)
            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);
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getMemberMapping(valKeyMmd));
                stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                JavaTypeMapping keyMapping = valTbl.getMemberMapping(valKeyMmd);
                SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
                subStmt.whereAnd(elemIdExpr.eq(keyExpr), true);
            }
        } else {
            DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
            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);
            // Join to value table
            SQLTable valSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), keyTbl.getIdMapping(), valTbl, null, valTbl.getMemberMapping(valKeyMmd), null, null, true);
            // Restrict to map owner (on value table)
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, valSqlTbl, ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
                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);
        }
        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);
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getIdMapping());
            stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key
            JavaTypeMapping keyMapping = keyTbl.getIdMapping();
            SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
            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) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 5 with BooleanSubqueryExpression

use of org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression in project datanucleus-rdbms by datanucleus.

the class MapContainsValueMethod method containsAsSubquery.

/**
 * Method to return an expression for Map.containsValue 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}
 * </pre>
 * </li>
 * <li><b>Map with key stored in value</b>
 * <pre>
 * SELECT 1 FROM VAL_TABLE A0_SUB INNER JOIN KEY_TBL B0 ON ...
 * WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.ID = {valExpr}
 * </pre>
 * </li>
 * <li><b>Map of value stored in key</b>
 * <pre>
 * SELECT 1 FROM VAL_TABLE A0_SUB
 * WHERE A0_SUB.OWN_ID = A0.ID AND A0_SUB.ID = {valExpr}
 * </pre>
 * </li>
 * </ul>
 * and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param valExpr Expression for the value
 * @return Contains expression
 */
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression valExpr) {
    boolean valIsUnbound = (valExpr instanceof UnboundExpression);
    String varName = null;
    if (valIsUnbound) {
        varName = ((UnboundExpression) valExpr).getVariableName();
        NucleusLogger.QUERY.debug("map.containsValue binding unbound variable " + varName + " 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 valCmd = mmd.getMap().getValueClassMetaData(clr);
    MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
    SelectStatement subStmt = null;
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // JoinTable Map
        if (valCmd == null) {
            // Map<?, Non-PC>
            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 map 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);
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getValueMapping());
                stmt.getQueryGenerator().bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getValueMapping());
                subStmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        } else {
            // Map<?, PC>
            DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
            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);
            // Join to join table
            SQLTable joinSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), valTbl.getIdMapping(), joinTbl, null, joinTbl.getValueMapping(), null, null, true);
            // Restrict to map owner
            JavaTypeMapping ownerMapping = joinTbl.getOwnerMapping();
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
                subStmt.whereAnd(valIdExpr.eq(valExpr), 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);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        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)
        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);
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
            stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value
            JavaTypeMapping valMapping = valTbl.getIdMapping();
            SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valMapping);
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
        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());
        if (valCmd == null) {
            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);
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getMemberMapping(keyValMmd));
                stmt.getQueryGenerator().bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                JavaTypeMapping valMapping = keyTbl.getMemberMapping(keyValMmd);
                SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valMapping);
                subStmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        } else {
            DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
            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);
            // Join to key table
            SQLTable keySqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), valTbl.getIdMapping(), keyTbl, null, keyTbl.getMemberMapping(keyValMmd), null, null, true);
            // Restrict to map owner (on key table)
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, keySqlTbl, ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
                subStmt.whereAnd(valIdExpr.eq(valExpr), 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) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Aggregations

BooleanSubqueryExpression (org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression)10 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)8 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)7 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)6 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)5 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)5 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)5 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)5 BooleanExpression (org.datanucleus.store.rdbms.sql.expression.BooleanExpression)5 JoinTable (org.datanucleus.store.rdbms.table.JoinTable)5 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)4 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)4 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)4 NucleusException (org.datanucleus.exceptions.NucleusException)3 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)2 ArrayExpression (org.datanucleus.query.expression.ArrayExpression)2 CaseExpression (org.datanucleus.query.expression.CaseExpression)2 ClassExpression (org.datanucleus.query.expression.ClassExpression)2 CreatorExpression (org.datanucleus.query.expression.CreatorExpression)2