1 13 14 package mondrian.olap; 15 import mondrian.calc.Calc; 16 import mondrian.calc.ExpCompiler; 17 import mondrian.calc.ExpCompiler.ResultStyle; 18 import mondrian.calc.impl.BetterExpCompiler; 19 import mondrian.mdx.*; 20 import mondrian.olap.fun.FunUtil; 21 import mondrian.olap.fun.ParameterFunDef; 22 import mondrian.olap.type.*; 23 import mondrian.resource.MondrianResource; 24 import mondrian.rolap.*; 25 26 import java.io.*; 27 import java.util.*; 28 29 60 public class Query extends QueryPart { 61 62 65 public Formula[] formulas; 66 67 70 public QueryAxis[] axes; 71 72 75 public QueryAxis slicerAxis; 76 77 80 private final List<Parameter> parameters = new ArrayList<Parameter>(); 81 82 private final Map<String , Parameter> parametersByName = 83 new HashMap<String , Parameter>(); 84 85 88 private final QueryPart[] cellProps; 89 90 93 private final Cube cube; 94 95 private final Connection connection; 96 public Calc[] axisCalcs; 97 public Calc slicerCalc; 98 99 103 Set<FunDef> alertedNonNativeFunDefs; 104 105 108 private long startTime; 109 110 113 private final int queryTimeout; 114 115 118 private boolean isCanceled; 119 120 124 private String outOfMemoryMsg; 125 126 129 private boolean isExecuting; 130 131 136 private Set<Member> measuresMembers; 137 138 142 private boolean nativeCrossJoinVirtualCube; 143 144 149 private Set<Map<RolapLevel, RolapStar.Column>> virtualCubeBaseCubeMaps; 150 151 156 private Map<Map<RolapLevel, RolapStar.Column>, RolapMember> levelMapToMeasureMap; 157 158 161 private boolean load; 162 163 170 private ResultStyle resultStyle = (Util.PreJdk15) 171 ? ResultStyle.LIST : ResultStyle.ITERABLE; 172 173 174 private Map<String , Object > evalCache = new HashMap<String , Object >(); 175 176 179 public Query( 180 Connection connection, 181 Formula[] formulas, 182 QueryAxis[] axes, 183 String cube, 184 QueryAxis slicerAxis, 185 QueryPart[] cellProps, 186 boolean load) { 187 this(connection, 188 connection.getSchema().lookupCube(cube, true), 189 formulas, 190 axes, 191 slicerAxis, 192 cellProps, 193 new Parameter[0], 194 load); 195 } 196 197 200 public Query( 201 Connection connection, 202 Cube mdxCube, 203 Formula[] formulas, 204 QueryAxis[] axes, 205 QueryAxis slicerAxis, 206 QueryPart[] cellProps, 207 Parameter[] parameters, 208 boolean load) { 209 this.connection = connection; 210 this.cube = mdxCube; 211 this.formulas = formulas; 212 this.axes = axes; 213 normalizeAxes(); 214 this.slicerAxis = slicerAxis; 215 this.cellProps = cellProps; 216 this.parameters.addAll(Arrays.asList(parameters)); 217 this.isExecuting = false; 218 this.queryTimeout = 219 MondrianProperties.instance().QueryTimeout.get() * 1000; 220 this.measuresMembers = new HashSet<Member>(); 221 this.nativeCrossJoinVirtualCube = true; 224 this.load = load; 225 this.alertedNonNativeFunDefs = new HashSet<FunDef>(); 226 resolve(); 227 } 228 229 233 public void addFormula(String [] names, Exp exp) { 234 Formula newFormula = new Formula(names, exp); 235 int formulaCount = 0; 236 if (formulas.length > 0) { 237 formulaCount = formulas.length; 238 } 239 Formula[] newFormulas = new Formula[formulaCount + 1]; 240 System.arraycopy(formulas, 0, newFormulas, 0, formulaCount); 241 newFormulas[formulaCount] = newFormula; 242 formulas = newFormulas; 243 resolve(); 244 } 245 246 250 public void addFormula( 251 String [] names, 252 Exp exp, 253 MemberProperty[] memberProperties) { 254 Formula newFormula = new Formula(names, exp, memberProperties); 255 int formulaCount = 0; 256 if (formulas.length > 0) { 257 formulaCount = formulas.length; 258 } 259 Formula[] newFormulas = new Formula[formulaCount + 1]; 260 System.arraycopy(formulas, 0, newFormulas, 0, formulaCount); 261 newFormulas[formulaCount] = newFormula; 262 formulas = newFormulas; 263 resolve(); 264 } 265 266 public Validator createValidator() { 267 return new StackValidator(connection.getSchema().getFunTable()); 268 } 269 270 public Object clone() { 271 return new Query( 272 connection, 273 cube, 274 Formula.cloneArray(formulas), 275 QueryAxis.cloneArray(axes), 276 (slicerAxis == null) ? null : (QueryAxis) slicerAxis.clone(), 277 cellProps, 278 parameters.toArray(new Parameter[parameters.size()]), 279 load); 280 } 281 282 public Query safeClone() { 283 return (Query) clone(); 284 } 285 286 public Connection getConnection() { 287 return connection; 288 } 289 290 299 public String getQueryString() { 300 return toMdx(); 301 } 302 303 309 public void cancel() { 310 isCanceled = true; 311 } 312 313 void setOutOfMemory(String msg) { 314 outOfMemoryMsg = msg; 315 } 316 317 325 public void checkCancelOrTimeout() { 326 if (!isExecuting) { 327 return; 328 } 329 if (isCanceled) { 330 throw MondrianResource.instance().QueryCanceled.ex(); 331 } 332 if (queryTimeout > 0) { 333 long currTime = System.currentTimeMillis(); 334 if ((currTime - startTime) >= queryTimeout) { 335 throw MondrianResource.instance().QueryTimeout.ex( 336 (long) queryTimeout / 1000); 337 } 338 } 339 if (outOfMemoryMsg != null) { 340 throw new MemoryLimitExceededException(outOfMemoryMsg); 341 } 342 } 343 344 348 public void setQueryStartTime() { 349 startTime = System.currentTimeMillis(); 350 isExecuting = true; 351 } 352 353 358 public void setQueryEndExecution() { 359 isExecuting = false; 360 } 361 362 370 public boolean shouldAlertForNonNative(FunDef funDef) { 371 return alertedNonNativeFunDefs.add(funDef); 372 } 373 374 private void normalizeAxes() { 375 for (int i = 0; i < axes.length; i++) { 376 AxisOrdinal correctOrdinal = AxisOrdinal.forLogicalOrdinal(i); 377 if (axes[i].getAxisOrdinal() != correctOrdinal) { 378 for (int j = i + 1; j < axes.length; j++) { 379 if (axes[j].getAxisOrdinal() == correctOrdinal) { 380 QueryAxis temp = axes[i]; 382 axes[i] = axes[j]; 383 axes[j] = temp; 384 break; 385 } 386 } 387 } 388 } 389 } 390 391 399 public void resolve() { 400 final Validator validator = createValidator(); 401 resolve(validator); final Evaluator evaluator = RolapUtil.createEvaluator(this); 404 ExpCompiler compiler = createCompiler(evaluator, validator); 405 compile(compiler); 406 } 407 408 412 public boolean ignoreInvalidMembers() 413 { 414 return load && 415 MondrianProperties.instance().IgnoreInvalidMembers.get(); 416 } 417 418 426 public void setResultStyle(ResultStyle resultStyle) { 427 switch (resultStyle) { 428 case ITERABLE : 429 resultStyle = (Util.PreJdk15) 431 ? ResultStyle.LIST : ResultStyle.ITERABLE; 432 break; 433 case LIST : 434 case MUTABLE_LIST: 435 this.resultStyle = resultStyle; 436 break; 437 default : 438 throw ResultStyleException.generateBadType( 439 new ResultStyle[] { 440 ResultStyle.ITERABLE, 441 ResultStyle.LIST, 442 ResultStyle.MUTABLE_LIST 443 }, 444 resultStyle 445 ); 446 } 447 } 448 public ResultStyle getResultStyle() { 449 return resultStyle; 450 } 451 452 457 private void compile(ExpCompiler compiler) { 458 if (formulas != null) { 459 for (Formula formula : formulas) { 460 formula.compile(); 461 } 462 } 463 464 if (axes != null) { 465 axisCalcs = new Calc[axes.length]; 466 for (int i = 0; i < axes.length; i++) { 467 axisCalcs[i] = axes[i].compile(compiler, 468 new ResultStyle[] { resultStyle }); 469 } 470 } 471 if (slicerAxis != null) { 472 slicerCalc = slicerAxis.compile(compiler, 473 new ResultStyle[] { resultStyle }); 474 } 475 } 476 477 482 void resolve(Validator validator) { 483 if (formulas != null) { 486 for (Formula formula : formulas) { 490 formula.createElement(validator.getQuery()); 491 } 492 } 493 494 parameters.clear(); 496 parametersByName.clear(); 497 accept( 498 new MdxVisitorImpl() { 499 public Object visit(ParameterExpr parameterExpr) { 500 Parameter parameter = parameterExpr.getParameter(); 501 if (!parameters.contains(parameter)) { 502 parameters.add(parameter); 503 parametersByName.put(parameter.getName(), parameter); 504 } 505 return null; 506 } 507 508 public Object visit(UnresolvedFunCall call) { 509 if (call.getFunName().equals("Parameter")) { 510 String parameterName = 512 ParameterFunDef.getParameterName(call.getArgs()); 513 if (parametersByName.get(parameterName) != null) { 514 throw MondrianResource.instance(). 515 ParameterDefinedMoreThanOnce.ex(parameterName); 516 } 517 518 Type type = 519 ParameterFunDef.getParameterType(call.getArgs()); 520 521 Parameter parameter = new ParameterImpl( 524 parameterName, Literal.nullValue, null, type); 525 parameters.add(parameter); 526 parametersByName.put(parameterName, parameter); 527 } 528 return null; 529 } 530 } 531 ); 532 533 if (formulas != null) { 535 for (Formula formula : formulas) { 536 validator.validate(formula); 537 } 538 } 539 540 if (axes != null) { 542 for (QueryAxis axis : axes) { 543 validator.validate(axis); 544 } 545 } 546 if (slicerAxis != null) { 547 slicerAxis.validate(validator); 548 } 549 550 final Dimension[] dimensions = getCube().getDimensions(); 552 for (Dimension dimension : dimensions) { 553 int useCount = 0; 554 for (int j = -1; j < axes.length; j++) { 555 final QueryAxis axisExp; 556 if (j < 0) { 557 if (slicerAxis == null) { 558 continue; 559 } 560 axisExp = slicerAxis; 561 } else { 562 axisExp = axes[j]; 563 } 564 if (axisExp.getSet().getType().usesDimension(dimension, 565 false)) { 566 ++useCount; 567 } 568 } 569 if (useCount > 1) { 570 throw MondrianResource.instance().DimensionInIndependentAxes.ex( 571 dimension.getUniqueName()); 572 } 573 } 574 } 575 576 public void unparse(PrintWriter pw) { 577 if (formulas != null) { 578 for (int i = 0; i < formulas.length; i++) { 579 if (i == 0) { 580 pw.print("with "); 581 } else { 582 pw.print(" "); 583 } 584 formulas[i].unparse(pw); 585 pw.println(); 586 } 587 } 588 pw.print("select "); 589 if (axes != null) { 590 for (int i = 0; i < axes.length; i++) { 591 axes[i].unparse(pw); 592 if (i < axes.length - 1) { 593 pw.println(","); 594 pw.print(" "); 595 } else { 596 pw.println(); 597 } 598 } 599 } 600 if (cube != null) { 601 pw.println("from [" + cube.getName() + "]"); 602 } 603 if (slicerAxis != null) { 604 pw.print("where "); 605 slicerAxis.unparse(pw); 606 pw.println(); 607 } 608 } 609 610 public String toMdx() { 611 StringWriter sw = new StringWriter(); 612 PrintWriter pw = new QueryPrintWriter(sw); 613 unparse(pw); 614 return sw.toString(); 615 } 616 617 618 public String toString() { 619 resolve(); 620 return Util.unparse(this); 621 } 622 623 public Object [] getChildren() { 624 List<QueryPart> list = new ArrayList<QueryPart>(); 627 for (QueryAxis axis : axes) { 628 list.add(axis); 629 } 630 if (slicerAxis != null) { 631 list.add(slicerAxis); 632 } 633 for (Formula formula : formulas) { 634 list.add(formula); 635 } 636 return list.toArray(); 637 } 638 639 public QueryAxis getSlicerAxis() { 640 return slicerAxis; 641 } 642 643 public void setSlicerAxis(QueryAxis axis) { 644 this.slicerAxis = axis; 645 } 646 647 650 public void addLevelToAxis(AxisOrdinal axis, Level level) { 651 assert axis != null; 652 axes[axis.logicalOrdinal()].addLevel(level); 653 } 654 655 674 private Hierarchy[] collectHierarchies(Exp queryPart) { 675 Type exprType = queryPart.getType(); 676 if (exprType instanceof SetType) { 677 exprType = ((SetType) exprType).getElementType(); 678 } 679 if (exprType instanceof TupleType) { 680 final Type[] types = ((TupleType) exprType).elementTypes; 681 ArrayList<Hierarchy> hierarchyList = new ArrayList<Hierarchy>(); 682 for (Type type : types) { 683 hierarchyList.add(getTypeHierarchy(type)); 684 } 685 return hierarchyList.toArray(new Hierarchy[hierarchyList.size()]); 686 } 687 return new Hierarchy[] {getTypeHierarchy(exprType)}; 688 } 689 690 private Hierarchy getTypeHierarchy(final Type type) { 691 Hierarchy hierarchy = type.getHierarchy(); 692 if (hierarchy != null) { 693 return hierarchy; 694 } 695 final Dimension dimension = type.getDimension(); 696 if (dimension != null) { 697 return dimension.getHierarchy(); 698 } 699 return null; 700 } 701 702 707 public void setParameter(String parameterName, String value) { 708 if (parameters.isEmpty()) { 712 resolve(); 713 } 714 715 Parameter param = getSchemaReader(false).getParameter(parameterName); 716 if (param == null) { 717 throw MondrianResource.instance().UnknownParameter.ex(parameterName); 718 } 719 if (!param.isModifiable()) { 720 throw MondrianResource.instance().ParameterIsNotModifiable.ex( 721 parameterName, param.getScope().name()); 722 } 723 final Exp exp = quickParse( 724 TypeUtil.typeToCategory(param.getType()), value, this); 725 param.setValue(exp); 726 } 727 728 private static Exp quickParse(int category, String value, Query query) { 729 switch (category) { 730 case Category.Numeric: 731 return Literal.create(new Double (value)); 732 case Category.String: 733 return Literal.createString(value); 734 case Category.Member: 735 Member member = (Member) Util.lookup(query, Util.explode(value)); 736 return new MemberExpr(member); 737 default: 738 throw Category.instance.badValue(category); 739 } 740 } 741 742 746 public void swapAxes() { 747 if (axes.length == 2) { 748 Exp e0 = axes[0].getSet(); 749 boolean nonEmpty0 = axes[0].isNonEmpty(); 750 Exp e1 = axes[1].getSet(); 751 boolean nonEmpty1 = axes[1].isNonEmpty(); 752 axes[1].setSet(e0); 753 axes[1].setNonEmpty(nonEmpty0); 754 axes[0].setSet(e1); 755 axes[0].setNonEmpty(nonEmpty1); 756 } 758 } 759 760 763 public Parameter[] getParameters() { 764 return parameters.toArray(new Parameter[parameters.size()]); 765 } 766 767 public Cube getCube() { 768 return cube; 769 } 770 771 public SchemaReader getSchemaReader(boolean accessControlled) { 772 final Role role = accessControlled 773 ? getConnection().getRole() 774 : null; 775 final SchemaReader cubeSchemaReader = cube.getSchemaReader(role); 776 return new QuerySchemaReader(cubeSchemaReader); 777 } 778 779 783 public Member lookupMemberFromCache(String s) { 784 for (Member member : getDefinedMembers()) { 786 if (Util.equalName(member.getUniqueName(), s)) { 787 return member; 788 } 789 } 790 return null; 791 } 792 793 796 private NamedSet lookupNamedSet(String name) { 797 for (Formula formula : formulas) { 798 if (!formula.isMember() && 799 formula.getElement() != null && 800 formula.getName().equals(name)) { 801 return (NamedSet) formula.getElement(); 802 } 803 } 804 return null; 805 } 806 807 810 public Formula[] getFormulas() { 811 return formulas; 812 } 813 814 817 public QueryAxis[] getAxes() { 818 return axes; 819 } 820 821 826 public void removeFormula(String uniqueName, boolean failIfUsedInQuery) { 827 Formula formula = findFormula(uniqueName); 828 if (failIfUsedInQuery && formula != null) { 829 OlapElement mdxElement = formula.getElement(); 830 Walker walker = new Walker(this); 833 while (walker.hasMoreElements()) { 834 Object queryElement = walker.nextElement(); 835 if (!queryElement.equals(mdxElement)) { 836 continue; 837 } 838 String formulaType = formula.isMember() 841 ? MondrianResource.instance().CalculatedMember.str() 842 : MondrianResource.instance().CalculatedSet.str(); 843 844 int i = 0; 845 Object parent = walker.getAncestor(i); 846 Object grandParent = walker.getAncestor(i+1); 847 while ((parent != null) && (grandParent != null)) { 848 if (grandParent instanceof Query) { 849 if (parent instanceof Axis) { 850 throw MondrianResource.instance(). 851 MdxCalculatedFormulaUsedOnAxis.ex( 852 formulaType, 853 uniqueName, 854 ((QueryAxis) parent).getAxisName()); 855 856 } else if (parent instanceof Formula) { 857 String parentFormulaType = 858 ((Formula) parent).isMember() 859 ? MondrianResource.instance().CalculatedMember.str() 860 : MondrianResource.instance().CalculatedSet.str(); 861 throw MondrianResource.instance(). 862 MdxCalculatedFormulaUsedInFormula.ex( 863 formulaType, uniqueName, parentFormulaType, 864 ((Formula) parent).getUniqueName()); 865 866 } else { 867 throw MondrianResource.instance(). 868 MdxCalculatedFormulaUsedOnSlicer.ex( 869 formulaType, uniqueName); 870 } 871 } 872 ++i; 873 parent = walker.getAncestor(i); 874 grandParent = walker.getAncestor(i+1); 875 } 876 throw MondrianResource.instance(). 877 MdxCalculatedFormulaUsedInQuery.ex( 878 formulaType, uniqueName, Util.unparse(this)); 879 } 880 } 881 882 List<Formula> formulaList = new ArrayList<Formula>(); 884 for (Formula formula1 : formulas) { 885 if (!formula1.getUniqueName().equalsIgnoreCase(uniqueName)) { 886 formulaList.add(formula1); 887 } 888 } 889 890 this.formulas = formulaList.toArray(new Formula[0]); 892 } 893 894 897 public boolean canRemoveFormula(String uniqueName) { 898 Formula formula = findFormula(uniqueName); 899 if (formula == null) { 900 return false; 901 } 902 903 OlapElement mdxElement = formula.getElement(); 904 Walker walker = new Walker(this); 907 while (walker.hasMoreElements()) { 908 Object queryElement = walker.nextElement(); 909 if (!queryElement.equals(mdxElement)) { 910 continue; 911 } 912 return false; 913 } 914 return true; 915 } 916 917 918 public Formula findFormula(String uniqueName) { 919 for (Formula formula : formulas) { 920 if (formula.getUniqueName().equalsIgnoreCase(uniqueName)) { 921 return formula; 922 } 923 } 924 return null; 925 } 926 927 930 public void renameFormula(String uniqueName, String newName) { 931 Formula formula = findFormula(uniqueName); 932 if (formula == null) { 933 throw MondrianResource.instance().MdxFormulaNotFound.ex( 934 "formula", uniqueName, Util.unparse(this)); 935 } 936 formula.rename(newName); 937 } 938 939 List<Member> getDefinedMembers() { 940 List<Member> definedMembers = new ArrayList<Member>(); 941 for (final Formula formula : formulas) { 942 if (formula.isMember() && 943 formula.getElement() != null && 944 getConnection().getRole().canAccess(formula.getElement())) { 945 definedMembers.add((Member) formula.getElement()); 946 } 947 } 948 return definedMembers; 949 } 950 951 954 public void setAxisShowEmptyCells(int axis, boolean showEmpty) { 955 if (axis >= axes.length) { 956 throw MondrianResource.instance().MdxAxisShowSubtotalsNotSupported. 957 ex(axis); 958 } 959 axes[axis].setNonEmpty(!showEmpty); 960 } 961 962 966 public Hierarchy[] getMdxHierarchiesOnAxis(AxisOrdinal axis) { 967 if (axis.logicalOrdinal() >= axes.length) { 968 throw MondrianResource.instance().MdxAxisShowSubtotalsNotSupported. 969 ex(axis.logicalOrdinal()); 970 } 971 QueryAxis queryAxis = (axis == AxisOrdinal.SLICER) ? 972 slicerAxis : 973 axes[axis.logicalOrdinal()]; 974 return collectHierarchies(queryAxis.getSet()); 975 } 976 977 public Calc compileExpression(Exp exp, boolean scalar) { 978 Evaluator evaluator = RolapEvaluator.create(this); 979 final Validator validator = createValidator(); 980 final ExpCompiler compiler = createCompiler(evaluator, validator); 981 Calc calc = (scalar) 982 ? compiler.compileScalar(exp, false) 983 : compiler.compile(exp); 984 return calc; 985 } 986 987 private ExpCompiler createCompiler( 988 final Evaluator evaluator, final Validator validator) { 989 990 ExpCompiler compiler = ExpCompiler.Factory.getExpCompiler( 991 evaluator, 992 validator, 993 new ResultStyle[] { resultStyle }); 994 995 final int expDeps = MondrianProperties.instance().TestExpDependencies.get(); 996 if (expDeps > 0) { 997 compiler = RolapUtil.createDependencyTestingCompiler(compiler); 998 } 999 return compiler; 1000 } 1001 1002 1007 public void addMeasuresMembers(OlapElement olapElement) 1008 { 1009 if (olapElement instanceof Member) { 1010 Member member = (Member) olapElement; 1011 if (member.getDimension().getOrdinal(getCube()) == 0) { 1012 measuresMembers.add(member); 1013 } 1014 } 1015 } 1016 1017 1021 public Set<Member> getMeasuresMembers() { 1022 return Collections.unmodifiableSet(measuresMembers); 1023 } 1024 1025 1029 public void setVirtualCubeNonNativeCrossJoin() { 1030 nativeCrossJoinVirtualCube = false; 1031 } 1032 1033 1037 public boolean nativeCrossJoinVirtualCube() { 1038 return nativeCrossJoinVirtualCube; 1039 } 1040 1041 1047 public void setVirtualCubeBaseCubeMaps(Set<Map<RolapLevel, RolapStar.Column>> maps) 1048 { 1049 virtualCubeBaseCubeMaps = maps; 1050 } 1051 1052 1056 public Set<Map<RolapLevel, RolapStar.Column>> getVirtualCubeBaseCubeMaps() 1057 { 1058 return virtualCubeBaseCubeMaps; 1059 } 1060 1061 1066 public void setLevelMapToMeasureMap( 1067 Map<Map<RolapLevel, RolapStar.Column>, RolapMember> map) 1068 { 1069 levelMapToMeasureMap = map; 1070 } 1071 1072 1075 public Map<Map<RolapLevel, RolapStar.Column>, RolapMember> getLevelMapToMeasureMap() 1076 { 1077 return levelMapToMeasureMap; 1078 } 1079 1080 public Object accept(MdxVisitor visitor) { 1081 Object o = visitor.visit(this); 1082 1083 for (Formula formula : formulas) { 1085 formula.accept(visitor); 1086 } 1087 for (QueryAxis axis : axes) { 1089 axis.accept(visitor); 1090 } 1091 if (slicerAxis != null) { 1092 slicerAxis.accept(visitor); 1093 } 1094 1095 return o; 1096 } 1097 1098 1106 public void putEvalCache(String key, Object value) { 1107 evalCache.put(key, value); 1108 } 1109 1110 1116 public Object getEvalCache(String key) { 1117 return evalCache.get(key); 1118 } 1119 1120 1123 public void clearEvalCache() { 1124 evalCache.clear(); 1125 } 1126 1127 1140 private class StackValidator implements Validator { 1141 private final Stack<QueryPart> stack = new Stack<QueryPart>(); 1142 private final FunTable funTable; 1143 private final Map<QueryPart, QueryPart> resolvedNodes = 1144 new HashMap<QueryPart, QueryPart>(); 1145 private final QueryPart placeHolder = Literal.zero; 1146 1147 1152 public StackValidator(FunTable funTable) { 1153 Util.assertPrecondition(funTable != null, "funTable != null"); 1154 this.funTable = funTable; 1155 } 1156 1157 public Query getQuery() { 1158 return Query.this; 1159 } 1160 1161 public Exp validate(Exp exp, boolean scalar) { 1162 Exp resolved; 1163 try { 1164 resolved = (Exp) resolvedNodes.get(exp); 1165 } catch (ClassCastException e) { 1166 throw Util.newInternal( 1170 e, 1171 "Infinite recursion encountered while validating '" + 1172 Util.unparse(exp) + "'"); 1173 } 1174 if (resolved == null) { 1175 try { 1176 stack.push((QueryPart) exp); 1177 resolvedNodes.put((QueryPart) exp, placeHolder); 1180 resolved = exp.accept(this); 1181 Util.assertTrue(resolved != null); 1182 resolvedNodes.put((QueryPart) exp, (QueryPart) resolved); 1183 } finally { 1184 stack.pop(); 1185 } 1186 } 1187 1188 if (scalar) { 1189 final Type type = resolved.getType(); 1190 if (!TypeUtil.canEvaluate(type)) { 1191 String exprString = Util.unparse(resolved); 1192 throw MondrianResource.instance().MdxMemberExpIsSet.ex(exprString); 1193 } 1194 } 1195 1196 return resolved; 1197 } 1198 1199 public void validate(ParameterExpr parameterExpr) { 1200 ParameterExpr resolved = 1201 (ParameterExpr) resolvedNodes.get(parameterExpr); 1202 if (resolved != null) { 1203 return; } 1205 try { 1206 stack.push(parameterExpr); 1207 resolvedNodes.put(parameterExpr, placeHolder); 1208 resolved = (ParameterExpr) parameterExpr.accept(this); 1209 assert resolved != null; 1210 resolvedNodes.put(parameterExpr, resolved); 1211 } finally { 1212 stack.pop(); 1213 } 1214 } 1215 1216 public void validate(MemberProperty memberProperty) { 1217 MemberProperty resolved = 1218 (MemberProperty) resolvedNodes.get(memberProperty); 1219 if (resolved != null) { 1220 return; } 1222 try { 1223 stack.push(memberProperty); 1224 resolvedNodes.put(memberProperty, placeHolder); 1225 memberProperty.resolve(this); 1226 resolvedNodes.put(memberProperty, memberProperty); 1227 } finally { 1228 stack.pop(); 1229 } 1230 } 1231 1232 public void validate(QueryAxis axis) { 1233 final QueryAxis resolved = (QueryAxis) resolvedNodes.get(axis); 1234 if (resolved != null) { 1235 return; } 1237 try { 1238 stack.push(axis); 1239 resolvedNodes.put(axis, placeHolder); 1240 axis.resolve(this); 1241 resolvedNodes.put(axis, axis); 1242 } finally { 1243 stack.pop(); 1244 } 1245 } 1246 1247 public void validate(Formula formula) { 1248 final Formula resolved = (Formula) resolvedNodes.get(formula); 1249 if (resolved != null) { 1250 return; } 1252 try { 1253 stack.push(formula); 1254 resolvedNodes.put(formula, placeHolder); 1255 formula.accept(this); 1256 resolvedNodes.put(formula, formula); 1257 } finally { 1258 stack.pop(); 1259 } 1260 } 1261 1262 public boolean canConvert(Exp fromExp, int to, int[] conversionCount) { 1263 return FunUtil.canConvert(fromExp, to, conversionCount); 1264 } 1265 1266 public boolean requiresExpression() { 1267 return requiresExpression(stack.size() - 1); 1268 } 1269 1270 private boolean requiresExpression(int n) { 1271 if (n < 1) { 1272 return false; 1273 } 1274 final Object parent = stack.get(n - 1); 1275 if (parent instanceof Formula) { 1276 return ((Formula) parent).isMember(); 1277 } else if (parent instanceof ResolvedFunCall) { 1278 final ResolvedFunCall funCall = (ResolvedFunCall) parent; 1279 if (funCall.getFunDef().getSyntax() == Syntax.Parentheses) { 1280 return requiresExpression(n - 1); 1281 } else { 1282 int k = whichArg(funCall, (Exp) stack.get(n)); 1283 if (k < 0) { 1284 return false; 1289 } 1290 final FunDef funDef = funCall.getFunDef(); 1291 final int[] parameterTypes = funDef.getParameterCategories(); 1292 return parameterTypes[k] != Category.Set; 1293 } 1294 } else if (parent instanceof UnresolvedFunCall) { 1295 final UnresolvedFunCall funCall = (UnresolvedFunCall) parent; 1296 if (funCall.getSyntax() == Syntax.Parentheses) { 1297 return requiresExpression(n - 1); 1298 } else { 1299 int k = whichArg(funCall, (Exp) stack.get(n)); 1300 if (k < 0) { 1301 return false; 1306 } 1307 return funTable.requiresExpression(funCall, k, this); 1308 } 1309 } else { 1310 return false; 1311 } 1312 } 1313 1314 public FunTable getFunTable() { 1315 return funTable; 1316 } 1317 1318 public Parameter createOrLookupParam( 1319 boolean definition, 1320 String name, 1321 Type type, 1322 Exp defaultExp, 1323 String description) 1324 { 1325 final SchemaReader schemaReader = getSchemaReader(false); 1326 Parameter param = schemaReader.getParameter(name); 1327 1328 if (definition) { 1329 if (param != null) { 1330 if (param.getScope() == Parameter.Scope.Statement) { 1331 ParameterImpl paramImpl = (ParameterImpl) param; 1332 paramImpl.setDescription(description); 1333 paramImpl.setDefaultExp(defaultExp); 1334 paramImpl.setType(type); 1335 } 1336 return param; 1337 } 1338 param = new ParameterImpl( 1339 name, 1340 defaultExp, description, type); 1341 1342 parameters.add(param); 1344 parametersByName.put(name, param); 1345 return param; 1346 } else { 1347 if (param != null) { 1348 return param; 1349 } 1350 throw MondrianResource.instance().UnknownParameter.ex(name); 1351 } 1352 } 1353 1354 private int whichArg(final FunCall node, final Exp arg) { 1355 final Exp[] children = node.getArgs(); 1356 for (int i = 0; i < children.length; i++) { 1357 if (children[i] == arg) { 1358 return i; 1359 } 1360 } 1361 return -1; 1362 } 1363 } 1364 1365 1371 private class QuerySchemaReader extends DelegatingSchemaReader { 1372 1373 public QuerySchemaReader(SchemaReader cubeSchemaReader) { 1374 super(cubeSchemaReader); 1375 } 1376 1377 public Member getMemberByUniqueName( 1378 String [] uniqueNameParts, 1379 boolean failIfNotFound) 1380 { 1381 return getMemberByUniqueName( 1382 uniqueNameParts, failIfNotFound, MatchType.EXACT); 1383 } 1384 1385 public Member getMemberByUniqueName( 1386 String [] uniqueNameParts, 1387 boolean failIfNotFound, 1388 MatchType matchType) 1389 { 1390 final String uniqueName = Util.implode(uniqueNameParts); 1391 Member member = lookupMemberFromCache(uniqueName); 1392 if (member == null) { 1393 member = schemaReader.getMemberByUniqueName( 1395 uniqueNameParts, failIfNotFound, matchType); 1396 } 1397 if (!failIfNotFound && member == null) { 1398 return null; 1399 } 1400 if (getRole().canAccess(member)) { 1401 return member; 1402 } else { 1403 return null; 1404 } 1405 } 1406 1407 public Member[] getLevelMembers( 1408 Level level, boolean includeCalculated) { 1409 Member[] members = super.getLevelMembers(level, false); 1410 if (includeCalculated) { 1411 members = Util.addLevelCalculatedMembers(this, level, members); 1412 } 1413 return members; 1414 } 1415 1416 public Member getCalculatedMember(String [] nameParts) { 1417 final String uniqueName = Util.implode(nameParts); 1418 return lookupMemberFromCache(uniqueName); 1419 } 1420 1421 public List<Member> getCalculatedMembers(Hierarchy hierarchy) { 1422 List<Member> result = new ArrayList<Member>(); 1423 final List<Member> calculatedMembers = 1425 super.getCalculatedMembers(hierarchy); 1426 result.addAll(calculatedMembers); 1427 for (Member member : getDefinedMembers()) { 1429 if (member.getHierarchy().equals(hierarchy)) { 1430 result.add(member); 1431 } 1432 } 1433 return result; 1434 } 1435 1436 public List<Member> getCalculatedMembers(Level level) { 1437 List<Member> hierarchyMembers = 1438 getCalculatedMembers(level.getHierarchy()); 1439 List<Member> result = new ArrayList<Member>(); 1440 for (Member member : hierarchyMembers) { 1441 if (member.getLevel().equals(level)) { 1442 result.add(member); 1443 } 1444 } 1445 return result; 1446 } 1447 1448 public List<Member> getCalculatedMembers() { 1449 return getDefinedMembers(); 1450 } 1451 1452 public OlapElement getElementChild(OlapElement parent, String s) 1453 { 1454 return getElementChild(parent, s, MatchType.EXACT); 1455 } 1456 1457 public OlapElement getElementChild( 1458 OlapElement parent, String s, MatchType matchType) 1459 { 1460 OlapElement mdxElement = 1462 schemaReader.getElementChild(parent, s, matchType); 1463 if (mdxElement != null) { 1464 return mdxElement; 1465 } 1466 1468 for (Formula formula : formulas) { 1470 if (formula.isMember()) { 1471 continue; } 1473 if (Util.equalName(formula.getNames()[0], s)) { 1474 return formula.getNamedSet(); 1475 } 1476 } 1477 1478 return mdxElement; 1479 } 1480 1481 public OlapElement lookupCompound( 1482 OlapElement parent, 1483 String [] names, 1484 boolean failIfNotFound, 1485 int category) 1486 { 1487 return lookupCompound( 1488 parent, names, failIfNotFound, category, MatchType.EXACT); 1489 } 1490 1491 public OlapElement lookupCompound( 1492 OlapElement parent, 1493 String [] names, 1494 boolean failIfNotFound, 1495 int category, 1496 MatchType matchType) 1497 { 1498 switch (category) { 1500 case Category.Unknown: 1501 case Category.Member: 1502 if (parent == cube) { 1503 final Member calculatedMember = getCalculatedMember(names); 1504 if (calculatedMember != null) { 1505 return calculatedMember; 1506 } 1507 } 1508 } 1509 switch (category) { 1510 case Category.Unknown: 1511 case Category.Set: 1512 if (parent == cube) { 1513 final NamedSet namedSet = getNamedSet(names); 1514 if (namedSet != null) { 1515 return namedSet; 1516 } 1517 } 1518 } 1519 OlapElement olapElement = super.lookupCompound( 1521 parent, names, failIfNotFound, category, matchType); 1522 if (olapElement instanceof Member) { 1523 Member member = (Member) olapElement; 1524 final Formula formula = (Formula) 1525 member.getPropertyValue(Property.FORMULA.name); 1526 if (formula != null) { 1527 final Formula formulaClone = (Formula) formula.clone(); 1531 formulaClone.createElement(Query.this); 1532 formulaClone.accept(createValidator()); 1533 olapElement = formulaClone.getMdxMember(); 1534 } 1535 } 1536 return olapElement; 1537 } 1538 1539 public NamedSet getNamedSet(String [] nameParts) { 1540 if (nameParts.length != 1) { 1541 return null; 1542 } 1543 return lookupNamedSet(nameParts[0]); 1544 } 1545 1546 public Parameter getParameter(String name) { 1547 for (Parameter parameter : parameters) { 1549 if (parameter.getName().equals(name)) { 1550 return parameter; 1551 } 1552 } 1553 1554 if (Util.lookup(RolapConnectionProperties.class, name) != null) { 1556 Object value = connection.getProperty(name); 1557 Literal defaultValue = 1561 Literal.createString(String.valueOf(value)); 1562 return new ConnectionParameterImpl(name, defaultValue); 1563 } 1564 1565 return super.getParameter(name); 1566 } 1567 1568 } 1569 1570 private static class ConnectionParameterImpl 1571 extends ParameterImpl 1572 { 1573 public ConnectionParameterImpl(String name, Literal defaultValue) { 1574 super(name, defaultValue, "Connection property", new StringType()); 1575 } 1576 1577 public Scope getScope() { 1578 return Scope.Connection; 1579 } 1580 1581 public void setValue(Object value) { 1582 throw MondrianResource.instance().ParameterIsNotModifiable.ex( 1583 getName(), getScope().name()); 1584 } 1585 } 1586} 1587 1588 | Popular Tags |