use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class SubqueryNode method generateMaterialization.
/*
** Materialize the subquery in question. Given the expression
** that represents the subquery, this returns fieldX where
** fieldX is set up as follows:
**
** private ... fieldX
**
** execute()
** {
** fieldX = <subqueryExpression>
** ...
** }
**
** So we wind up evaluating the subquery when we start
** execution. Obviously, it is absolutely necessary that
** the subquery is invariant and has no correlations
** for this to work.
**
** Ideally we wouldn't evaluate the expression subquery
** until we know we need to, but because we are marking
** this expression subquery as pushable, we must evaluate
** it up front because it might wind up as a qualification,
** and we cannot execute a subquery in the store as a
** qualification because the store executes qualifications
** while holding a latch.
**
** @param acb
** @param type
** @param subqueryExpression
*/
private LocalField generateMaterialization(ActivationClassBuilder acb, MethodBuilder mbsq, String type) {
MethodBuilder mb = acb.getExecuteMethod();
// declare field
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, type);
/* Generate the call to the new method */
mb.pushThis();
mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mbsq.getName(), type, 0);
// generate: field = value (value is on stack)
mb.setField(field);
return field;
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class UnaryOperatorNode method generateExpression.
/**
* Do code generation for this unary operator.
*
* @param acb The ExpressionClassBuilder for the class we're generating
* @param mb The method the expression will go into
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
String resultTypeName = (kind == K_BASE) ? getTypeCompiler().interfaceName() : resultInterfaceType;
// System.out.println("resultTypeName " + resultTypeName + " method " + methodName);
// System.out.println("isBooleanTypeId() " + getTypeId().isBooleanTypeId());
boolean needField = !getTypeId().isBooleanTypeId();
String receiverType = getReceiverInterfaceName();
operand.generateExpression(acb, mb);
mb.cast(receiverType);
if (needField) {
/* Allocate an object for re-use to hold the result of the operator */
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
mb.getField(field);
int numArgs = 1;
// XML operators take extra arguments.
numArgs += addXmlOpMethodParams(acb, mb, field);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null, methodName, resultTypeName, numArgs);
/*
** Store the result of the method call in the field, so we can re-use
** the object.
*/
mb.putField(field);
} else {
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, resultTypeName, 0);
}
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class TernaryOperatorNode method generateExpression.
/**
* Do code generation for this ternary operator.
*
* @param acb The ExpressionClassBuilder for the class we're generating
* @param mb The method the expression will go into
*
* @exception StandardException Thrown on error
*/
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
int nargs = 0;
String receiverType = null;
/* Allocate an object for re-use to hold the result of the operator */
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultInterfaceType);
receiver.generateExpression(acb, mb);
if (kind == K_TRIM) {
mb.push(trimType);
leftOperand.generateExpression(acb, mb);
mb.cast(leftInterfaceType);
mb.getField(field);
nargs = 3;
receiverType = receiverInterfaceType;
} else if (kind == K_LOCATE) {
leftOperand.generateExpression(acb, mb);
mb.upCast(leftInterfaceType);
rightOperand.generateExpression(acb, mb);
mb.upCast(rightInterfaceType);
mb.getField(field);
nargs = 3;
} else if (kind == K_SUBSTRING) {
leftOperand.generateExpression(acb, mb);
mb.upCast(leftInterfaceType);
if (rightOperand != null) {
rightOperand.generateExpression(acb, mb);
mb.upCast(rightInterfaceType);
} else {
mb.pushNull(rightInterfaceType);
}
// third arg
mb.getField(field);
mb.push(receiver.getTypeServices().getMaximumWidth());
nargs = 4;
receiverType = receiverInterfaceType;
} else if (kind == K_TIMESTAMPADD || kind == K_TIMESTAMPDIFF) {
Object intervalType = leftOperand.getConstantValueAsObject();
if (SanityManager.DEBUG)
SanityManager.ASSERT(intervalType != null && intervalType instanceof Integer, "Invalid interval type used for " + operator);
mb.push(((Integer) intervalType).intValue());
rightOperand.generateExpression(acb, mb);
mb.upCast(TernaryArgType[kind][2]);
acb.getCurrentDateExpression(mb);
mb.getField(field);
nargs = 4;
receiverType = receiverInterfaceType;
}
mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultInterfaceType, nargs);
/*
** Store the result of the method call in the field, so we can re-use
** the object.
*/
mb.putField(field);
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class PredicateList method generateIndexableRow.
/**
* Generate the indexable row for a start key or stop key.
*
* @param acb The ActivationClassBuilder for the class we're building
* @param numberOfColumns The number of columns in the key
*
* @return The field that holds the indexable row
*/
private LocalField generateIndexableRow(ExpressionClassBuilder acb, int numberOfColumns) {
MethodBuilder mb = acb.getConstructor();
/*
** Generate a call to get an indexable row
** with the given number of columns
*/
// instance
acb.pushGetExecutionFactoryExpression(mb);
mb.push(numberOfColumns);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.ExecutionFactory, "getIndexableRow", ClassName.ExecIndexRow, 1);
/*
** Assign the indexable row to a field, and put this assignment into
** the constructor for the activation class. This way, we only have
** to get the row once.
*/
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecIndexRow);
mb.setField(field);
return field;
}
use of org.apache.derby.iapi.services.compiler.LocalField in project derby by apache.
the class PredicateList method generateQualifiers.
/**
* @see OptimizablePredicateList#generateQualifiers
*
* @exception StandardException Thrown on error
*/
public void generateQualifiers(ExpressionClassBuilderInterface acbi, MethodBuilder mb, Optimizable optTable, boolean absolute) throws StandardException {
String retvalType = ClassName.Qualifier + "[][]";
// If there are no qualifiers, return null.
if (numberOfQualifiers == 0) {
mb.pushNull(retvalType);
return;
}
ExpressionClassBuilder acb = (ExpressionClassBuilder) acbi;
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)
// first arg to reinitializeQualifiers()
executeMB.getField(qualField);
executeMB.callMethod(VMOpcode.INVOKESTATIC, acb.getBaseClassName(), "reinitializeQualifiers", "void", 1);
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 (elementAt(i).isOrList()) {
num_of_or_conjunctions++;
}
}
/* Assign the initializer to the Qualifier[] field */
consMB.pushNewArray(ClassName.Qualifier + "[]", num_of_or_conjunctions + 1);
consMB.setField(qualField);
// Allocate qualifiers[0] which is an entry for each of the leading
// AND clauses.
// 1st arg allocateQualArray
consMB.getField(qualField);
// 2nd arg allocateQualArray
consMB.push(0);
// 3rd arg allocateQualArray
consMB.push(numberOfQualifiers - num_of_or_conjunctions);
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.
*/
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 = 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;
for (int index = qualNum; index < size; index++, and_idx++) {
Predicate pred = 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<RelationalOperator> a_list = new ArrayList<RelationalOperator>();
QueryTreeNode node = pred.getAndNode().getLeftOperand();
while (node instanceof OrNode) {
OrNode or_node = (OrNode) node;
// (ie. A = 1)
if (or_node.getLeftOperand() instanceof RelationalOperator) {
a_list.add((RelationalOperator) 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.
// 1st arg allocateQualArray
consMB.getField(qualField);
// 2nd arg allocateQualArray
consMB.push(and_idx);
// 3rd arg allocateQualArray
consMB.push(a_list.size());
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++) {
generateSingleQualifierCode(consMB, optTable, absolute, acb, a_list.get(i), qualField, and_idx, i);
}
qualNum++;
}
}
if (SanityManager.DEBUG) {
SanityManager.ASSERT(qualNum == numberOfQualifiers, qualNum + " Qualifiers found, " + numberOfQualifiers + " expected.");
}
/*
** Return a reference to the field that holds the initialized
** array of Qualifiers.
*/
mb.getField(qualField);
}
Aggregations