/** Test of the retrieval of FKs. */ public void testForeignKeyRetrieval() { addClassesToSchema(new Class[] {SchemaClass1.class, SchemaClass2.class}); PersistenceManager pm = pmf.getPersistenceManager(); RDBMSStoreManager databaseMgr = (RDBMSStoreManager) storeMgr; // Retrieve the table for SchemaClass1 ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null); DatastoreClass table1 = databaseMgr.getDatastoreClass(SchemaClass1.class.getName(), clr); // Check for the FK using the schema handler StoreSchemaHandler handler = databaseMgr.getSchemaHandler(); Connection con = (Connection) databaseMgr .getConnection(((JDOPersistenceManager) pm).getExecutionContext()) .getConnection(); RDBMSTableFKInfo fkInfo = (RDBMSTableFKInfo) handler.getSchemaData(con, "foreign-keys", new Object[] {table1}); // Expecting single FK between SchemaClass1.other and SchemaClass2 assertEquals( "Number of FKs for table " + table1 + " is wrong", 1, fkInfo.getNumberOfChildren()); // Check the FK details ForeignKeyInfo fk = (ForeignKeyInfo) fkInfo.getChild(0); assertEquals("FK Name is wrong", "TABLE1_FK1", fk.getProperty("fk_name")); assertEquals("PK Table Name is wrong", "SCHEMA_TABLE_2", fk.getProperty("pk_table_name")); assertEquals("FK Table Name is wrong", "SCHEMA_TABLE_1", fk.getProperty("fk_table_name")); assertEquals("PK Column Name is wrong", "TABLE2_ID", fk.getProperty("pk_column_name")); assertEquals("FK Column Name is wrong", "OTHER_ID", fk.getProperty("fk_column_name")); }
/** * Method to reserve a block of identities. Note : Only allocates a single id always. * * @param size The block size * @return The reserved block */ public ValueGenerationBlock reserveBlock(long size) { // search an Id in the database PreparedStatement ps = null; ResultSet rs = null; RDBMSStoreManager rdbmsMgr = (RDBMSStoreManager) storeMgr; SQLController sqlControl = rdbmsMgr.getSQLController(); try { String stmt = getStatement(); ps = sqlControl.getStatementForUpdate(connection, stmt, false); rs = sqlControl.executeStatementQuery(null, connection, stmt, ps); if (!rs.next()) { return new ValueGenerationBlock(new Object[] {Long.valueOf(1)}); } return new ValueGenerationBlock(new Object[] {Long.valueOf(rs.getLong(1) + 1)}); } catch (SQLException e) { // TODO adds a message correspondent to the exception. // we need to work to create user friendly messages throw new ValueGenerationException(e.getMessage()); } finally { try { if (rs != null) { rs.close(); } if (ps != null) { sqlControl.closeStatement(connection, ps); } } catch (SQLException e) { // no recoverable error } } }
protected void setStatement() { boolean isEmpty = (value == null || value.size() == 0); if (!isEmpty) { RDBMSStoreManager storeMgr = stmt.getRDBMSManager(); valueExpressions = new ArrayList(); st.append("("); boolean hadPrev = false; Collection values = value.values(); for (Iterator it = values.iterator(); it.hasNext(); ) { Object current = it.next(); if (null != current) { JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(current.getClass(), false); SQLExpression expr = storeMgr.getSQLExpressionFactory().newLiteral(stmt, m, current); // Append the SQLExpression (should be a literal) for the current element. st.append(hadPrev ? "," : ""); st.append(expr); valueExpressions.add(expr); hadPrev = true; } } st.append(")"); } }
/** Test of the retrieval of indices. */ public void testIndexRetrieval() { addClassesToSchema(new Class[] {SchemaClass1.class, SchemaClass2.class}); PersistenceManager pm = pmf.getPersistenceManager(); RDBMSStoreManager databaseMgr = (RDBMSStoreManager) storeMgr; // Retrieve the table for SchemaClass1 ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null); DatastoreClass table1 = databaseMgr.getDatastoreClass(SchemaClass1.class.getName(), clr); DatastoreClass table2 = databaseMgr.getDatastoreClass(SchemaClass2.class.getName(), clr); // Check for the indices using the schema handler StoreSchemaHandler handler = databaseMgr.getSchemaHandler(); Connection con = (Connection) databaseMgr .getConnection(((JDOPersistenceManager) pm).getExecutionContext()) .getConnection(); RDBMSTableIndexInfo indexInfo = (RDBMSTableIndexInfo) handler.getSchemaData(con, "indices", new Object[] {table1}); assertEquals( "Number of Indices for table " + table1 + " is wrong", 3, indexInfo.getNumberOfChildren()); Iterator indexIter = indexInfo.getChildren().iterator(); while (indexIter.hasNext()) { IndexInfo index = (IndexInfo) indexIter.next(); String columnName = (String) index.getProperty("column_name"); boolean unique = !((Boolean) index.getProperty("non_unique")).booleanValue(); if (columnName.equals("OTHER_ID")) { assertFalse("Index for column " + columnName + " is unique!", unique); } else if (columnName.equals("TABLE1_ID1")) { assertTrue("Index for column " + columnName + " is not unique!", unique); } else if (columnName.equals("TABLE1_ID2")) { assertTrue("Index for column " + columnName + " is not unique!", unique); } else { fail("Unexpected index " + columnName + " for table " + table1); } } indexInfo = (RDBMSTableIndexInfo) handler.getSchemaData(con, "indices", new Object[] {table2}); assertEquals( "Number of Indices for table " + table2 + " is wrong", 2, indexInfo.getNumberOfChildren()); indexIter = indexInfo.getChildren().iterator(); while (indexIter.hasNext()) { IndexInfo index = (IndexInfo) indexIter.next(); String columnName = (String) index.getProperty("column_name"); String indexName = (String) index.getProperty("index_name"); boolean unique = !((Boolean) index.getProperty("non_unique")).booleanValue(); if (columnName.equals("VALUE")) { assertFalse("Index for column " + columnName + " is unique!", unique); assertEquals("Index name for column " + columnName + " is wrong!", "VALUE_IDX", indexName); } else if (columnName.equals("TABLE2_ID")) { assertTrue("Index for column " + columnName + " is not unique!", unique); } else { fail("Unexpected index " + columnName + " for table " + table1); } } }
/* (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) { SQLExpression invokedExpr = getInvokedExpression(expr, args, "DAY"); RDBMSStoreManager storeMgr = stmt.getRDBMSManager(); JavaTypeMapping mapping = storeMgr.getMappingManager().getMapping(String.class); ArrayList funcArgs = new ArrayList(); funcArgs.add(exprFactory.newLiteral(stmt, mapping, "day")); funcArgs.add(invokedExpr); return new NumericExpression(stmt, getMappingForClass(int.class), "date_part", funcArgs); }
/** * Method to apply any restrictions to the created ResultSet. * * @param ps The PreparedStatement * @param query The query * @param applyTimeout Whether to apply the query timeout (if any) direct to the PreparedStatement * @throws SQLException Thrown when an error occurs applying the constraints */ public static void prepareStatementForExecution( PreparedStatement ps, Query query, boolean applyTimeout) throws SQLException { NucleusContext nucleusCtx = query.getExecutionContext().getNucleusContext(); RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager(); PersistenceConfiguration conf = nucleusCtx.getPersistenceConfiguration(); if (applyTimeout) { Integer timeout = query.getDatastoreReadTimeoutMillis(); if (timeout != null && timeout > 0) { ps.setQueryTimeout(timeout / 1000); } } // Apply any fetch size int fetchSize = 0; if (query.getFetchPlan().getFetchSize() > 0) { // FetchPlan has a size set so use that fetchSize = query.getFetchPlan().getFetchSize(); } if (storeMgr.getDatastoreAdapter().supportsQueryFetchSize(fetchSize)) { ps.setFetchSize(fetchSize); } // Apply any fetch direction String fetchDir = conf.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); Object fetchDirExt = query.getExtension(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); if (fetchDirExt != null) { fetchDir = (String) fetchDirExt; if (!fetchDir.equals("forward") && !fetchDir.equals("reverse") && !fetchDir.equals("unknown")) { throw new NucleusUserException(LOCALISER.msg("052512")); } } if (fetchDir.equals("reverse")) { ps.setFetchDirection(ResultSet.FETCH_REVERSE); } else if (fetchDir.equals("unknown")) { ps.setFetchDirection(ResultSet.FETCH_UNKNOWN); } // Add a limit on the number of rows to include the maximum we may need long toExclNo = query.getRangeToExcl(); if (toExclNo != 0 && toExclNo != Long.MAX_VALUE) { if (toExclNo > Integer.MAX_VALUE) { // setMaxRows takes an int as input so limit to the correct range ps.setMaxRows(Integer.MAX_VALUE); } else { ps.setMaxRows((int) toExclNo); } } }
/** * Return the SQL statement. TODO Allow this to work in different catalog/schema * * @return statement */ private String getStatement() { RDBMSStoreManager srm = (RDBMSStoreManager) storeMgr; StringBuilder stmt = new StringBuilder(); stmt.append("SELECT max("); stmt.append( srm.getIdentifierFactory() .getIdentifierInAdapterCase((String) properties.get("column-name"))); stmt.append(") FROM "); stmt.append( srm.getIdentifierFactory() .getIdentifierInAdapterCase((String) properties.get("table-name"))); return stmt.toString(); }
/* (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 instanceof TypeConverterExpression) || !(((TypeConverterExpression) expr).getDelegate() instanceof TemporalExpression)) { throw new NucleusException(Localiser.msg("060001", "getHour", expr)); } RDBMSStoreManager storeMgr = stmt.getRDBMSManager(); JavaTypeMapping mapping = storeMgr.getMappingManager().getMapping(String.class); SQLExpression hh = exprFactory.newLiteral(stmt, mapping, "HH24"); List funcArgs = new ArrayList(); funcArgs.add(expr); funcArgs.add(hh); List funcArgs2 = new ArrayList(); funcArgs2.add(new StringExpression(stmt, mapping, "TO_CHAR", funcArgs)); return new NumericExpression(stmt, getMappingForClass(int.class), "TO_NUMBER", funcArgs2); }
/** * Method to create the repository for ids to be stored. * * @return Whether it was created successfully. */ protected boolean createRepository() { RDBMSStoreManager srm = (RDBMSStoreManager) storeMgr; if (!srm.isAutoCreateTables()) { throw new NucleusUserException(LOCALISER.msg("040011", sequenceTable)); } try { if (sequenceTable == null) { initialiseSequenceTable(); } sequenceTable.exists((Connection) connection.getConnection(), true); repositoryExists = true; return true; } catch (SQLException sqle) { throw new ValueGenerationException( "Exception thrown calling table.exists() for " + sequenceTable, sqle); } }
/** Method to initialise the sequence table used for storing the sequence values. */ protected void initialiseSequenceTable() { // Set catalog/schema name (using properties, and if not specified using the values for the // table) String catalogName = properties.getProperty("sequence-catalog-name"); if (catalogName == null) { catalogName = properties.getProperty("catalog-name"); } String schemaName = properties.getProperty("sequence-schema-name"); if (schemaName == null) { schemaName = properties.getProperty("schema-name"); } String tableName = (properties.getProperty("sequence-table-name") == null ? DEFAULT_TABLE_NAME : properties.getProperty("sequence-table-name")); RDBMSStoreManager storeMgr = (RDBMSStoreManager) this.storeMgr; DatastoreAdapter dba = storeMgr.getDatastoreAdapter(); DatastoreIdentifier identifier = storeMgr.getIdentifierFactory().newTableIdentifier(tableName); if (dba.supportsOption(DatastoreAdapter.CATALOGS_IN_TABLE_DEFINITIONS) && catalogName != null) { identifier.setCatalogName(catalogName); } if (dba.supportsOption(DatastoreAdapter.SCHEMAS_IN_TABLE_DEFINITIONS) && schemaName != null) { identifier.setSchemaName(schemaName); } DatastoreClass table = storeMgr.getDatastoreClass(identifier); if (table != null) { sequenceTable = (SequenceTable) table; } else { String sequenceNameColumnName = DEFAULT_SEQUENCE_COLUMN_NAME; String nextValColumnName = DEFAULT_NEXTVALUE_COLUMN_NAME; if (properties.getProperty("sequence-name-column-name") != null) { sequenceNameColumnName = properties.getProperty("sequence-name-column-name"); } if (properties.getProperty("sequence-nextval-column-name") != null) { nextValColumnName = properties.getProperty("sequence-nextval-column-name"); } sequenceTable = new SequenceTable(identifier, storeMgr, sequenceNameColumnName, nextValColumnName); sequenceTable.initialize(storeMgr.getNucleusContext().getClassLoaderResolver(null)); } }
/** Test of the retrieval of PKs. */ public void testPrimaryKeyRetrieval() { addClassesToSchema(new Class[] {SchemaClass1.class, SchemaClass2.class}); PersistenceManager pm = pmf.getPersistenceManager(); RDBMSStoreManager databaseMgr = (RDBMSStoreManager) storeMgr; // Retrieve the table for SchemaClass1 ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null); DatastoreClass table1 = databaseMgr.getDatastoreClass(SchemaClass1.class.getName(), clr); DatastoreClass table2 = databaseMgr.getDatastoreClass(SchemaClass2.class.getName(), clr); // Check for the FK using the schema handler StoreSchemaHandler handler = databaseMgr.getSchemaHandler(); Connection con = (Connection) databaseMgr .getConnection(((JDOPersistenceManager) pm).getExecutionContext()) .getConnection(); RDBMSTablePKInfo pkInfo1 = (RDBMSTablePKInfo) handler.getSchemaData(con, "primary-keys", new Object[] {table1}); RDBMSTablePKInfo pkInfo2 = (RDBMSTablePKInfo) handler.getSchemaData(con, "primary-keys", new Object[] {table2}); // Expecting 2 PK columns for SchemaClass1 // TODO Enable checks on the PK name (when JDBC drivers return it correctly) assertEquals( "Number of PKs for table " + table1 + " is wrong", 2, pkInfo1.getNumberOfChildren()); PrimaryKeyInfo pk = (PrimaryKeyInfo) pkInfo1.getChild(0); assertEquals("Column Name is wrong", "TABLE1_ID1", pk.getProperty("column_name")); // assertEquals("PK Name is wrong", "TABLE1_PK", pk.getProperty("pk_name")); pk = (PrimaryKeyInfo) pkInfo1.getChild(1); assertEquals("Column Name is wrong", "TABLE1_ID2", pk.getProperty("column_name")); // assertEquals("PK Name is wrong", "TABLE1_PK", pk.getProperty("pk_name")); // Expecting 1 PK column for SchemaClass assertEquals( "Number of PKs for table " + table1 + " is wrong", 1, pkInfo2.getNumberOfChildren()); pk = (PrimaryKeyInfo) pkInfo2.getChild(0); assertEquals("Column Name is wrong", "TABLE2_ID", pk.getProperty("column_name")); // assertEquals("PK Name is wrong", "TABLE2_PK", pk.getProperty("pk_name")); }
/** Test of the retrieval of columns. */ public void testColumnRetrieval() { addClassesToSchema(new Class[] {SchemaClass1.class, SchemaClass2.class}); PersistenceManager pm = pmf.getPersistenceManager(); RDBMSStoreManager databaseMgr = (RDBMSStoreManager) storeMgr; StoreSchemaHandler handler = databaseMgr.getSchemaHandler(); ClassLoaderResolver clr = storeMgr.getNucleusContext().getClassLoaderResolver(null); Connection con = (Connection) databaseMgr .getConnection(((JDOPersistenceManager) pm).getExecutionContext()) .getConnection(); // Retrieve and check the table for SchemaClass1 DatastoreClass table1 = databaseMgr.getDatastoreClass(SchemaClass1.class.getName(), clr); RDBMSTableInfo tableInfo1 = (RDBMSTableInfo) handler.getSchemaData(con, "columns", new Object[] {table1}); assertEquals( "Number of columns for table " + table1 + " is wrong", 4, tableInfo1.getNumberOfChildren()); Iterator colsIter = tableInfo1.getChildren().iterator(); Collection colNamesPresent = new HashSet(); colNamesPresent.add("TABLE1_ID1"); colNamesPresent.add("TABLE1_ID2"); colNamesPresent.add("NAME"); colNamesPresent.add("OTHER_ID"); while (colsIter.hasNext()) { RDBMSColumnInfo colInfo = (RDBMSColumnInfo) colsIter.next(); if (colInfo.getColumnName().equals("TABLE1_ID1")) { colNamesPresent.remove(colInfo.getColumnName()); } if (colInfo.getColumnName().equals("TABLE1_ID2")) { colNamesPresent.remove(colInfo.getColumnName()); } if (colInfo.getColumnName().equals("NAME")) { colNamesPresent.remove(colInfo.getColumnName()); } if (colInfo.getColumnName().equals("OTHER_ID")) { colNamesPresent.remove(colInfo.getColumnName()); } } assertTrue( "Some columns expected were not present in the datastore table : " + StringUtils.collectionToString(colNamesPresent), colNamesPresent.size() == 0); // Retrieve and check the table for SchemaClass2 DatastoreClass table2 = databaseMgr.getDatastoreClass(SchemaClass2.class.getName(), clr); RDBMSTableInfo tableInfo2 = (RDBMSTableInfo) handler.getSchemaData(con, "columns", new Object[] {table2}); assertEquals( "Number of columns for table " + table2 + " is wrong", 3, tableInfo2.getNumberOfChildren()); colsIter = tableInfo2.getChildren().iterator(); colNamesPresent.clear(); colNamesPresent.add("TABLE2_ID"); colNamesPresent.add("NAME"); colNamesPresent.add("VALUE"); while (colsIter.hasNext()) { RDBMSColumnInfo colInfo = (RDBMSColumnInfo) colsIter.next(); if (colInfo.getColumnName().equals("TABLE2_ID")) { colNamesPresent.remove(colInfo.getColumnName()); } if (colInfo.getColumnName().equals("NAME")) { colNamesPresent.remove(colInfo.getColumnName()); assertEquals( "Length of column " + colInfo.getColumnName() + " has incorrect length", 20, colInfo.getColumnSize()); } if (colInfo.getColumnName().equals("VALUE")) { colNamesPresent.remove(colInfo.getColumnName()); } } assertTrue( "Some columns expected were not present in the datastore table : " + StringUtils.collectionToString(colNamesPresent), colNamesPresent.size() == 0); // Now check retrieval of a column for a table RDBMSColumnInfo colInfo = (RDBMSColumnInfo) handler.getSchemaData(con, "column", new Object[] {table2, "VALUE"}); assertNotNull("Column VALUE for table " + table2 + " was not found", colInfo); assertEquals("Column name is wrong", "VALUE", colInfo.getColumnName()); }
/** * Method to return a statement selecting the candidate table(s) required to cover all possible * types for this candidates inheritance strategy. * * @param storeMgr RDBMS StoreManager * @param parentStmt Parent statement (if there is one) * @param cmd Metadata for the class * @param clsMapping Mapping for the results of the statement * @param ec ExecutionContext * @param candidateCls Candidate class * @param subclasses Whether to create a statement for subclasses of the candidate too * @param result The result clause * @param candidateAlias alias for the candidate (if any) * @param candidateTableGroupName TableGroup name for the candidate (if any) * @return The SQLStatement * @throws NucleusException if there are no tables for concrete classes in this query (hence would * return null) */ public static SQLStatement getStatementForCandidates( RDBMSStoreManager storeMgr, SQLStatement parentStmt, AbstractClassMetaData cmd, StatementClassMapping clsMapping, ExecutionContext ec, Class candidateCls, boolean subclasses, String result, String candidateAlias, String candidateTableGroupName) { SQLStatement stmt = null; DatastoreIdentifier candidateAliasId = null; if (candidateAlias != null) { candidateAliasId = storeMgr.getIdentifierFactory().newTableIdentifier(candidateAlias); } ClassLoaderResolver clr = ec.getClassLoaderResolver(); List<DatastoreClass> candidateTables = new ArrayList<DatastoreClass>(); if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) { DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); if (candidateTable != null) { candidateTables.add(candidateTable); } if (subclasses) { Collection<String> subclassNames = storeMgr.getSubClassesForClass(cmd.getFullClassName(), subclasses, clr); if (subclassNames != null) { Iterator<String> subclassIter = subclassNames.iterator(); while (subclassIter.hasNext()) { String subclassName = subclassIter.next(); DatastoreClass tbl = storeMgr.getDatastoreClass(subclassName, clr); if (tbl != null) { candidateTables.add(tbl); } } } } Iterator<DatastoreClass> iter = candidateTables.iterator(); int maxClassNameLength = cmd.getFullClassName().length(); while (iter.hasNext()) { DatastoreClass cls = iter.next(); String className = cls.getType(); if (className.length() > maxClassNameLength) { maxClassNameLength = className.length(); } } iter = candidateTables.iterator(); while (iter.hasNext()) { DatastoreClass cls = iter.next(); SQLStatement tblStmt = new SQLStatement(parentStmt, storeMgr, cls, candidateAliasId, candidateTableGroupName); tblStmt.setClassLoaderResolver(clr); tblStmt.setCandidateClassName(cls.getType()); // Add SELECT of dummy column accessible as "NUCLEUS_TYPE" containing the classname JavaTypeMapping m = storeMgr.getMappingManager().getMapping(String.class); String nuctypeName = cls.getType(); if (maxClassNameLength > nuctypeName.length()) { nuctypeName = StringUtils.leftAlignedPaddedString(nuctypeName, maxClassNameLength); } StringLiteral lit = new StringLiteral(tblStmt, m, nuctypeName, null); tblStmt.select(lit, UnionStatementGenerator.NUC_TYPE_COLUMN); if (stmt == null) { stmt = tblStmt; } else { stmt.union(tblStmt); } } if (clsMapping != null) { clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.NUC_TYPE_COLUMN); } } else { // "new-table", "superclass-table", "subclass-table" List<Class> candidateClasses = new ArrayList<Class>(); if (ClassUtils.isReferenceType(candidateCls)) { // Persistent interface, so find all persistent implementations String[] clsNames = storeMgr .getNucleusContext() .getMetaDataManager() .getClassesImplementingInterface(candidateCls.getName(), clr); for (int i = 0; i < clsNames.length; i++) { Class cls = clr.classForName(clsNames[i]); DatastoreClass table = storeMgr.getDatastoreClass(clsNames[i], clr); candidateClasses.add(cls); candidateTables.add(table); AbstractClassMetaData implCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(cls, clr); if (implCmd.getIdentityType() != cmd.getIdentityType()) { throw new NucleusUserException( "You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") " + " uses a different identity type!"); } else if (cmd.getIdentityType() == IdentityType.APPLICATION) { if (cmd.getPKMemberPositions().length != implCmd.getPKMemberPositions().length) { throw new NucleusUserException( "You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") " + " has a different number of PK members!"); } } } } else { DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr); if (candidateTable != null) { // Candidate has own table candidateClasses.add(candidateCls); candidateTables.add(candidateTable); } else { // Candidate stored in subclass tables AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(cmd, clr); if (cmds != null && cmds.length > 0) { for (int i = 0; i < cmds.length; i++) { DatastoreClass table = storeMgr.getDatastoreClass(cmds[i].getFullClassName(), clr); Class cls = clr.classForName(cmds[i].getFullClassName()); candidateClasses.add(cls); candidateTables.add(table); } } else { throw new UnsupportedOperationException( "No tables for query of " + cmd.getFullClassName()); } } } for (int i = 0; i < candidateTables.size(); i++) { DatastoreClass tbl = candidateTables.get(i); Class cls = candidateClasses.get(i); StatementGenerator stmtGen = null; if (tbl.getDiscriminatorMapping(true) != null || QueryUtils.resultHasOnlyAggregates(result)) { // Either has a discriminator, or only selecting aggregates so need single select stmtGen = new DiscriminatorStatementGenerator( storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName); stmtGen.setOption(StatementGenerator.OPTION_RESTRICT_DISCRIM); } else { stmtGen = new UnionStatementGenerator( storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName); if (result == null) { // Returning one row per candidate so include distinguisher column stmtGen.setOption(StatementGenerator.OPTION_SELECT_NUCLEUS_TYPE); clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.NUC_TYPE_COLUMN); } } stmtGen.setParentStatement(parentStmt); SQLStatement tblStmt = stmtGen.getStatement(); if (stmt == null) { stmt = tblStmt; } else { stmt.union(tblStmt); } } } return stmt; }
/** * 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)); }