docs: public void resolveExpressionTypes(Session session) {
  
          for (int i = 0; i < indexStartAggregates; i++) {
              Expression e = exprColumns[i];
  
              e.resolveTypes(session, null);
  
              if (e.getType() == OpTypes.ROW) {
                  throw Error.error(ErrorCode.X_42564);
              }
          }
  
          for (int i = 0, len = rangeVariables.length; i < len; i++) {
              Expression e = rangeVariables[i].nonIndexJoinCondition;
  
              if (e != null) {
                  e.resolveTypes(session, null);
  
                  if (e.getDataType() != Type.SQL_BOOLEAN) {
                      throw Error.error(ErrorCode.X_42568);
                  }
              }
          }
  
          if (queryCondition != null) {
              queryCondition.resolveTypes(session, null);
  
              if (queryCondition.getDataType() != Type.SQL_BOOLEAN) {
                  throw Error.error(ErrorCode.X_42568);
              }
              if (queryCondition.opType == OpTypes.VALUE) {
                  if (!((boolean)queryCondition.valueData)) { // WHERE false => LIMIT 0
                      SortAndSlice sortAndSlice = new SortAndSlice();
                      ExpressionValue limit0 = new ExpressionValue(ValuePool.INTEGER_0, Type.SQL_INTEGER);
                      ExpressionValue offset = new ExpressionValue(ValuePool.INTEGER_0, Type.SQL_INTEGER);
                      sortAndSlice.addLimitCondition(new ExpressionOp(OpTypes.LIMIT, offset, limit0));
                      addSortAndSlice(sortAndSlice);
                  }
                  // Leave out the original WHERE condition no matter it is WHERE true or WHERE false.
                  queryCondition = null;
              }
              else {
                  // A VoltDB extension to guard against abuse of aggregates in subqueries.
                  // Make sure no aggregates in WHERE clause
                  tempSet.clear();
                  Expression.collectAllExpressions(
                          tempSet, queryCondition, Expression.aggregateFunctionSet,
                          Expression.subqueryExpressionSet);
                  if (!tempSet.isEmpty()) {
  
                      // A top level WHERE clause can't have aggregate expressions.
                      // In theory, a subquery WHERE clause may have aggregate
                      // expressions in some edge cases where they reference only
                      // columns from parent query(s).
                      // Even these should be restricted to cases where the subquery
                      // is evaluated after the parent agg, such as from the HAVING
                      // or SELECT clause of the parent query defining the columns.
                      // TO be safe, VoltDB doesn't support ANY cases of aggs of
                      // parent columns. All this code block does is choose between
                      // two error messages for two different unsupported cases.
                      if ( ! isTopLevel) {
                          HsqlList columnSet = new OrderedHashSet();
                          Iterator aggIt = tempSet.iterator();
                          while (aggIt.hasNext()) {
                              Expression nextAggr = (Expression) aggIt.next();
                              Expression.collectAllExpressions(columnSet, nextAggr,
                                      Expression.columnExpressionSet, Expression.emptyExpressionSet);
                          }
                          Iterator columnIt = columnSet.iterator();
                          while (columnIt.hasNext()) {
                              Expression nextColumn = (Expression) columnIt.next();
                              assert(nextColumn instanceof ExpressionColumn);
                              ExpressionColumn nextColumnEx = (ExpressionColumn) nextColumn;
                              String tableName = nextColumnEx.rangeVariable.rangeTable.tableName.name;
                              String tableAlias = (nextColumnEx.rangeVariable.tableAlias != null) ?
                                      nextColumnEx.rangeVariable.tableAlias.name : null;
                              boolean resolved = false;
                              for (RangeVariable rv : rangeVariables) {
                                  if (rv.rangeTable.tableName.name.equals(tableName)) {
                                      if (rv.tableAlias == null && tableAlias == null) {
                                          resolved = true;
                                      } else if (rv.tableAlias != null && tableAlias != null) {
                                          resolved = tableAlias.equals(rv.tableAlias.name);
                                      }
                                  }
                              }
                              if (!resolved) {
                                  throw Error.error(ErrorCode.X_47001);
                              }
                          }
                      }
                      // If we get here it means that WHERE expression has an aggregate expression
                      // with local columns
                      throw Error.error(ErrorCode.X_47000);
                  }
                  // End of VoltDB extension
              }
          }
  
          if (havingCondition != null) {
              havingCondition.resolveTypes(session, null);
  
              if (havingCondition.getDataType() != Type.SQL_BOOLEAN) {
                  throw Error.error(ErrorCode.X_42568);
              }
          }
      }