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
  public Exp validate(Exp exp, boolean scalar) {
    Exp resolved;
    try {
      resolved = (Exp) resolvedNodes.get(exp);
    } catch (ClassCastException e) {
      // A classcast exception will occur if there is a String
      // placeholder in the map. This is an internal error -- should
      // not occur for any query, valid or invalid.
      throw Util.newInternal(
          e, "Infinite recursion encountered while validating '" + Util.unparse(exp) + "'");
    }
    if (resolved == null) {
      try {
        stack.push((QueryPart) exp);
        // To prevent recursion, put in a placeholder while we're
        // resolving.
        resolvedNodes.put((QueryPart) exp, placeHolder);
        resolved = exp.accept(this);
        Util.assertTrue(resolved != null);
        resolvedNodes.put((QueryPart) exp, (QueryPart) resolved);
      } finally {
        stack.pop();
      }
    }

    if (scalar) {
      final Type type = resolved.getType();
      if (!TypeUtil.canEvaluate(type)) {
        String exprString = Util.unparse(resolved);
        throw MondrianResource.instance().MdxMemberExpIsSet.ex(exprString);
      }
    }

    return resolved;
  }
Example #3
0
  public Parameter createOrLookupParam(
      boolean definition, String name, Type type, Exp defaultExp, String description) {
    final SchemaReader schemaReader = getQuery().getSchemaReader(false);
    Parameter param = schemaReader.getParameter(name);

    if (definition) {
      if (param != null) {
        if (param.getScope() == Parameter.Scope.Statement) {
          ParameterImpl paramImpl = (ParameterImpl) param;
          paramImpl.setDescription(description);
          paramImpl.setDefaultExp(defaultExp);
          paramImpl.setType(type);
        }
        return param;
      }
      param = new ParameterImpl(name, defaultExp, description, type);

      // Append it to the list of known parameters.
      defineParameter(param);
      return param;
    } else {
      if (param != null) {
        return param;
      }
      throw MondrianResource.instance().UnknownParameter.ex(name);
    }
  }
Example #4
0
  /**
   * Returns two membercalc objects, substituting nulls with the hierarchy null member of the other
   * expression.
   *
   * @param exp0 first expression
   * @param exp1 second expression
   * @return two member calcs
   */
  private MemberCalc[] compileMembers(Exp exp0, Exp exp1, ExpCompiler compiler) {
    MemberCalc[] members = new MemberCalc[2];

    if (exp0.getType() instanceof NullType) {
      members[0] = null;
    } else {
      members[0] = compiler.compileMember(exp0);
    }

    if (exp1.getType() instanceof NullType) {
      members[1] = null;
    } else {
      members[1] = compiler.compileMember(exp1);
    }

    // replace any null types with hierachy null member
    // if both objects are null, throw exception

    if (members[0] == null && members[1] == null) {
      throw MondrianResource.instance().TwoNullsNotSupported.ex();
    } else if (members[0] == null) {
      Member nullMember = ((RolapMember) members[1].evaluate(null)).getHierarchy().getNullMember();
      members[0] = (MemberCalc) ConstantCalc.constantMember(nullMember);
    } else if (members[1] == null) {
      Member nullMember = ((RolapMember) members[0].evaluate(null)).getHierarchy().getNullMember();
      members[1] = (MemberCalc) ConstantCalc.constantMember(nullMember);
    }

    return members;
  }
 public List<RolapMember> getRootMembers() {
   int topLevelDepth = hierarchyAccess.getTopLevelDepth();
   if (topLevelDepth > 0) {
     RolapLevel topLevel = (RolapLevel) getHierarchy().getLevels()[topLevelDepth];
     final List<RolapMember> memberList = getMembersInLevel(topLevel, 0, Integer.MAX_VALUE);
     if (memberList.isEmpty()) {
       throw MondrianResource.instance()
           .HierarchyHasNoAccessibleMembers
           .ex(getHierarchy().getUniqueName());
     }
     return memberList;
   }
   return super.getRootMembers();
 }
