MethodBuilder mb,
Optimizable optTable,
boolean absolute)
throws StandardException
{
ExpressionClassBuilder acb = (ExpressionClassBuilder) acbi;
String retvalType = ClassName.Qualifier + "[][]";
MethodBuilder consMB = acb.getConstructor();
MethodBuilder executeMB = acb.getExecuteMethod();
/* Create and initialize the array of Qualifiers */
LocalField qualField =
acb.newFieldDeclaration(Modifier.PRIVATE, retvalType);
/*
** Stick a reinitialize of the Qualifier array in execute().
** Done because although we call Exec/Qualifier.clearOrderableCache()
** before each query, we only clear the cache for VARIANT and
** SCAN_INVARIANT qualifiers. However, each time the same
** statement is executed, even the QUERY_INVARIANT qualifiers
** need to be flushed. For example:
** prepare select c1 from t where c1 = (select max(c1) from t) as p;
** execute p; -- we now have the materialized subquery result (1)
** -- in our predicate
** insert into t values 666;
** execute p; -- we need to clear out 1 and recache the subq result
*/
// PUSHCOMPILER
// if (mb == executeMB) {
// System.out.println("adding code to method in two places");
// new Throwable().printStackTrace();
// }
//
// generate code to reinitializeQualifiers(Qualifier[][] qualifiers)
executeMB.getField(qualField); // first arg to reinitializeQualifiers()
executeMB.callMethod(
VMOpcode.INVOKESTATIC,
acb.getBaseClassName(), "reinitializeQualifiers", "void", 1);
/*
** Initialize the Qualifier array to a new Qualifier[][] if
** there are any qualifiers. It is automatically initialized to
** null if it isn't explicitly initialized.
*/
if (numberOfQualifiers != 0)
{
if (SanityManager.DEBUG)
{
if (numberOfQualifiers > size())
{
SanityManager.THROWASSERT(
"numberOfQualifiers(" + numberOfQualifiers +
") > size(" + size() + ")." + ":" + this.hashCode());
}
}
// Determine number of leading AND qualifiers, and subsequent
// trailing OR qualifiers.
int num_of_or_conjunctions = 0;
for (int i = 0; i < numberOfQualifiers; i++)
{
if (((Predicate) elementAt(i)).isOrList())
{
num_of_or_conjunctions++;
}
}
/* Assign the initializer to the Qualifier[] field */
consMB.pushNewArray(
ClassName.Qualifier + "[]", (int) num_of_or_conjunctions + 1);
consMB.setField(qualField);
// Allocate qualifiers[0] which is an entry for each of the leading
// AND clauses.
consMB.getField(qualField); // 1st arg allocateQualArray
consMB.push((int) 0); // 2nd arg allocateQualArray
consMB.push((int) numberOfQualifiers - num_of_or_conjunctions); // 3rd arg allocateQualArray
consMB.callMethod(
VMOpcode.INVOKESTATIC,
acb.getBaseClassName(),
"allocateQualArray", "void", 3);
}
/* Sort the qualifiers by "selectivity" before generating.
* We want the qualifiers ordered by selectivity with the
* most selective ones first. There are 3 groups of qualifiers:
* = and IS NULL are the most selective,
* <> and IS NOT NULL are the least selective and
* all of the other RELOPs are in between.
* We break the list into 4 parts (3 types of qualifiers and
* then everything else) and then rebuild the ordered list.
* RESOLVE - we will eventually want to order the qualifiers
* by (column #, selectivity) once the store does just in time
* instantiation.
*/
if (numberOfQualifiers > 0)
{
orderQualifiers();
}
/* Generate each of the qualifiers, if any */
// First generate the "leading" AND qualifiers.
int qualNum = 0;
int size = size();
boolean gotOrQualifier = false;
for (int index = 0; index < size; index++)
{
Predicate pred = ((Predicate) elementAt(index));
if (!pred.isQualifier())
{
continue;
}
else if (pred.isOrList())
{
gotOrQualifier = true;
// will generate the OR qualifiers below.
break;
}
else
{
generateSingleQualifierCode(
consMB,
optTable,
absolute,
acb,
pred.getRelop(),
qualField,
0,
qualNum);
qualNum++;
}
}
if (gotOrQualifier)
{
// process each set of or's into a list which are AND'd. Each
// predicate will become an array list in the qualifier array of
// array's.
//
// The first list of And's went into qual[0][0...N]
// Now each subquent predicate is actually a list of OR's so
// will be passed as:
// 1st OR predicate -> qual[1][0.. number of OR terms]
// 2nd OR predicate -> qual[2][0.. number of OR terms]
// ...
//
int and_idx = 1;
// The remaining qualifiers must all be OR predicates, which
// are pushed slightly differently than the leading AND qualifiers.
for (int index = qualNum; index < size; index++, and_idx++)
{
Predicate pred = ((Predicate) elementAt(index));
if (SanityManager.DEBUG)
{
SanityManager.ASSERT(pred.isOrList());
}
// create an ArrayList of the OR nodes. We need the count
// of Or's in order to first generate the allocateQualArray()
// call, then we walk the list assigning each of the OR's to
// entries in the array in generateSingleQualifierCode().
ArrayList a_list = new ArrayList();
QueryTreeNode node = pred.getAndNode().getLeftOperand();
while (node instanceof OrNode)
{
OrNode or_node = (OrNode) node;
// The left operand of OR node is one of the terms,
// (ie. A = 1)
if (or_node.getLeftOperand() instanceof RelationalOperator)
{
a_list.add(or_node.getLeftOperand());
}
// The next OR node in the list if linked to the right.
node = or_node.getRightOperand();
}
// Allocate an array to hold each of the terms of this OR,
// clause. ie. (a = 1 or b = 2), will allocate a 2 entry array.
consMB.getField(qualField); // 1st arg allocateQualArray
consMB.push((int) and_idx); // 2nd arg allocateQualArray
consMB.push((int) a_list.size()); // 3rd arg allocateQualArray
consMB.callMethod(
VMOpcode.INVOKESTATIC,
acb.getBaseClassName(),
"allocateQualArray", "void", 3);
// finally transfer the nodes to the 2-d qualifier
for (int i = 0; i < a_list.size(); i++)