{
SanityManager.ASSERT(expressionBuilder instanceof ActivationClassBuilder,
"Expecting an ActivationClassBuilder");
}
ActivationClassBuilder acb = (ActivationClassBuilder) expressionBuilder;
/* Reuse generated code, where possible */
/* Generate the appropriate (Any or Once) ResultSet */
if (subqueryType == EXPRESSION_SUBQUERY)
{
resultSetString = "getOnceResultSet";
}
else
{
resultSetString = "getAnyResultSet";
}
// Get cost estimate for underlying subquery
CostEstimate costEstimate = resultSet.getFinalCostEstimate();
/* Generate a new method. It's only used within the other
* exprFuns, so it could be private. but since we don't
* generate the right bytecodes to invoke private methods,
* we just make it protected. This generated class won't
* have any subclasses, certainly! (nat 12/97)
*/
String subqueryTypeString =
getTypeCompiler().interfaceName();
MethodBuilder mb = acb.newGeneratedFun(subqueryTypeString, Modifier.PROTECTED);
/* Declare the field to hold the suquery's ResultSet tree */
LocalField rsFieldLF = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
ResultSetNode subNode = null;
if (!isMaterializable())
{
MethodBuilder executeMB = acb.getExecuteMethod();
if (pushedNewPredicate && (! hasCorrelatedCRs()))
{
/* We try to materialize the subquery if it can fit in the memory. We
* evaluate the subquery first. If the result set fits in the memory,
* we replace the resultset with in-memory unions of row result sets.
* We do this trick by replacing the child result with a new node --
* MaterializeSubqueryNode, which essentially generates the suitable
* code to materialize the subquery if possible. This may have big
* performance improvement. See beetle 4373.
*/
if (SanityManager.DEBUG)
{
SanityManager.ASSERT(resultSet instanceof ProjectRestrictNode,
"resultSet expected to be a ProjectRestrictNode!");
}
subNode = ((ProjectRestrictNode) resultSet).getChildResult();
LocalField subRS = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
mb.getField(subRS);
mb.conditionalIfNull();
ResultSetNode materialSubNode = new MaterializeSubqueryNode(subRS);
((ProjectRestrictNode) resultSet).setChildResult(materialSubNode);
/* Evaluate subquery resultset here first. Next time when we come to
* this subquery it may be replaced by a bunch of unions of rows.
*/
subNode.generate(acb, mb);
mb.startElseCode();
mb.getField(subRS);
mb.completeConditional();
mb.putField(subRS);
mb.endStatement();
executeMB.pushNull( ClassName.NoPutResultSet);
executeMB.putField(subRS);
executeMB.endStatement();
}
executeMB.pushNull( ClassName.NoPutResultSet);
executeMB.putField(rsFieldLF);
executeMB.endStatement();
// now we fill in the body of the conditional
mb.getField(rsFieldLF);
mb.conditionalIfNull();
}
acb.pushGetResultSetFactoryExpression(mb);
// start of args
int nargs;
/* Inside here is where subquery could already have been materialized. 4373
*/
resultSet.generate(acb, mb);
/* Get the next ResultSet #, so that we can number the subquery's
* empty row ResultColumnList and Once/Any ResultSet.
*/
int subqResultSetNumber = cc.getNextResultSetNumber();
/* We will be reusing the RCL from the subquery's ResultSet for the
* empty row function. We need to reset the resultSetNumber in the
* RCL, before we generate that function. Now that we've called
* generate() on the subquery's ResultSet, we can reset that
* resultSetNumber.
*/
resultSet.getResultColumns().setResultSetNumber(subqResultSetNumber);
acb.pushThisAsActivation(mb);
/* Generate code for empty row */
resultSet.getResultColumns().generateNulls(acb, mb);
/*