SelectQueryPlanpublic class SelectQueryPlan extends QueryPlan This class prepares the generation of select statements,
by joining the constaint stacks of all retrieve descriptors
into one stack. |
Fields Summary |
---|
private static final int | ST_JOINEDThis plan is joined with the parent plan. Used only for dependent plan. | public static final int | ST_C_BUILTThis plans's constraints are already processed. | public static final int | ST_OC_BUILTThis plans's order by constraints are already processed. | protected Constraint | constraintPointer to the retrieve descriptor's constraint stack.
NOTE: The retrieve descriptor's stack will be modified
building the query plan! | public int | optionsBitmask constaining OPT_* Constants defined in {@link RetrieveDescImpl } | private Iterator | fieldIteratorIterator for the retrieve descriptor's list of fields to be retrieved. | private int | aggregateResultTypeAggregate result type from the retrieve descriptor as defined by
{@link FieldTypeEnumeration} | private ArrayList | foreignPlansList of SelectQueryPlan. After this plan is completely built, this field
contains all the foreign plans that could not be joined with this plan. | protected ForeignFieldDesc | parentFieldThis foreign field joins this plan to the parent plan. The field is from
config of the parent plan. Used only for dependent plan. | private boolean | prefetchedThis plan corresponds to prefetched values for parentField .
Used only for dependent plan. | private com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency | concurrency | private BitSet | hierarchicalGroupMaskBitSet containing the hierarchical fetch groups to be retrieved for this plan. | private BitSet | independentGroupMaskBitSet containing the independent fetch groups to be retrieved for this plan. | private BitSet | fieldMaskBitSet containing the fields to be retrieved for this plan | private Map | foreignConstraintPlans | private com.sun.jdo.spi.persistence.support.sqlstore.sql.ResultDesc | resultDesc | private boolean | appendAndOpTakes care of adding an "And" constraint for unbound constraints, e.g.
"empid == department.deptid". As the foreign constraint stack is empty,
we would not add the necessary "And" constraint otherwise. | private static final com.sun.jdo.spi.persistence.utility.logging.Logger | loggerThe logger. |
Constructors Summary |
---|
public SelectQueryPlan(com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc desc, com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager store, com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency concurrency)Creates a new SelectQueryPlan.
super(desc, store);
action = ACT_SELECT;
// Initialize internal fields.
fieldMask = new BitSet();
hierarchicalGroupMask = new BitSet();
independentGroupMask = new BitSet();
this.concurrency = concurrency;
//excludeSubclasses = true;
if (desc instanceof RetrieveDescImpl) {
RetrieveDescImpl retrieveDesc = (RetrieveDescImpl) desc;
retrieveDesc.setPlan(this);
// Get the information from the retrieve descriptor.
constraint = retrieveDesc.getConstraint();
options = retrieveDesc.getOptions();
fieldIterator = retrieveDesc.getFields();
aggregateResultType = retrieveDesc.getAggregateResultType();
} else {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.generic.notinstanceof", desc.getClass().getName(), "RetrieveDescImpl")); // NOI18N
}
|
Methods Summary |
---|
protected void | addColumn(LocalFieldDesc fieldDesc)The addColumn method is used to specify a field for which data needs
to be retrieved and therefore for which we need to select a column.
addColumn(fieldDesc, true, false);
| private void | addColumn(LocalFieldDesc fieldDesc, boolean add, boolean projection)The addColumn method is used to specify a field for which data needs to
be retrieved and therefore for which we need to select a column.
// We first search to see if any of the tables to which the requested
// field is mapped is being used by this query plan. Initially
// there is a select statement for each table so we just append this
// request as a column to the found statement. If none of the tables
// are being used in this query plan then we create a new statement.
//
for (Iterator iter = fieldDesc.getColumnElements(); iter.hasNext(); ) {
ColumnElement columnElement = (ColumnElement) iter.next();
QueryTable table = findQueryTable(columnElement.getDeclaringTable());
if (table == null)
table = addQueryTable(columnElement.getDeclaringTable(), null);
SelectStatement statement = (SelectStatement) getStatement(table);
if (statement == null)
statement = (SelectStatement) addStatement(table);
if (add) {
ColumnRef columnRef = statement.addColumn(columnElement, table);
// initialize the resultDesc
if (resultDesc == null) {
resultDesc = new ResultDesc(config, aggregateResultType);
}
resultDesc.addField(fieldDesc, columnRef, projection);
}
}
| private void | addCorrelatedExistsQuery(ForeignFieldDesc ff, int operation)Adds a subquery constraint for a correlated exists query to the
constraint stack. Also add the table alias from the subquery
to the local table aliases.
Class classType = (ff.cardinalityUPB > 1) ? ff.getComponentType() : ff.getType();
RetrieveDescImpl rd = (RetrieveDescImpl) store.getRetrieveDesc(classType);
SelectQueryPlan subqueryPlan = new CorrelatedExistSelectPlan(rd, store, ff, this);
subqueryPlan.build();
// Make the tables involved in the subquery known to the parent query.
addQueryTables(subqueryPlan.tables);
ConstraintSubquery subqueryConstraint = new ConstraintSubquery();
subqueryConstraint.operation = operation;
subqueryConstraint.plan = subqueryPlan;
constraint.stack.add(subqueryConstraint);
| private void | addCorrelatedInQuery(ConstraintFieldNameSubQuery node)Creates and builds a correlated "In" subquery.
Merges tables from the subquery plan to the current plan and adds
the local fields corresponding to the subquery to the constaints.
The subquery is added to the constraint stack.
FieldDesc field = config.getField(node.fieldName);
RetrieveDescImpl rd = (RetrieveDescImpl) node.desc;
if (field != null && field instanceof ForeignFieldDesc) {
ForeignFieldDesc ff = (ForeignFieldDesc) field;
if (ff.getComponentType() != rd.getPersistenceCapableClass() ) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.constraint.unknownfield", // NOI18N
node.fieldName, rd.getPersistenceCapableClass().getName()));
}
SelectQueryPlan subqueryPlan = new CorrelatedInSelectPlan(rd, store, ff, this);
subqueryPlan.build();
// Make the tables involved in the subquery known to the parent query.
addQueryTables(subqueryPlan.tables);
// Push a new subquery constraint on the stack
ConstraintSubquery subqueryConstraint = new ConstraintSubquery();
subqueryConstraint.plan = subqueryPlan;
constraint.stack.add(subqueryConstraint);
ArrayList localFields = ff.getLocalFields();
// Add the local fields corresponding to the subquery to the stack.
for (int i = 0; i < localFields.size(); i++) {
constraint.addField((LocalFieldDesc) localFields.get(i), this);
}
} else {
// We didn't get a ForeignFieldDesc from config,
// or the field is not present in the config.
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.constraint.unknownfield", // NOI18N
node.fieldName, rd.getPersistenceCapableClass().getName()));
}
| private void | addFetchGroup(int groupID, java.util.ArrayList localFields, java.util.ArrayList foreignFields)Add the fields from the fetch group specified by groupID
to the list of selected fields. The decision which fields are
added is based on the following rules:
- Local fields are added for all the queries and user
projections, that aren't aggregates.
- Only key fields are added for aggregate queries counting persistence capable objects.
- Foreign fields are added only for the projected retrieve descriptor and for
queries that do not have relationsip prefetch disabled.
-
// We should enter this method only if OPT_ADD_FETCHGROUPS is set.
assert (options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0;
ArrayList group = config.getFetchGroup(groupID);
setGroupMask(groupID);
if (group != null) {
for (int i = 0; i < group.size() ; i++) {
FieldDesc f = (FieldDesc) group.get(i);
if (!getFieldMask(f.absoluteID)) {
final boolean isLocalField = f instanceof LocalFieldDesc;
// Prevent testing field again.
setFieldMask(f.absoluteID);
if (isLocalField) {
if ((options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 || f.isKeyField()) {
// pk fields are added before any other fields already
// present in localFields. This is because pk fields
// are the first to be read when resultset is processed.
// Please see IN=8852 for more details.
// All other fields are appended to the list.
int indexToInsert = ( f.isKeyField() ? 0 : localFields.size() );
localFields.add(indexToInsert, f);
}
} else {
// Add foreign fields only if this plan corresponds to the
// projected RD and relationship prefetch is not explicitly
// disabled by the user.
if ( (options & RetrieveDescImpl.OPT_PROJECTION) > 0 &&
(options & RetrieveDescImpl.OPT_ADD_KEYS_ONLY) == 0 &&
(options & RetrieveDescImpl.OPT_DISABLE_RELATIONSHIP_PREFETCH) == 0 ) {
// Add current field to foreignFields as ConstraintFieldName
ForeignFieldDesc ff = (ForeignFieldDesc) f;
RetrieveDescImpl desc = (RetrieveDescImpl)
store.getRetrieveDesc(ff.foreignConfig.getPersistenceCapableClass());
foreignFields.add(new ConstraintFieldName(ff.getName(), desc, true));
}
}
}
}
}
| private void | addFetchGroups(int groupID, java.util.ArrayList localFields, java.util.ArrayList foreignFields)Add the fields from the fetch group specified by groupID
to the list of selected fields. For hierarchical groups, we add all the
groups from GROUP_DEFAULT up to groupID . For independent
groups, we only add the default and the group indicated by
groupID .
if (groupID >= FieldDesc.GROUP_DEFAULT) {
//Hierachical fetch group
for (int i = FieldDesc.GROUP_DEFAULT; i <= groupID; i++) {
if (!getGroupMask(i)) {
addFetchGroup(i, localFields, foreignFields);
}
}
} else if (groupID < FieldDesc.GROUP_NONE) {
if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) {
//Independent fetch group
addFetchGroup(FieldDesc.GROUP_DEFAULT, localFields, foreignFields);
}
if (!getGroupMask(groupID)) {
addFetchGroup(groupID, localFields, foreignFields);
}
}
| protected void | addJoinConstraint(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan fromPlan, com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan toPlan, java.util.ArrayList fromColumns, java.util.ArrayList toColumns, int joinOp)Put in a join constraint to the foreign table.
ConstraintJoin join = new ConstraintJoin();
join.operation = joinOp;
join.fromColumns = fromColumns;
join.fromPlan = fromPlan;
join.toColumns = toColumns;
join.toPlan = toPlan;
constraint.addJoinConstraint(join);
| protected void | addTable(LocalFieldDesc fieldDesc)The addTable method is used to add tables correponding to a field to the plan.
No columns corresponding the field are added to the plan.
addColumn(fieldDesc, false, false);
| public void | build()Builds the query plan for a select type
{@link ActionDesc} (i.e. a {@link RetrieveDesc}).
// Plan must be build only once.
if ((status & ST_BUILT) > 0) {
return;
}
processFields();
processConstraints();
processJoins();
processOrderConstraints();
status |= ST_BUILT;
| private void | doJoin(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan foreignPlan, int joinOperation)Joins the current plan with foreignPlan .
The join operation joinOperation
will be added to the constraint stack.
if ((foreignPlan.status & ST_JOINED) > 0) {
return;
}
mergeConstraints(foreignPlan, joinOperation);
mergeStatements(foreignPlan, joinOperation);
if (foreignPlan.tables != null) {
addQueryTables(foreignPlan.tables);
}
foreignPlan.status = foreignPlan.status | ST_JOINED;
| public Constraint | getConstraint()
return constraint;
| private boolean | getFieldMask(int index)
if (index < 0) {
index = config.fields.size() - index;
}
return fieldMask.get(index);
| private boolean | getGroupMask(int groupID)
if (groupID >= FieldDesc.GROUP_DEFAULT)
return hierarchicalGroupMask.get(groupID);
else if (groupID < FieldDesc.GROUP_NONE)
return independentGroupMask.get(-(groupID + 1));
return true;
| private int | getJoinOperator(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan dependentPlan)Defines the join operator based on the projection property (and
the navigated relationship). Depending on the relationship
cardinality the plans are joined with OP_EQUIJOIN
or OP_LEFTJOIN . Projection queries are always
joined with OP_LEFTJOIN .)
int joinOperator;
ForeignFieldDesc parentField = null;
if (isProjection(this)) {
parentField = dependentPlan.parentField;
} else if (isProjection(dependentPlan)) {
parentField = dependentPlan.parentField.getInverseRelationshipField();
}
if (parentField != null) {
joinOperator = ActionDesc.OP_LEFTJOIN;
// TODO: Check the parentField's cardinality?
// if (parentField.cardinalityUPB == 1) {
// // Join "to one" associations.
// // There are two kinds of "to one" associations:
// if (parentField.cardinalityLWB == 1) {
// // 1-1 associations: (fp.parentField.cardinalityLWB == 1)
// joinOperator = ActionDesc.OP_EQUIJOIN;
// } else {
// // Optional associations: (fp.parentField.cardinalityLWB == 0)
// // The query should return an object, even if the navigated
// // relationship isn't set.
// joinOperator = ActionDesc.OP_LEFTJOIN;
// }
// } else { // parentField.cardinalityUPB > 1
// // To-Many associations are always optional.
// joinOperator = ActionDesc.OP_LEFTJOIN;
// }
} else {
joinOperator = ActionDesc.OP_EQUIJOIN;
}
return joinOperator;
| public java.lang.Object | getResult(com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager pm, java.sql.ResultSet resultData)Extract data from given resultData
return resultDesc.getResult(pm, resultData);
| private boolean | isProjection(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan plan)
return(prefetched
|| (plan.options & RetrieveDescImpl.OPT_PROJECTION) > 0
&& (plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0);
| private void | joinSecondaryTableStatement(SelectStatement statement, SelectStatement secondaryTableStatement)
statement.copyColumns(secondaryTableStatement);
QueryTable secondaryTable = (QueryTable) secondaryTableStatement.getQueryTables().get(0);
ReferenceKeyDesc key = secondaryTable.getTableDesc().getPrimaryTableKey();
addJoinConstraint(this, this,
key.getReferencedKey().getColumns(),
key.getReferencingKey().getColumns(), ActionDesc.OP_LEFTJOIN);
secondaryTableStatement.markJoined();
| private void | mergeConstraints(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan foreignPlan, int joinOperation)Merge the foreign constraints with us.
Adds the appropriate Join-constraint to the stack and merges
the constraint stacks. Adds an And-constraint, if neccessary,
see {@link com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.Constraint#mergeConstraint}.
if (joinOperation != ActionDesc.OP_NONREL_JOIN) {
// Add the join constraint.
if (foreignPlan.parentField.useJoinTable()) {
// The join table is added to the foreign plan while processing
// parent field
addJoinConstraint(this, foreignPlan,
foreignPlan.parentField.localColumns,
foreignPlan.parentField.assocLocalColumns, joinOperation);
addJoinConstraint(foreignPlan, foreignPlan,
foreignPlan.parentField.assocForeignColumns,
foreignPlan.parentField.foreignColumns, joinOperation);
// Except for oracle, the outer join condition will end up in
// from clause. Hence, add OP_AND for Equijoin only
if (joinOperation == ActionDesc.OP_EQUIJOIN) {
constraint.addOperation(ActionDesc.OP_AND);
}
} else {
addJoinConstraint(this, foreignPlan,
foreignPlan.parentField.localColumns,
foreignPlan.parentField.foreignColumns, joinOperation);
}
}
// Copy the constraints from the toStack.
boolean addAnd = constraint.mergeConstraint(foreignPlan.constraint, joinOperation);
if (addAnd || foreignPlan.appendAndOp) {
constraint.addOperation(ActionDesc.OP_AND);
}
| private void | mergeResultDesc(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan foreignPlan)Joins foreignPlan 's result
descriptor with the current plan.
ResultDesc foreignResult = foreignPlan.resultDesc;
if (resultDesc != null && foreignResult != null) {
resultDesc.doJoin(foreignResult, foreignPlan.parentField);
} else if (resultDesc == null) {
resultDesc = foreignResult;
}
| private void | mergeStatements(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan foreignPlan, int joinOperation)Merge the foreign statement with us.
If there is no foreign statement,
this method just returns.
SelectStatement fromStatement;
SelectStatement toStatement;
if (foreignPlan.statements.size() > 0) {
toStatement = (SelectStatement) foreignPlan.statements.get(0);
// Merge the foreign query with us.
if (statements.size() > 0) {
fromStatement = (SelectStatement) statements.get(0);
// Copy projected columns
fromStatement.copyColumns(toStatement);
// For a non relationship join, we need to add all tables from the
// foreign statement. In any other case, the tables will be added
// when the join operation is processed by the statement.
if (joinOperation == ActionDesc.OP_NONREL_JOIN) {
fromStatement.tableList.addAll(toStatement.tableList);
}
mergeResultDesc(foreignPlan);
if (foreignPlan.prefetched) {
// If the foreign plan is marked as a prefetched plan,
// propagate this information to its resultDesc.
resultDesc.setPrefetching();
}
this.options |= foreignPlan.options;
}
}
| private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan | newForeignConstraintPlan(com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl rd, java.lang.String fieldName)Returns the plan for {@link RetrieveDesc} rd . If there is no
plan associated with rd , a new plan is created.
If fieldName is not null, the returned plan will be matched
with the first plan that was registered for a navigation on the field
or the plan's navigational id. The navigational id is used to discriminate
several navigations on the same field.
SelectQueryPlan fcp = rd.getPlan();
if (fcp == null) {
fcp = new SelectQueryPlan(rd, store, null);
}
// If fieldName is null, it means that we don't know what the relationship
// field name is yet and this query plan is a place holder.
if (fieldName == null) {
return fcp;
}
if (foreignConstraintPlans == null) {
foreignConstraintPlans = new HashMap();
}
SelectQueryPlan masterPlan = null;
Object tag = (rd.getNavigationalId() != null) ? rd.getNavigationalId() : fieldName;
if ((masterPlan = (SelectQueryPlan) foreignConstraintPlans.get(tag)) != null) {
// Share the tables with the master plan.
fcp.tables = masterPlan.tables;
fcp.foreignConstraintPlans = masterPlan.foreignConstraintPlans;
} else {
foreignConstraintPlans.put(tag, fcp);
fcp.foreignConstraintPlans = new HashMap();
}
return fcp;
| public static com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan | newInstance(com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl desc, com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager store, com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency concurrency)Creates a new instance of SelectQueryPlan depending on the retrieve
descriptor options.
SelectQueryPlan plan = null;
if ( (desc.getOptions() & RetrieveDescImpl.OPT_VERIFY) > 0) {
plan = new VerificationSelectPlan(desc, store);
} else {
plan = new SelectQueryPlan(desc, store, concurrency);
}
return plan;
| protected Statement | newStatement()
return new SelectStatement(store.getVendorType(), this);
| protected void | processConstraints()
// Constraints must be build only once.
if ((status & ST_BUILT) > 0 || (status & ST_C_BUILT) > 0) {
return;
}
processLocalConstraints();
// Join all the statements.
processStatements();
processForeignConstraints();
// Joins over unbound variables.
processUnboundConstraints();
status |= ST_C_BUILT;
| private void | processFetchGroups(java.util.ArrayList localFields, java.util.ArrayList foreignFields)Add the fetch group fields to the list of selected fields.
The decision if fetch groups are added is based on the following rules:
- Always add fetch groups for internal queries.
- For external queries, add fetch groups to the projected retrieve
descriptor as marked in RetrieveDescImpl#setFetchGroupOptions(int)
if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) {
int requestedItems = localFields.size() + foreignFields.size();
// Add the default fetch group.
if (!getGroupMask(FieldDesc.GROUP_DEFAULT)) {
addFetchGroups(FieldDesc.GROUP_DEFAULT, localFields, foreignFields);
}
if (requestedItems > 0) {
for (int i = 0; i < localFields.size(); i++) {
FieldDesc f = (FieldDesc) localFields.get(i);
setFieldMask(f.absoluteID);
if (f.fetchGroup != FieldDesc.GROUP_NONE) {
if (!getGroupMask(f.fetchGroup)) {
addFetchGroups(f.fetchGroup, localFields, foreignFields);
}
}
}
for (int i = 0; i < foreignFields.size(); i++) {
ConstraintFieldName cfn = (ConstraintFieldName) foreignFields.get(i);
FieldDesc f = config.getField(cfn.name);
setFieldMask(f.absoluteID);
if (f.fetchGroup != FieldDesc.GROUP_NONE) {
if (!getGroupMask(f.fetchGroup)) {
addFetchGroups(f.fetchGroup, localFields, foreignFields);
}
}
}
}
}
| protected void | processFields()Process the fields from the retrieve descriptor's field list.
Must be overwritten by subquery plans!
ArrayList foreignFields = new ArrayList();
ArrayList localFields = new ArrayList();
LocalFieldDesc projectionField = separateFieldList(localFields, foreignFields);
// Because of a problem with BLOB columns on SQLServer
// fetch group fields are added to the beginning of localFields.
processFetchGroups(localFields, foreignFields);
// For internal queries, processForeignFields might add additional
// fields to localFields, so we call it first.
processForeignFields(foreignFields, localFields);
processLocalFields(localFields, projectionField);
| private void | processForeignConstraints()Builds the constraint plan for foreign constraints on the constraint
stack. This method joins the current plan with all plans
related by foreign constraints found in the plan hierarchy.
List currentStack = constraint.getConstraints();
constraint.stack = new ArrayList();
int index = 0;
while (index < currentStack.size()) {
ConstraintNode node = (ConstraintNode) currentStack.get(index);
if (node instanceof ConstraintForeignFieldName) {
processForeignFieldConstraint((ConstraintForeignFieldName) node);
} else if (node instanceof ConstraintFieldName) {
index = processLocalFieldConstraint((ConstraintFieldName) node, currentStack, index);
} else if (node instanceof ConstraintFieldNameSubQuery) {
addCorrelatedInQuery((ConstraintFieldNameSubQuery) node);
} else {
constraint.stack.add(node);
}
index++;
}
| private void | processForeignField(ConstraintFieldName cfn, java.util.ArrayList localFields)Process the projected foreign field at index index .
Initializes and builds a new SelectQueryPlan for this field and
adds selected columns to the result descriptor. If the field is
navigated only, just adds the statement and table alias.
SelectQueryPlan fp = new SelectQueryPlan(cfn.desc, store, concurrency);
fp.prefetched = cfn.isPrefetched();
if (fp.prefetched) {
// Add fetch groups to the foreign plan if we are prefetching.
fp.options |= RetrieveDescImpl.OPT_ADD_FETCHGROUPS;
}
fp.processParentField(config, cfn.name);
fp.build();
// For navigational queries, add in any additional local fields which
// may be needed by this foreign field (typically the foreign keys).
// For external (user) queries, we just make sure we include the
// corresponding table into the table list.
for (int i = 0; i < fp.parentField.localFields.size(); i++) {
LocalFieldDesc la = (LocalFieldDesc) fp.parentField.localFields.get(i);
if (!getFieldMask(la.absoluteID)) {
if ((options & RetrieveDescImpl.OPT_ADD_FETCHGROUPS) > 0) {
// Add the field to localFields only if this plan corresponds
// to a candidate.
localFields.add(la);
} else {
// This plan is participating in a projection.
// Add the table and a corresponding statement to the plan.
addTable(la);
}
}
}
foreignPlans.add(fp);
| private void | processForeignFieldConstraint(ConstraintForeignFieldName node)Joins the current plan with the constraint node . The constraint
includes the name of the parent field and the retrieve descriptor for the
related class. The plans will be joined with OP_EQUIJOIN .
The constraints processed here have been added by
{@link RetrieveDesc#addConstraint(String, RetrieveDesc)}.
RetrieveDescImpl rd = (RetrieveDescImpl) node.desc;
if (rd == null) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"sqlstore.constraint.noretrievedesc", // NOI18N
node.name, config.getPersistenceCapableClass().getName()));
}
SelectQueryPlan fcp = newForeignConstraintPlan(rd, node.name);
if ((fcp.status & ST_JOINED) == 0) {
fcp.processParentField(config, node.name);
// Joins on constraints always join as equijoin
processJoin(fcp, ActionDesc.OP_EQUIJOIN);
fcp.appendAndOp = true;
} else {
fcp.appendAndOp = false;
}
| private int | processForeignFieldNullComparision(ConstraintFieldName node, java.util.List currentStack, int index)Processes a null comparision on a foreign field.
boolean addCurrentNode = true;
if (node.name != null) {
// The name entry is null for unbound constraints.
FieldDesc f = config.getField(node.name);
if (f instanceof ForeignFieldDesc && (index + 1 < currentStack.size())) {
ConstraintNode nextNode = (ConstraintNode) currentStack.get(++index);
if ((nextNode instanceof ConstraintOperation) &&
((((ConstraintOperation) nextNode).operation == ActionDesc.OP_NULL) ||
(((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL))) {
processNullConstraint((ForeignFieldDesc) f, nextNode);
} else {
constraint.stack.add(node);
constraint.stack.add(nextNode);
}
// Current node has been processed above.
addCurrentNode = false;
}
}
if (addCurrentNode) {
constraint.stack.add(node);
}
return index;
| private void | processForeignFields(java.util.ArrayList foreignFields, java.util.ArrayList localFields)Create and build the query plans for foreign fields that have been
added by {@link RetrieveDesc#addResult(String, RetrieveDesc, boolean)}.
If there is no projection, add the foreign key fields to the list
of fields to be selected.
if (foreignFields.size() == 0) {
return;
}
boolean debug = logger.isLoggable(Logger.FINEST);
if (debug) {
logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield", // NOI18N
config.getPersistenceCapableClass().getName());
}
foreignPlans = new ArrayList();
for (int i = 0; i < foreignFields.size(); i++) {
processForeignField((ConstraintFieldName) foreignFields.get(i), localFields);
}
if (debug) {
logger.finest("sqlstore.sql.generator.selectqueryplan.processforeignfield.exit"); // NOI18N
}
| private void | processJoin(com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.SelectQueryPlan fcp, int joinOp)Builds the foreign constraint plan fcp without
adding any new fields to {@link ResultDesc} and joins
the plans with the join operation joinOp .
fcp.processConstraints();
doJoin(fcp, joinOp);
| private void | processJoins()Compares the statements generated for the current plan
against the statements generated for foreign query plans
and joins any statements together which it can. This method
joins query plans on foreign fields that have been added by
{@link RetrieveDesc#addResult(String,RetrieveDesc,boolean)}.
if (foreignPlans == null) {
return;
}
for (Iterator iter = foreignPlans.iterator(); iter.hasNext(); ) {
SelectQueryPlan fp = (SelectQueryPlan) iter.next();
if ((fp.status & ST_JOINED) == 0) {
// Recursively join foreign plans of the foreign plan.
fp.processJoins();
// TODO: We only join to foreign query plans that involve one statement.
if (statements.size() == 1 && fp.statements.size() == 1) {
doJoin(fp, getJoinOperator(fp));
}
}
if ((fp.status & ST_JOINED) > 0) {
// Foreign plan has been joined
iter.remove();
}
}
// Sanity check.
if (foreignPlans != null && foreignPlans.size() > 0) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"sqlstore.sql.generator.selectqueryplan.plansnotjoined")); // NOI18N
} else {
foreignPlans = null;
}
| private void | processLocalConstraints()Asociates every local constraint on the stack with it's original plan
and include any table that hasn't been added to the table list of the
corresponding original plan.
List stack = constraint.getConstraints();
for (int i = 0; i < stack.size(); i++) {
ConstraintNode node = (ConstraintNode) stack.get(i);
if (node instanceof ConstraintFieldName) {
ConstraintFieldName fieldNode = (ConstraintFieldName) node;
if (fieldNode.originalPlan == null) {
// The field has not been processed before
SelectQueryPlan thePlan = null;
if (fieldNode.desc == null) {
thePlan = this;
} else {
// If the field belongs to a different RetrieveDesc, we need
// to use the query plan associated with that RetrieveDesc.
RetrieveDescImpl rd = (RetrieveDescImpl) fieldNode.desc;
thePlan = newForeignConstraintPlan(rd, fieldNode.name);
}
fieldNode.originalPlan = thePlan;
// The name field is null for unrelated constraints.
if (fieldNode.name != null) {
FieldDesc field = thePlan.config.getField(fieldNode.name);
if (field instanceof LocalFieldDesc) {
// Adds the statement and table for the field.
// This is only required to process plans corresponding
// to query filters containing unbound variables
// e.g. setFilter("empid == d.deptid") on an employee query.
thePlan.addTable((LocalFieldDesc) field);
}
}
}
}
}
| private int | processLocalFieldConstraint(ConstraintFieldName node, java.util.List currentStack, int index)Joins unrelated constraints that have been added by
{@link RetrieveDesc#addConstraint(String, RetrieveDesc)} where the
name of the foreign field is null. Other constraints have been added by
{@link RetrieveDesc#addConstraint(String, int, RetrieveDesc, String)}
if (node.desc != null) {
SelectQueryPlan fcp = ((RetrieveDescImpl) node.desc).getPlan();
constraint.stack.add(node);
if ((fcp.status & ST_JOINED) == 0) {
fcp.appendAndOp = true;
// Local fields connecting to foreign plans
// (non relationship constraints) are not processed here
// because we want to join on all foreign fields first.
} else {
// The foreign plan has already been joined. We need
// to add another And-constraint for
// FieldName-constraints using the same retrieve
// descriptor. This is only required for query filters
// comparing local fields from different tables,
// e.g. setFilter("empid == department.deptid") on an
// employee query.
// Push the remaining operand and the operator onto the stack.
constraint.stack.add(currentStack.get(++index));
constraint.stack.add(currentStack.get(++index));
if (fcp.appendAndOp) {
constraint.addOperation(ActionDesc.OP_AND);
fcp.appendAndOp = false;
}
}
} else {
index = processForeignFieldNullComparision(node, currentStack, index);
}
return index;
| private void | processLocalFields(java.util.ArrayList localFields, LocalFieldDesc projectionField)Add all requested local fields to {@link ResultDesc}.
boolean debug = logger.isLoggable(Logger.FINEST);
if (debug) {
logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield", // NOI18N
config.getPersistenceCapableClass().getName());
}
for (int i = 0; i < localFields.size(); i++) {
LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
addColumn(lf, true, (projectionField == lf));
}
if (debug) {
logger.finest("sqlstore.sql.generator.selectqueryplan.processlocalfield.exit"); // NOI18N
}
| private void | processNullConstraint(ForeignFieldDesc ff, ConstraintNode nextNode)Handles the comparison of a relationship field with (non-) null.
Comparisons for non-collection relationships not mapped to jointables can be
optimized to comparing the foreign key columns being (non-) null. All other
cases lead to a nested (NOT-) EXISTS query.
if (ff.hasForeignKey()) {
// Optimize the query to compare the foreign key fields with null.
ArrayList localFields = ff.getLocalFields();
for (int j = 0; j < localFields.size(); j++) {
constraint.stack.add(new ConstraintFieldDesc((LocalFieldDesc) localFields.get(j)));
constraint.stack.add(nextNode);
}
} else {
// Otherwise, generate a nested (NOT-) EXISTS sub query.
int subOp = ActionDesc.OP_NOTEXISTS;
if (((ConstraintOperation) nextNode).operation == ActionDesc.OP_NOTNULL) {
subOp = ActionDesc.OP_EXISTS;
}
// Add a subquery constraint for this field
addCorrelatedExistsQuery(ff, subOp);
}
| public void | processOrderConstraints()Converts ConstraintFieldName used in Order by constraints into
ConstraintFieldDesc using ConstraintFieldName#originalPlan.
Currently unused functionality:
Gets all the "order by" constraints from the the current stack.
The constraints are ordered such that any "order by" constraint
with position N is placed before any "order by" constraint with
position N+m, where m > 0. Also any "order by" constraint with
no position (i.e. position < 0) are placed immediately
following the previous "order by" constraint with a position.
The order of the "order by" constraints on the constraint stack
is changed to effect this ordering.
NOTE: The value constraints giving the position for
the order by constraints is currently not generated by the
query compiler.
if ((status & ST_BUILT) > 0 || (status & ST_OC_BUILT) > 0) {
return;
}
ArrayList orderByArray = new ArrayList();
int i, pos;
int insertAt = 0;
// Now pull out all "order by" constraints and convert
// ConstraintFieldName to ConstraintFieldDesc expected
// by SelectStatement.
if (constraint != null) {
i = 0;
while (i < constraint.stack.size()) {
ConstraintNode opNode = (ConstraintNode) constraint.stack.get(i);
if ((opNode instanceof ConstraintOperation)
&& ((((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY) ||
(((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC))) {
pos = -1;
if ((i > 1) && (constraint.stack.get(i - 2) instanceof ConstraintValue)) {
pos = ((Integer) ((ConstraintValue) constraint.stack.get(i - 2)).getValue() ).intValue();
constraint.stack.remove(i - 2);
i = i - 1;
}
if (pos > 0) {
insertAt = pos;
}
for (int k = orderByArray.size(); k <= insertAt; k++) {
orderByArray.add(null);
}
if (orderByArray.get(insertAt) == null) {
orderByArray.set(insertAt, new ArrayList());
}
ConstraintNode fieldNode = (ConstraintNode) constraint.stack.get(i - 1);
ConstraintFieldDesc consFieldDesc = null;
if (fieldNode instanceof ConstraintFieldName) {
QueryPlan originalPlan = this;
if (((ConstraintField) fieldNode).originalPlan != null) {
originalPlan = ((ConstraintField) fieldNode).originalPlan;
}
FieldDesc fieldDesc = originalPlan.config.
getField(((ConstraintFieldName) fieldNode).name);
if (!(fieldDesc instanceof LocalFieldDesc)) {
throw new JDOUserException(I18NHelper.getMessage(messages,
"core.generic.notinstanceof", // NOI18N
fieldDesc.getClass().getName(),
"LocalFieldDesc")); // NOI18N
}
consFieldDesc = new ConstraintFieldDesc((LocalFieldDesc) fieldDesc,
originalPlan, 1);
} else if (fieldNode instanceof ConstraintFieldDesc) {
consFieldDesc = (ConstraintFieldDesc) fieldNode;
} else {
throw new JDOUserException(I18NHelper.getMessage(messages,
"core.generic.notinstanceof", // NOI18N
fieldNode.getClass().getName(),
"ConstraintFieldName/ConstraintFieldDesc")); // NOI18N
}
if (((ConstraintOperation) opNode).operation == ActionDesc.OP_ORDERBY_DESC) {
consFieldDesc.ordering = -1;
}
// Remember constraint in orderByArray.
ArrayList temp = (ArrayList) (orderByArray.get(insertAt));
temp.add(consFieldDesc);
constraint.stack.remove(i);
constraint.stack.remove(i - 1);
i = i - 2 + 1;
}
i = i + 1;
}
}
for (int j = 0, size = orderByArray.size(); j < size; j++) {
ArrayList oa = (ArrayList) orderByArray.get(j);
if (constraint == null) {
constraint = new Constraint();
}
for (int k = 0, sizeK = oa.size(); k < sizeK; k++) {
ConstraintFieldDesc ob = (ConstraintFieldDesc) oa.get(k);
if (ob.ordering < 0) {
constraint.addField(ob);
constraint.addOperation(ActionDesc.OP_ORDERBY_DESC);
} else {
constraint.addField(ob);
constraint.addOperation(ActionDesc.OP_ORDERBY);
}
}
}
status |= ST_OC_BUILT;
| private void | processParentField(ClassDesc parentConfig, java.lang.String fieldName)Sets the plan's parent field and adds the tables for the join columns
to the table list. The parent field is identified by fieldName
and defined in the model information of the parent class
parentConfig .
if (parentField == null) {
// The plan has not been processed before
FieldDesc f = parentConfig.getField(fieldName);
if (f == null || !(f instanceof ForeignFieldDesc)) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.constraint.unknownfield", // NOI18N
fieldName, parentConfig.getPersistenceCapableClass().getName()));
}
parentField = (ForeignFieldDesc) f;
// Add the join table, if neccessary.
if (parentField.useJoinTable()) {
// It is important to add the join table here so that this table does not
// get lost behind the same join table in parentPlan's table list
// See collection38
//
for (int i = 0; i < parentField.assocLocalColumns.size(); i++) {
ColumnElement col = (ColumnElement) parentField.assocLocalColumns.get(i);
addQueryTable(col.getDeclaringTable(), config);
}
}
// Add the joined tables.
// This is required for cases where no fields from this plan are selected
// The side-effect for this is to create statements with no columns.
for (int i = 0; i < parentField.foreignColumns.size(); i++) {
ColumnElement col = (ColumnElement) parentField.foreignColumns.get(i);
addQueryTable(col.getDeclaringTable(), config);
}
}
| private void | processRelatedStatements(SelectStatement statement)
ArrayList secondaryTableStatements = statement.getSecondaryTableStatements();
if (secondaryTableStatements != null) {
for (int i = 0; i < secondaryTableStatements.size(); i++) {
SelectStatement secondaryTableStatement = (SelectStatement) secondaryTableStatements.get(i);
if (!secondaryTableStatement.isJoined()) {
processRelatedStatements(secondaryTableStatement);
joinSecondaryTableStatement(statement, secondaryTableStatement);
}
}
secondaryTableStatements.clear();
}
| protected void | processStatements()
boolean debug = logger.isLoggable(Logger.FINEST);
if (debug) {
Object[] items = new Object[] {config.getPersistenceCapableClass().getName(),
new Integer(statements.size())};
logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts",items); // NOI18N
}
if (concurrency != null) {
concurrency.select(this);
}
int size = statements.size();
if (size > 1) {
super.processStatements();
for (int i = 0; i < size; i++) {
SelectStatement s = (SelectStatement) statements.get(i);
if (!s.isJoined())
processRelatedStatements(s);
}
// Remove all the statements that have been joined.
for (int i = 0; i < statements.size(); i++) {
SelectStatement s = (SelectStatement) statements.get(i);
if (s.isJoined()) {
statements.remove(i);
i--;
continue;
}
}
}
if (debug) {
logger.finest("sqlstore.sql.generator.selectqueryplan.processstmts.exit"); // NOI18N
}
| private void | processUnboundConstraints()Builds the constraint plan for unbound contraints between
different retrieve descriptors. Unbound constraints
do not navigate a relationship, i.e. there isn't a {@link
ConstraintForeignFieldName} connecting the two retrieve
descriptors. This method handles filters like setFilter("empid ==
d.deptid") on an employee query, where d is
the unbound variable. These constraints have been added by
{@link RetrieveDesc#addConstraint(String, int, RetrieveDesc, String)}.
List currentStack = constraint.getConstraints();
constraint.stack = new ArrayList();
for (int i = 0; i < currentStack.size(); i++) {
ConstraintNode node = (ConstraintNode) currentStack.get(i);
if (node instanceof ConstraintFieldName) {
ConstraintFieldName fieldNode = (ConstraintFieldName) node;
if (fieldNode.name != null) {
constraint.stack.add(fieldNode);
} else if (fieldNode.desc != null) {
SelectQueryPlan fcp = ((RetrieveDescImpl) fieldNode.desc).getPlan();
// Do the join.
if ((fcp.status & ST_JOINED) == 0) {
// As this is a "real" non-relationship join,
// do not force the addition of an and constraint.
fcp.appendAndOp = false;
processJoin(fcp, ActionDesc.OP_NONREL_JOIN);
}
}
} else {
constraint.stack.add(node);
}
}
| private LocalFieldDesc | separateFieldList(java.util.ArrayList localFields, java.util.ArrayList foreignFields)Separates the retrieve descriptor's field list. Cull out the
foreign field constraints into foreignFields . Get
the field descriptors of local fields and put them into
localFields .
LocalFieldDesc projectionField = null;
while (fieldIterator.hasNext()) {
ConstraintFieldName cfn = (ConstraintFieldName) fieldIterator.next();
FieldDesc f = config.getField(cfn.name);
if (f == null) {
throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
"core.constraint.unknownfield", // NOI18N
cfn.name, config.getPersistenceCapableClass().getName()));
}
setFieldMask(f.absoluteID);
if (cfn.desc != null) {
foreignFields.add(cfn);
} else {
localFields.add(f);
if (cfn.isProjection()) {
projectionField = (LocalFieldDesc) f;
}
}
}
return projectionField;
| private void | setFieldMask(int index)
if (index < 0) {
index = config.fields.size() - index;
}
fieldMask.set(index);
| private void | setGroupMask(int groupID)
if (groupID >= FieldDesc.GROUP_DEFAULT)
hierarchicalGroupMask.set(groupID);
else if (groupID < FieldDesc.GROUP_NONE)
independentGroupMask.set(-(groupID + 1));
|
|