/**
 * Container for the default aggregate recognition rules. It is generated by parsing the default
 * rule xml information found in the {@link MondrianProperties#AggregateRules} value which normally
 * is a resource in the jar file (but can be a url).
 *
 * <p>It is a singleton since it is used to recognize tables independent of database connection
 * (each {@link mondrian.rolap.RolapSchema} uses the same instance).
 *
 * @author Richard M. Emberson
 * @version $Id: //open/mondrian-release/3.0/src/main/mondrian/rolap/aggmatcher/DefaultRules.java#2
 *     $
 */
public class DefaultRules {

  private static final Logger LOGGER = Logger.getLogger(DefaultRules.class);

  private static final MondrianResource mres = MondrianResource.instance();
  /**
   * There is a single instance of the {@link DefaultRecognizer} and the {@link DefaultRules} class
   * is a container of that instance.
   */
  public static synchronized DefaultRules getInstance() {
    if (instance == null) {
      InputStream inStream = getAggRuleInputStream();
      if (inStream == null) {
        return null;
      }

      DefaultDef.AggRules defs = makeAggRules(inStream);

      // validate the DefaultDef.AggRules object
      ListRecorder reclists = new ListRecorder();
      try {
        defs.validate(reclists);
      } catch (RecorderException e) {
        // ignore
      }

      reclists.logWarningMessage(LOGGER);
      reclists.logErrorMessage(LOGGER);

      if (reclists.hasErrors()) {
        reclists.throwRTException();
      }

      // make sure the tag name exists
      String tag = MondrianProperties.instance().AggregateRuleTag.get();
      DefaultDef.AggRule aggrule = defs.getAggRule(tag);
      if (aggrule == null) {
        throw mres.MissingDefaultAggRule.ex(tag);
      }

      DefaultRules rules = new DefaultRules(defs);
      rules.setTag(tag);
      instance = rules;
    }
    return instance;
  }

  private static InputStream getAggRuleInputStream() {
    String aggRules = MondrianProperties.instance().AggregateRules.get();

    InputStream inStream = DefaultRules.class.getResourceAsStream(aggRules);
    if (inStream == null) {
      try {
        URL url = new URL(aggRules);
        inStream = url.openStream();
      } catch (MalformedURLException e) {
        // ignore
      } catch (IOException e) {
        // ignore
      }
    }
    if (inStream == null) {
      String msg = mres.CouldNotLoadDefaultAggregateRules.str(aggRules);
      LOGGER.warn(msg);
    }
    return inStream;
  }

  private static DefaultRules instance = null;

  static {
    // When the value of the AggregateRules property is changed, force
    // system to reload the DefaultRules.
    // There is no need to provide equals/hashCode methods for this
    // Trigger since it is a singleton and is never removed.
    Trigger trigger =
        new Trigger() {
          public boolean isPersistent() {
            return true;
          }

          public int phase() {
            return Trigger.PRIMARY_PHASE;
          }

          public void execute(Property property, String value) {
            synchronized (DefaultRules.class) {
              DefaultRules oldInstance = DefaultRules.instance;
              DefaultRules.instance = null;

              DefaultRules newInstance = null;
              Exception ex = null;
              try {
                newInstance = DefaultRules.getInstance();
              } catch (Exception e) {
                ex = e;
              }
              if (ex != null) {
                DefaultRules.instance = oldInstance;

                throw new Trigger.VetoRT(ex);

              } else if (newInstance == null) {
                DefaultRules.instance = oldInstance;

                String msg =
                    mres.FailedCreateNewDefaultAggregateRules.str(property.getPath(), value);
                throw new Trigger.VetoRT(msg);

              } else {
                instance = newInstance;
              }
            }
          }
        };

    final MondrianProperties properties = MondrianProperties.instance();
    properties.AggregateRules.addTrigger(trigger);
    properties.AggregateRuleTag.addTrigger(trigger);
  }

