/* (non-Javadoc) * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List) */ public SQLExpression getExpression(SQLExpression expr, List<SQLExpression> args) { if (args == null || args.size() == 0 || args.size() > 1) { throw new NucleusException(Localiser.msg("060016", "containsValue", "MapExpression", 1)); } MapExpression mapExpr = (MapExpression) expr; SQLExpression valExpr = args.get(0); if (valExpr.isParameter()) { // Value is a parameter so make sure its type is set AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData(); if (mmd != null && mmd.getMap() != null) { Class valCls = stmt.getQueryGenerator() .getClassLoaderResolver() .classForName(mmd.getMap().getValueType()); stmt.getQueryGenerator().bindParameter(valExpr.getParameterName(), valCls); } } if (mapExpr instanceof MapLiteral) { MapLiteral lit = (MapLiteral) mapExpr; Map map = (Map) lit.getValue(); if (map == null || map.size() == 0) { return new BooleanLiteral(stmt, expr.getJavaTypeMapping(), Boolean.FALSE); } // TODO If valExpr is a parameter and mapExpr is derived from a parameter ? MapValueLiteral mapValueLiteral = lit.getValueLiteral(); BooleanExpression bExpr = null; List<SQLExpression> elementExprs = mapValueLiteral.getValueExpressions(); for (int i = 0; i < elementExprs.size(); i++) { if (bExpr == null) { bExpr = (elementExprs.get(i)).eq(valExpr); } else { bExpr = bExpr.ior((elementExprs.get(i)).eq(valExpr)); } } if (bExpr != null) { bExpr.encloseInParentheses(); } return bExpr; } if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER) { boolean needsSubquery = getNeedsSubquery(); // TODO Check if *this* "containsValue" is negated, not any of them (and remove above check) if (needsSubquery) { NucleusLogger.QUERY.debug( "map.containsValue on " + mapExpr + "(" + valExpr + ") using SUBQUERY"); return containsAsSubquery(mapExpr, valExpr); } NucleusLogger.QUERY.debug( "map.containsValue on " + mapExpr + "(" + valExpr + ") using INNERJOIN"); return containsAsInnerJoin(mapExpr, valExpr); } return containsAsSubquery(mapExpr, valExpr); }
/* (non-Javadoc) * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List) */ public SQLExpression getExpression(SQLExpression expr, List args) { if (expr != null) { throw new NucleusException(LOCALISER.msg("060002", getFunctionName(), expr)); } else if (args == null || args.size() != 1) { throw new NucleusException(getFunctionName() + " is only supported with a single argument"); } if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.RESULT || stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.HAVING) { // FUNC(argExpr) JavaTypeMapping m = null; if (args.get(0) instanceof SQLExpression) { // Use same java type as the argument SQLExpression argExpr = (SQLExpression) args.get(0); m = getMappingForClass(argExpr.getJavaTypeMapping().getJavaType()); if (args.get(0) instanceof TemporalExpression) { return new AggregateTemporalExpression(stmt, m, getFunctionName(), args); } else { return new AggregateNumericExpression(stmt, m, getFunctionName(), args); } } else { // What is coming through here? // Fallback to the type for this aggregate TODO Allow for temporal types m = getMappingForClass(double.class); return new AggregateNumericExpression(stmt, m, getFunctionName(), args); } } else { // Handle as Subquery "SELECT AVG(expr) FROM tbl" SQLExpression argExpr = (SQLExpression) args.get(0); SQLStatement subStmt = new SQLStatement( stmt, stmt.getRDBMSManager(), argExpr.getSQLTable().getTable(), argExpr.getSQLTable().getAlias(), null); subStmt.setClassLoaderResolver(clr); JavaTypeMapping mapping = stmt.getRDBMSManager() .getMappingManager() .getMappingWithDatastoreMapping(String.class, false, false, clr); String aggregateString = getFunctionName() + "(" + argExpr.toSQLText() + ")"; SQLExpression aggExpr = exprFactory.newLiteral(subStmt, mapping, aggregateString); ((StringLiteral) aggExpr).generateStatementWithoutQuotes(); subStmt.select(aggExpr, null); JavaTypeMapping subqMapping = exprFactory.getMappingForType(Integer.class, false); SQLExpression subqExpr = null; if (argExpr instanceof TemporalExpression) { subqExpr = new TemporalSubqueryExpression(stmt, subStmt); } else { subqExpr = new NumericSubqueryExpression(stmt, subStmt); } subqExpr.setJavaTypeMapping(subqMapping); return subqExpr; } }
/* (non-Javadoc) * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List) */ public SQLExpression getExpression(SQLExpression expr, List<SQLExpression> args) { if (!expr.isParameter() && expr instanceof StringLiteral) { JavaTypeMapping m = exprFactory.getMappingForType(int.class, false); String val = (String) ((StringLiteral) expr).getValue(); return new IntegerLiteral(stmt, m, Integer.valueOf(val.length()), null); } else if (expr instanceof StringExpression || expr instanceof ParameterLiteral) { ArrayList funcArgs = new ArrayList(); funcArgs.add(expr); return new NumericExpression(stmt, getMappingForClass(int.class), "CHAR_LENGTH", funcArgs); } else { throw new NucleusException(Localiser.msg("060001", "length", expr)); } }
/** * Utility that does a discriminator candidate query for the specified candidate and subclasses * and returns the class name of the instance that has the specified identity (if any). * * @param storeMgr RDBMS StoreManager * @param ec execution context * @param id The id * @param cmd Metadata for the root candidate class * @return Name of the class with this identity (or null if none found) */ public static String getClassNameForIdUsingDiscriminator( RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, AbstractClassMetaData cmd) { // Check for input error if (cmd == null || id == null) { return null; } SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory(); ClassLoaderResolver clr = ec.getClassLoaderResolver(); DatastoreClass primaryTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); // Form the query to find which one of these classes has the instance with this id DiscriminatorStatementGenerator stmtGen = new DiscriminatorStatementGenerator( storeMgr, clr, clr.classForName(cmd.getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM); SelectStatement sqlStmt = stmtGen.getStatement(); // Select the discriminator JavaTypeMapping discrimMapping = primaryTable.getDiscriminatorMapping(true); SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable( sqlStmt, sqlStmt.getPrimaryTable(), discrimMapping); sqlStmt.select(discrimSqlTbl, discrimMapping, null); // Restrict to this id JavaTypeMapping idMapping = primaryTable.getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression sqlFldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression sqlFldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(sqlFldExpr.eq(sqlFldVal), true); // Perform the query try { ManagedConnection mconn = storeMgr.getConnection(ec); SQLController sqlControl = storeMgr.getSQLController(); if (ec.getSerializeReadForClass(cmd.getFullClassName())) { sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true); } try { PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmt, ec, mconn, null, null); String statement = sqlStmt.getSQLText().toSQL(); try { ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps); try { if (rs != null) { while (rs.next()) { DiscriminatorMetaData dismd = discrimMapping.getTable().getDiscriminatorMetaData(); return RDBMSQueryUtils.getClassNameFromDiscriminatorResultSetRow( discrimMapping, dismd, rs, ec); } } } finally { rs.close(); } } finally { sqlControl.closeStatement(mconn, ps); } } finally { mconn.release(); } } catch (SQLException sqe) { NucleusLogger.DATASTORE.error("Exception thrown on querying of discriminator for id", sqe); throw new NucleusDataStoreException(sqe.toString(), sqe); } return null; }
/** * Utility that does a union candidate query for the specified candidate(s) and subclasses and * returns the class name of the instance that has the specified identity (if any). * * @param storeMgr RDBMS StoreManager * @param ec execution context * @param id The id * @param rootCmds Metadata for the classes at the root * @return Name of the class with this identity (or null if none found) */ public static String getClassNameForIdUsingUnion( RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, List<AbstractClassMetaData> rootCmds) { // Check for input error if (rootCmds == null || rootCmds.isEmpty() || id == null) { return null; } SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory(); ClassLoaderResolver clr = ec.getClassLoaderResolver(); // Form a query UNIONing all possible root candidates (and their subclasses) Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator(); AbstractClassMetaData sampleCmd = null; // Metadata for sample class in the tree so we can check if needs locking SelectStatement sqlStmtMain = null; while (rootCmdIter.hasNext()) { AbstractClassMetaData rootCmd = rootCmdIter.next(); DatastoreClass rootTbl = storeMgr.getDatastoreClass(rootCmd.getFullClassName(), clr); if (rootTbl == null) { // Class must be using "subclass-table" (no table of its own) so find where it is AbstractClassMetaData[] subcmds = storeMgr.getClassesManagingTableForClass(rootCmd, clr); if (subcmds == null || subcmds.length == 0) { // No table for this class so ignore } else { for (int i = 0; i < subcmds.length; i++) { UnionStatementGenerator stmtGen = new UnionStatementGenerator( storeMgr, clr, clr.classForName(subcmds[i].getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); if (sqlStmtMain == null) { sampleCmd = subcmds[i]; sqlStmtMain = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID"); sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true); } else { SelectStatement sqlStmt = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true); sqlStmtMain.union(sqlStmt); } } } } else { UnionStatementGenerator stmtGen = new UnionStatementGenerator( storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), true, null, null); stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); if (sqlStmtMain == null) { sampleCmd = rootCmd; sqlStmtMain = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID"); sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true); } else { SelectStatement sqlStmt = stmtGen.getStatement(); // WHERE (object id) = ? JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping(); JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping); SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping); SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID"); sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true); sqlStmtMain.union(sqlStmt); } } } // Perform the query try { ManagedConnection mconn = storeMgr.getConnection(ec); SQLController sqlControl = storeMgr.getSQLController(); if (ec.getSerializeReadForClass(sampleCmd.getFullClassName())) { sqlStmtMain.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true); } try { PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement( sqlStmtMain, ec, mconn, null, null); String statement = sqlStmtMain.getSQLText().toSQL(); try { ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps); try { if (rs != null) { while (rs.next()) { try { return rs.getString(UnionStatementGenerator.NUC_TYPE_COLUMN).trim(); } catch (SQLException sqle) { } } } } finally { rs.close(); } } finally { sqlControl.closeStatement(mconn, ps); } } finally { mconn.release(); } } catch (SQLException sqe) { NucleusLogger.DATASTORE.error("Exception with UNION statement", sqe); throw new NucleusDataStoreException(sqe.toString()); } return null; }
/** * 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><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><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> * </ul> * * and returns a BooleanSubqueryExpression ("EXISTS (subquery)") * * @param mapExpr Map expression * @param valExpr Expression for the value * @return Contains expression */ protected SQLExpression containsAsSubquery(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(); MetaDataManager mmgr = storeMgr.getMetaDataManager(); AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData(); AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr, mmgr); MapTable joinTbl = (MapTable) storeMgr.getTable(mmd); SQLStatement subStmt = null; if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) { // JoinTable Map if (valCmd == null) { // Map<?, Non-PC> subStmt = new SQLStatement(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 SQLStatement(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.innerJoin( subStmt.getPrimaryTable(), valTbl.getIdMapping(), joinTbl, null, joinTbl.getValueMapping(), null, null); // 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, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK); } subStmt = new SQLStatement(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, mmgr); 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, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK); } AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy()); if (valCmd == null) { subStmt = new SQLStatement(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 SQLStatement(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.innerJoin( subStmt.getPrimaryTable(), valTbl.getIdMapping(), keyTbl, null, keyTbl.getMemberMapping(keyValMmd), null, null); // 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); }
/** * Method to return an expression for Map.containsValue using INNER JOIN to the element. This is * only for use when there are no "!containsValue" and no "OR" operations. Creates SQL by adding * INNER JOIN to the join table (where it exists), and also to the value table adding an AND * condition on the value (with value of the valueExpr). Returns a BooleanExpression "TRUE" (since * the INNER JOIN will guarantee if the value is contained of not). * * @param mapExpr Map expression * @param valExpr Expression for the value * @return Contains expression */ protected SQLExpression containsAsInnerJoin(MapExpression mapExpr, SQLExpression valExpr) { boolean valIsUnbound = (valExpr instanceof UnboundExpression); String varName = null; String valAlias = null; if (valIsUnbound) { varName = ((UnboundExpression) valExpr).getVariableName(); NucleusLogger.QUERY.debug( "map.containsValue(" + valExpr + ") binding unbound variable " + varName + " using INNER JOIN"); // TODO What if the variable is declared as a subtype, handle this see // CollectionContainsMethod } else if (!stmt.getQueryGenerator().hasExplicitJoins()) { JoinType joinType = stmt.getJoinTypeForTable(valExpr.getSQLTable()); if (joinType == JoinType.CROSS_JOIN) { // Value is currently joined via CROSS JOIN, so remove it (and use INNER JOIN below) valAlias = stmt.removeCrossJoin(valExpr.getSQLTable()); valIsUnbound = true; NucleusLogger.QUERY.debug( "map.containsValue(" + valExpr + ") was previously bound as CROSS JOIN but changing to INNER JOIN"); } // TODO If owner is joined via CROSS JOIN and value is already present then remove CROSS JOIN // and join via INNER JOIN } RDBMSStoreManager storeMgr = stmt.getRDBMSManager(); MetaDataManager mmgr = storeMgr.getMetaDataManager(); AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData(); AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr, mmgr); if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) { // Map formed in join table - add join to join table, then to value table (if present) MapTable mapTbl = (MapTable) storeMgr.getTable(mmd); SQLTable joinSqlTbl = stmt.innerJoin( mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null); if (valCmd != null) { if (valIsUnbound) { DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr); SQLTable valSqlTbl = stmt.innerJoin( joinSqlTbl, mapTbl.getValueMapping(), valTbl, valAlias, valTbl.getIdMapping(), null, null); // Bind the variable in the QueryGenerator valExpr = exprFactory.newExpression(stmt, valSqlTbl, valSqlTbl.getTable().getIdMapping()); stmt.getQueryGenerator() .bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping()); } else { // Add restrict to value SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping()); stmt.whereAnd(valIdExpr.eq(valExpr), true); } } else { if (valIsUnbound) { // Bind the variable in the QueryGenerator valExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping()); stmt.getQueryGenerator() .bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping()); } else { // Add restrict to value SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping()); stmt.whereAnd(valIdExpr.eq(valExpr), true); } } } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) { // Map formed in value table - add join to value table DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr); JavaTypeMapping ownerMapping = null; if (mmd.getMappedBy() != null) { ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy())); } else { ownerMapping = valTbl.getExternalMapping(mmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK); } SQLTable valSqlTbl = stmt.innerJoin( mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, valAlias, ownerMapping, null, null); if (valIsUnbound) { // Bind the variable in the QueryGenerator valExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping()); stmt.getQueryGenerator() .bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping()); } else { // Add restrict to value SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping()); stmt.whereAnd(valIdExpr.eq(valExpr), true); } } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) { // Map formed in key table - add join to key table then to value table AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr, mmgr); DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr); AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy()); JavaTypeMapping ownerMapping = null; if (mmd.getMappedBy() != null) { ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy())); } else { ownerMapping = keyTbl.getExternalMapping(mmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK); } SQLTable keySqlTbl = stmt.innerJoin( mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, null, ownerMapping, null, null); if (valCmd != null) { DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr); SQLTable valSqlTbl = stmt.innerJoin( keySqlTbl, keyTbl.getMemberMapping(keyValMmd), valTbl, valAlias, valTbl.getIdMapping(), null, null); if (valIsUnbound) { // Bind the variable in the QueryGenerator valExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping()); stmt.getQueryGenerator() .bindVariable(varName, valCmd, valExpr.getSQLTable(), valExpr.getJavaTypeMapping()); } else { // Add restrict to value SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping()); stmt.whereAnd(valIdExpr.eq(valExpr), true); } } else { if (valIsUnbound) { // Bind the variable in the QueryGenerator valExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd)); stmt.getQueryGenerator() .bindVariable(varName, null, valExpr.getSQLTable(), valExpr.getJavaTypeMapping()); } else { // Add restrict to value SQLExpression valIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd)); stmt.whereAnd(valIdExpr.eq(valExpr), true); } } } JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true); return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true)); }