/** Convenience method to mark PK fields as loaded (if using app id). */
 protected void markPKFieldsAsLoaded() {
   if (cmd.getIdentityType() == IdentityType.APPLICATION) {
     int[] pkPositions = cmd.getPKMemberPositions();
     for (int i = 0; i < pkPositions.length; i++) {
       loadedFields[pkPositions[i]] = true;
     }
   }
 }
  /**
   * Utility to create the application identity columns and mapping. Uses the id mapping of the
   * specified class table and copies the mappings and columns, whilst retaining the passed
   * preferences for column namings. This is used to copy the PK mappings of a superclass table so
   * we have the same PK.
   *
   * @param columnContainer The container of column MetaData with any namings
   * @param refTable The table that we use as reference
   * @param clr The ClassLoaderResolver
   * @param cmd The ClassMetaData
   */
  final void addApplicationIdUsingClassTableId(
      ColumnMetaDataContainer columnContainer,
      DatastoreClass refTable,
      ClassLoaderResolver clr,
      AbstractClassMetaData cmd) {
    ColumnMetaData[] userdefinedCols = null;
    int nextUserdefinedCol = 0;
    if (columnContainer != null) {
      userdefinedCols = columnContainer.getColumnMetaData();
    }

    pkMappings = new JavaTypeMapping[cmd.getPKMemberPositions().length];
    for (int i = 0; i < cmd.getPKMemberPositions().length; i++) {
      AbstractMemberMetaData mmd =
          cmd.getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]);
      JavaTypeMapping mapping = refTable.getMemberMapping(mmd);
      if (mapping == null) {
        // probably due to invalid metadata defined by the user
        throw new NucleusUserException(
            "Cannot find mapping for field "
                + mmd.getFullFieldName()
                + " in table "
                + refTable.toString()
                + " "
                + StringUtils.collectionToString(refTable.getColumns()));
      }

      JavaTypeMapping masterMapping =
          storeMgr.getMappingManager().getMapping(clr.classForName(mapping.getType()));
      masterMapping.setMemberMetaData(mmd); // Update field info in mapping
      masterMapping.setTable(this);
      pkMappings[i] = masterMapping;

      // Loop through each id column in the reference table and add the same here
      // applying the required names from the columnContainer
      for (int j = 0; j < mapping.getNumberOfDatastoreMappings(); j++) {
        JavaTypeMapping m = masterMapping;
        Column refColumn = mapping.getDatastoreMapping(j).getColumn();
        if (mapping instanceof PersistableMapping) {
          m =
              storeMgr
                  .getMappingManager()
                  .getMapping(clr.classForName(refColumn.getJavaTypeMapping().getType()));
          ((PersistableMapping) masterMapping).addJavaTypeMapping(m);
        }

        ColumnMetaData userdefinedColumn = null;
        if (userdefinedCols != null) {
          for (int k = 0; k < userdefinedCols.length; k++) {
            if (refColumn.getIdentifier().toString().equals(userdefinedCols[k].getTarget())) {
              userdefinedColumn = userdefinedCols[k];
              break;
            }
          }
          if (userdefinedColumn == null && nextUserdefinedCol < userdefinedCols.length) {
            userdefinedColumn = userdefinedCols[nextUserdefinedCol++];
          }
        }

        // Add this application identity column
        Column idColumn = null;
        if (userdefinedColumn != null) {
          // User has provided a name for this column
          // Currently we only use the column namings from the users definition but we could easily
          // take more of their details.
          idColumn =
              addColumn(
                  refColumn.getStoredJavaType(),
                  storeMgr
                      .getIdentifierFactory()
                      .newIdentifier(IdentifierType.COLUMN, userdefinedColumn.getName()),
                  m,
                  refColumn.getColumnMetaData());
        } else {
          // No name provided so take same as superclass
          idColumn =
              addColumn(
                  refColumn.getStoredJavaType(),
                  refColumn.getIdentifier(),
                  m,
                  refColumn.getColumnMetaData());
        }
        if (mapping.getDatastoreMapping(j).getColumn().getColumnMetaData() != null) {
          refColumn.copyConfigurationTo(idColumn);
        }
        idColumn.setPrimaryKey();

        // Set the column type based on the field.getType()
        getStoreManager()
            .getMappingManager()
            .createDatastoreMapping(m, idColumn, refColumn.getJavaTypeMapping().getType());
      }

      // Update highest field number if this is higher
      int absoluteFieldNumber = mmd.getAbsoluteFieldNumber();
      if (absoluteFieldNumber > highestMemberNumber) {
        highestMemberNumber = absoluteFieldNumber;
      }
    }
  }
예제 #3
0
  /**
   * 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;
  }