  protected static DefaultDef.AggRules makeAggRules(final File file) {
    DOMWrapper def = makeDOMWrapper(file);
    try {
      DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
      return rules;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex(file.getName(), e);
    }
  }

  protected static DefaultDef.AggRules makeAggRules(final URL url) {
    DOMWrapper def = makeDOMWrapper(url);
    try {
      DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
      return rules;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex(url.toString(), e);
    }
  }

  protected static DefaultDef.AggRules makeAggRules(final InputStream inStream) {
    DOMWrapper def = makeDOMWrapper(inStream);
    try {
      DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
      return rules;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex("InputStream", e);
    }
  }

  protected static DefaultDef.AggRules makeAggRules(final String text, final String name) {
    DOMWrapper def = makeDOMWrapper(text, name);
    try {
      DefaultDef.AggRules rules = new DefaultDef.AggRules(def);
      return rules;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex(name, e);
    }
  }

  protected static DOMWrapper makeDOMWrapper(final File file) {
    try {
      return makeDOMWrapper(file.toURL());
    } catch (MalformedURLException e) {
      throw mres.AggRuleParse.ex(file.getName(), e);
    }
  }

  protected static DOMWrapper makeDOMWrapper(final URL url) {
    try {
      final Parser xmlParser = XOMUtil.createDefaultParser();
      DOMWrapper def = xmlParser.parse(url);
      return def;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex(url.toString(), e);
    }
  }

  protected static DOMWrapper makeDOMWrapper(final InputStream inStream) {
    try {
      final Parser xmlParser = XOMUtil.createDefaultParser();
      DOMWrapper def = xmlParser.parse(inStream);
      return def;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex("InputStream", e);
    }
  }

  protected static DOMWrapper makeDOMWrapper(final String text, final String name) {
    try {
      final Parser xmlParser = XOMUtil.createDefaultParser();
      DOMWrapper def = xmlParser.parse(text);
      return def;
    } catch (XOMException e) {
      throw mres.AggRuleParse.ex(name, e);
    }
  }

  private final DefaultDef.AggRules rules;
  private final Map<String, Recognizer.Matcher> factToPattern;
  private final Map<String, Recognizer.Matcher> foreignKeyMatcherMap;
  private Recognizer.Matcher ignoreMatcherMap;
  private Recognizer.Matcher factCountMatcher;
  private String tag;

  private DefaultRules(final DefaultDef.AggRules rules) {
    this.rules = rules;
    this.factToPattern = new HashMap<String, Recognizer.Matcher>();
    this.foreignKeyMatcherMap = new HashMap<String, Recognizer.Matcher>();
    this.tag = MondrianProperties.instance().AggregateRuleTag.getDefaultValue();
  }

  public void validate(MessageRecorder msgRecorder) {
    rules.validate(msgRecorder);
  }

  /**
   * Sets the name (tag) of this rule.
   *
   * @param tag
   */
  private void setTag(final String tag) {
    this.tag = tag;
  }

  /**
   * Gets the tag of this rule (this is the value of the {@link MondrianProperties#AggregateRuleTag}
   * property).
   */
  public String getTag() {
    return this.tag;
  }

  /**
   * Returns the {@link mondrian.rolap.aggmatcher.DefaultDef.AggRule} whose tag equals this rule's
   * tag.
   */
  public DefaultDef.AggRule getAggRule() {
    return getAggRule(getTag());
  }

  /**
   * Returns the {@link mondrian.rolap.aggmatcher.DefaultDef.AggRule} whose tag equals the parameter
   * tag, or null if not found.
   *
   * @param tag
   * @return the AggRule with tag value equal to tag parameter, or null.
   */
  public DefaultDef.AggRule getAggRule(final String tag) {
    return this.rules.getAggRule(tag);
  }

  /**
   * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for this tableName.
   *
   * @param tableName
   */
  public Recognizer.Matcher getTableMatcher(final String tableName) {
    Recognizer.Matcher matcher = factToPattern.get(tableName);
    if (matcher == null) {
      // get default AggRule
      DefaultDef.AggRule rule = getAggRule();
      DefaultDef.TableMatch tableMatch = rule.getTableMatch();
      matcher = tableMatch.getMatcher(tableName);
      factToPattern.put(tableName, matcher);
    }
    return matcher;
  }

