8080import java .net .URLClassLoader ;
8181import java .nio .file .Files ;
8282import java .nio .file .Path ;
83- import java .util .ArrayDeque ;
8483import java .util .ArrayList ;
8584import java .util .Collection ;
8685import java .util .Collections ;
87- import java .util .Deque ;
8886import java .util .HashMap ;
8987import java .util .HashSet ;
9088import java .util .LinkedHashSet ;
@@ -265,7 +263,7 @@ public List<String> generateModelCode(final IRContext context,
265263 final OutputIR .Block outerBlock = outputIR .newBlock ("outer" );
266264 translationContext .enterScope (outerBlock );
267265 final OutputIR .Block block = addView (name , rewrittenComprehension , false , translationContext );
268- translationContext .leaveScope ();
266+ output . addCode ( translationContext .leaveScope (). toString () );
269267 output .addCode (block .toString ());
270268 });
271269 constraintViews
@@ -277,7 +275,7 @@ public List<String> generateModelCode(final IRContext context,
277275 final OutputIR .Block outerBlock = outputIR .newBlock ("outer" );
278276 translationContext .enterScope (outerBlock );
279277 final OutputIR .Block block = addView (name , rewrittenComprehension , true , translationContext );
280- translationContext .leaveScope ();
278+ output . addCode ( translationContext .leaveScope (). toString () );
281279 output .addCode (block .toString ());
282280 } else {
283281 final OutputIR .Block outerBlock = outputIR .newBlock ("outer" );
@@ -297,7 +295,6 @@ public List<String> generateModelCode(final IRContext context,
297295 final OutputIR .Block outerBlock = outputIR .newBlock ("outer" );
298296 objFunctionContext .enterScope (outerBlock );
299297 final String exprStr = exprToStr (rewrittenComprehension , objFunctionContext );
300- objFunctionContext .leaveScope ();
301298 output .addCode (outerBlock .toString ());
302299 output .addStatement ("final $T $L = $L" , IntVar .class , name , exprStr );
303300 });
@@ -568,7 +565,7 @@ private List<ColumnIdentifier> getColumnsAccessed(final List<? extends Expr> exp
568565 }
569566
570567 private LinkedHashSet <ColumnIdentifier > getColumnsAccessed (final Expr expr ) {
571- final GetColumnIdentifiers visitor = new GetColumnIdentifiers ();
568+ final GetColumnIdentifiers visitor = new GetColumnIdentifiers (false );
572569 visitor .visit (expr );
573570 return visitor .getColumnIdentifiers ();
574571 }
@@ -1590,12 +1587,12 @@ protected String visitMonoidComprehension(final MonoidComprehension node, final
15901587 visitor .visit (headSelectItem );
15911588 final boolean headSelectItemContainsMonoidFunction = visitor .getFound ();
15921589
1593- final OutputIR .Block currentBlock = context .currentScope ();
1590+ attemptConstantSubqueryOptimization (node , subQueryBlock , context );
1591+
15941592 final TranslationContext newCtx = context .withEnterFunctionContext ();
15951593 // If the head contains a function, then this is a scalar subquery
15961594 if (headSelectItemContainsMonoidFunction ) {
15971595 newCtx .enterScope (subQueryBlock );
1598- currentBlock .addBody (subQueryBlock );
15991596 final String ret = apply (innerVisitor .visit (headSelectItem , newCtx ), context );
16001597 newCtx .leaveScope ();
16011598 return ret ;
@@ -1606,7 +1603,6 @@ protected String visitMonoidComprehension(final MonoidComprehension node, final
16061603 final String type = inferType (node .getHead ().getSelectExprs ().get (0 ));
16071604 final String listName =
16081605 extractListFromLoop (processedHeadItem , subQueryBlock , newSubqueryName , type );
1609- currentBlock .addBody (subQueryBlock );
16101606 newCtx .leaveScope ();
16111607 return apply (listName , subQueryBlock , context );
16121608 }
@@ -1624,12 +1620,13 @@ protected String visitGroupByComprehension(final GroupByComprehension node, fina
16241620 Preconditions .checkArgument (node .getComprehension ().getHead ().getSelectExprs ().size () == 1 );
16251621 final Expr headSelectItem = node .getComprehension ().getHead ().getSelectExprs ().get (0 );
16261622
1627- final OutputIR .Block currentBlock = context .currentScope ();
16281623 final TranslationContext newCtx = context .withEnterFunctionContext ();
1624+
1625+ attemptConstantSubqueryOptimization (node , subQueryBlock , context );
1626+
16291627 // if scalar subquery
16301628 if (headSelectItem instanceof MonoidFunction ) {
16311629 newCtx .enterScope (subQueryBlock );
1632- currentBlock .addBody (subQueryBlock );
16331630 final String ret = apply (innerVisitor .visit (headSelectItem , newCtx ), context );
16341631 newCtx .leaveScope ();
16351632 return ret ;
@@ -1640,7 +1637,6 @@ protected String visitGroupByComprehension(final GroupByComprehension node, fina
16401637 final String type = inferType (node .getComprehension ().getHead ().getSelectExprs ().get (0 ));
16411638 final String listName =
16421639 extractListFromLoop (processedHeadItem , subQueryBlock , newSubqueryName , type );
1643- currentBlock .addBody (subQueryBlock );
16441640 newCtx .leaveScope ();
16451641 // Treat as a vector
16461642 return apply (listName , subQueryBlock , context );
@@ -1740,6 +1736,20 @@ private String createTermsForScalarProduct(final Expr variables, final Expr coef
17401736 extractListFromLoop (coefficientsItem , outerBlock , forLoop , coefficientsType );
17411737 return CodeBlock .of ("o.scalProd($L, $L)" , listOfVariablesItem , listOfCoefficientsItem ).toString ();
17421738 }
1739+
1740+ /**
1741+ * Constant sub-queries can be floated to the root block so that we evaluate them only once
1742+ */
1743+ private void attemptConstantSubqueryOptimization (final MonoidComprehension node ,
1744+ final OutputIR .Block subQueryBlock ,
1745+ final TranslationContext context ) {
1746+ if (IsConstantSubquery .apply (node )) {
1747+ final OutputIR .Block rootBlock = context .getRootBlock ();
1748+ rootBlock .addBody (subQueryBlock );
1749+ } else {
1750+ context .currentScope ().addBody (subQueryBlock );
1751+ }
1752+ }
17431753 }
17441754
17451755 /**
@@ -1778,7 +1788,7 @@ private String extractListFromLoop(final String variableToExtract, final OutputI
17781788 * @return the name of the list being extracted
17791789 */
17801790 @ SuppressFBWarnings ("UPM_UNCALLED_PRIVATE_METHOD" ) // false positive
1781- private String extractListFromLoop (final String variableToExtract , final OutputIR .Block outerBlock ,
1791+ private String extractListFromLoop (final String variableToExtract , final OutputIR .Block outerBlock ,
17821792 final String loopBlockName , final String variableType ) {
17831793 final OutputIR .Block forLoop = outerBlock .getForLoopByName (loopBlockName );
17841794 return extractListFromLoop (variableToExtract , outerBlock , forLoop , variableType );
@@ -1865,62 +1875,6 @@ private String getTempViewName() {
18651875 return "tmp" + intermediateViewCounter .getAndIncrement ();
18661876 }
18671877
1868- /**
1869- * Represents context required for code generation. It maintains a stack of blocks
1870- * in the IR, that is used to correctly scope variable declarations and accesses.
1871- */
1872- private static class TranslationContext {
1873- private final Deque <OutputIR .Block > scopeStack ;
1874- private final boolean isFunctionContext ;
1875-
1876- private TranslationContext (final Deque <OutputIR .Block > declarations , final boolean isFunctionContext ) {
1877- this .scopeStack = declarations ;
1878- this .isFunctionContext = isFunctionContext ;
1879- }
1880-
1881- private TranslationContext (final boolean isFunctionContext ) {
1882- this (new ArrayDeque <>(), isFunctionContext );
1883- }
1884-
1885- TranslationContext withEnterFunctionContext () {
1886- final Deque <OutputIR .Block > stackCopy = new ArrayDeque <>(scopeStack );
1887- return new TranslationContext (stackCopy , true );
1888- }
1889-
1890- boolean isFunctionContext () {
1891- return isFunctionContext ;
1892- }
1893-
1894- void enterScope (final OutputIR .Block block ) {
1895- scopeStack .addLast (block );
1896- }
1897-
1898- OutputIR .Block currentScope () {
1899- return Objects .requireNonNull (scopeStack .getLast ());
1900- }
1901-
1902- OutputIR .Block leaveScope () {
1903- return scopeStack .removeLast ();
1904- }
1905-
1906- String declareVariable (final String expression ) {
1907- for (final OutputIR .Block block : scopeStack ) {
1908- if (block .hasDeclaration (expression )) {
1909- return block .getDeclaredName (expression );
1910- }
1911- }
1912- return scopeStack .getLast ().declare (expression );
1913- }
1914-
1915- String declareVariable (final String expression , final OutputIR .Block block ) {
1916- return block .declare (expression );
1917- }
1918-
1919- String getTupleVarName () {
1920- return currentScope ().getTupleName ();
1921- }
1922- }
1923-
19241878 private static CodeBlock statement (final String format , final Object ... args ) {
19251879 return CodeBlock .builder ().addStatement (format , args ).build ();
19261880 }
0 commit comments