Example #1
0
  public FunDef getDef(Exp[] args, String funName, Syntax syntax) {
    // Compute signature first. It makes debugging easier.
    final String signature = syntax.getSignature(funName, Category.Unknown, ExpBase.getTypes(args));

    // Resolve function by its upper-case name first.  If there is only one
    // function with that name, stop immediately.  If there is more than
    // function, use some custom method, which generally involves looking
    // at the type of one of its arguments.
    List<Resolver> resolvers = funTable.getResolvers(funName, syntax);
    assert resolvers != null;

    final List<Resolver.Conversion> conversionList = new ArrayList<Resolver.Conversion>();
    int minConversionCost = Integer.MAX_VALUE;
    List<FunDef> matchDefs = new ArrayList<FunDef>();
    List<Resolver.Conversion> matchConversionList = null;
    for (Resolver resolver : resolvers) {
      conversionList.clear();
      FunDef def = resolver.resolve(args, this, conversionList);
      if (def != null) {
        int conversionCost = sumConversionCost(conversionList);
        if (conversionCost < minConversionCost) {
          minConversionCost = conversionCost;
          matchDefs.clear();
          matchDefs.add(def);
          matchConversionList = new ArrayList<Resolver.Conversion>(conversionList);
        } else if (conversionCost == minConversionCost) {
          matchDefs.add(def);
        } else {
          // ignore this match -- it required more coercions than
          // other overloadings we've seen
        }
      }
    }
    switch (matchDefs.size()) {
      case 0:
        throw MondrianResource.instance().NoFunctionMatchesSignature.ex(signature);
      case 1:
        break;
      default:
        final StringBuilder buf = new StringBuilder();
        for (FunDef matchDef : matchDefs) {
          if (buf.length() > 0) {
            buf.append(", ");
          }
          buf.append(matchDef.getSignature());
        }
        throw MondrianResource.instance()
            .MoreThanOneFunctionMatchesSignature
            .ex(signature, buf.toString());
    }

    final FunDef matchDef = matchDefs.get(0);
    for (Resolver.Conversion conversion : matchConversionList) {
      conversion.checkValid();
      conversion.apply(this, Arrays.asList(args));
    }

    return matchDef;
  }
Example #2
0
 private boolean requiresExpression(int n) {
   if (n < 1) {
     return false;
   }
   final Object parent = stack.get(n - 1);
   if (parent instanceof Formula) {
     return ((Formula) parent).isMember();
   } else if (parent instanceof ResolvedFunCall) {
     final ResolvedFunCall funCall = (ResolvedFunCall) parent;
     if (funCall.getFunDef().getSyntax() == Syntax.Parentheses) {
       return requiresExpression(n - 1);
     } else {
       int k = whichArg(funCall, (Exp) stack.get(n));
       if (k < 0) {
         // Arguments of call have mutated since call was placed
         // on stack. Presumably the call has already been
         // resolved correctly, so the answer we give here is
         // irrelevant.
         return false;
       }
       final FunDef funDef = funCall.getFunDef();
       final int[] parameterTypes = funDef.getParameterCategories();
       return parameterTypes[k] != Category.Set;
     }
   } else if (parent instanceof UnresolvedFunCall) {
     final UnresolvedFunCall funCall = (UnresolvedFunCall) parent;
     if (funCall.getSyntax() == Syntax.Parentheses || funCall.getFunName().equals("*")) {
       return requiresExpression(n - 1);
     } else {
       int k = whichArg(funCall, (Exp) stack.get(n));
       if (k < 0) {
         // Arguments of call have mutated since call was placed
         // on stack. Presumably the call has already been
         // resolved correctly, so the answer we give here is
         // irrelevant.
         return false;
       }
       return requiresExpression(funCall, k);
     }
   } else {
     return false;
   }
 }
  NativeEvaluator createEvaluator(RolapEvaluator evaluator, FunDef fun, Exp[] args) {
    if (!isEnabled()) {
      return null;
    }
    if (!FilterConstraint.isValidContext(evaluator, restrictMemberTypes())) {
      return null;
    }
    // is this "Filter(<set>, <numeric expr>)"
    String funName = fun.getName();
    if (!"Filter".equalsIgnoreCase(funName)) {
      return null;
    }

    if (args.length != 2) {
      return null;
    }

    // extract the set expression
    List<CrossJoinArg[]> allArgs = crossJoinArgFactory().checkCrossJoinArg(evaluator, args[0]);

    // checkCrossJoinArg returns a list of CrossJoinArg arrays.  The first
    // array is the CrossJoin dimensions.  The second array, if any,
    // contains additional constraints on the dimensions. If either the
    // list or the first array is null, then native cross join is not
    // feasible.
    if (allArgs == null || allArgs.isEmpty() || allArgs.get(0) == null) {
      return null;
    }

    CrossJoinArg[] cjArgs = allArgs.get(0);
    if (isPreferInterpreter(cjArgs, false)) {
      return null;
    }

    // extract "order by" expression
    SchemaReader schemaReader = evaluator.getSchemaReader();
    DataSource ds = schemaReader.getDataSource();

    // generate the WHERE condition
    // Need to generate where condition here to determine whether
    // or not the filter condition can be created. The filter
    // condition could change to use an aggregate table later in evaluation
    SqlQuery sqlQuery = SqlQuery.newQuery(ds, "NativeFilter");
    RolapNativeSql sql = new RolapNativeSql(sqlQuery, null, evaluator, cjArgs[0].getLevel());
    final Exp filterExpr = args[1];
    String filterExprStr = sql.generateFilterCondition(filterExpr);
    if (filterExprStr == null) {
      return null;
    }

    // Check to see if evaluator contains a calculated member that can't be
    // expanded.  This is necessary due to the SqlConstraintsUtils.
    // addContextConstraint()
    // method which gets called when generating the native SQL.
    if (SqlConstraintUtils.containsCalculatedMember(evaluator.getNonAllMembers(), true)) {
      return null;
    }

    LOGGER.debug("using native filter");

    final int savepoint = evaluator.savepoint();
    try {
      overrideContext(evaluator, cjArgs, sql.getStoredMeasure());
      // Now construct the TupleConstraint that contains both the CJ
      // dimensions and the additional filter on them.
      CrossJoinArg[] combinedArgs = cjArgs;
      if (allArgs.size() == 2) {
        CrossJoinArg[] predicateArgs = allArgs.get(1);
        if (predicateArgs != null) {
          // Combined the CJ and the additional predicate args.
          combinedArgs = Util.appendArrays(cjArgs, predicateArgs);
        }
      }

      TupleConstraint constraint = new FilterConstraint(combinedArgs, evaluator, filterExpr);
      return new SetEvaluator(cjArgs, schemaReader, constraint);
    } finally {
      evaluator.restore(savepoint);
    }
  }