  /** Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for the fact count column. */
  public Recognizer.Matcher getIgnoreMatcher() {
    if (ignoreMatcherMap == null) {
      // get default AggRule
      DefaultDef.AggRule rule = getAggRule();
      DefaultDef.IgnoreMap ignoreMatch = rule.getIgnoreMap();
      if (ignoreMatch == null) {
        ignoreMatcherMap =
            new Recognizer.Matcher() {
              public boolean matches(String name) {
                return false;
              }
            };
      } else {
        ignoreMatcherMap = ignoreMatch.getMatcher();
      }
    }
    return ignoreMatcherMap;
  }

  /**
   * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for columns that should be
   * ignored.
   *
   * @return the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for columns that should be
   *     ignored.
   */
  public Recognizer.Matcher getFactCountMatcher() {
    if (factCountMatcher == null) {
      // get default AggRule
      DefaultDef.AggRule rule = getAggRule();
      DefaultDef.FactCountMatch factCountMatch = rule.getFactCountMatch();
      factCountMatcher = factCountMatch.getMatcher();
    }
    return factCountMatcher;
  }

  /**
   * Gets the {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for this foreign key column name.
   *
   * @param foreignKeyName Name of a foreign key column
   */
  public Recognizer.Matcher getForeignKeyMatcher(String foreignKeyName) {
    Recognizer.Matcher matcher = foreignKeyMatcherMap.get(foreignKeyName);
    if (matcher == null) {
      // get default AggRule
      DefaultDef.AggRule rule = getAggRule();
      DefaultDef.ForeignKeyMatch foreignKeyMatch = rule.getForeignKeyMatch();
      matcher = foreignKeyMatch.getMatcher(foreignKeyName);
      foreignKeyMatcherMap.put(foreignKeyName, matcher);
    }
    return matcher;
  }

  /**
   * Returns true if this candidate aggregate table name "matches" the factTableName.
   *
   * @param factTableName Name of the fact table
   * @param name candidate aggregate table name
   */
  public boolean matchesTableName(final String factTableName, final String name) {
    Recognizer.Matcher matcher = getTableMatcher(factTableName);
    return matcher.matches(name);
  }

  /**
   * Creates a {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for the given measure name
   * (symbolic name), column name and aggregate name (sum, count, etc.).
   */
  public Recognizer.Matcher getMeasureMatcher(
      final String measureName, final String measureColumnName, final String aggregateName) {
    DefaultDef.AggRule rule = getAggRule();
    Recognizer.Matcher matcher =
        rule.getMeasureMap().getMatcher(measureName, measureColumnName, aggregateName);
    return matcher;
  }

  /**
   * Gets a {@link mondrian.rolap.aggmatcher.Recognizer.Matcher} for a given level's hierarchy's
   * name, level name and column name.
   */
  public Recognizer.Matcher getLevelMatcher(
      final String usagePrefix,
      final String hierarchyName,
      final String levelName,
      final String levelColumnName) {
    DefaultDef.AggRule rule = getAggRule();
    Recognizer.Matcher matcher =
        rule.getLevelMap().getMatcher(usagePrefix, hierarchyName, levelName, levelColumnName);
    return matcher;
  }

  /**
   * Uses the {@link DefaultRecognizer} Recognizer to determine if the given aggTable's columns all
   * match upto the dbFactTable's columns (where present) making the column usages as a result.
   */
  public boolean columnsOK(
      final RolapStar star,
      final JdbcSchema.Table dbFactTable,
      final JdbcSchema.Table aggTable,
      final MessageRecorder msgRecorder) {
    Recognizer cb = new DefaultRecognizer(this, star, dbFactTable, aggTable, msgRecorder);
    return cb.check();
  }
}
 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
   throw MondrianResource.instance().SqlQueryLimitReached.ex();
 }