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; }
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; }
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); } }
/** * 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(); }