001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2006-2009 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.mdx; 011 012import mondrian.calc.*; 013import mondrian.olap.*; 014import mondrian.olap.type.*; 015 016import java.io.PrintWriter; 017import java.util.List; 018 019/** 020 * MDX expression which is a usage of a {@link mondrian.olap.Parameter}. 021 * 022 * @author jhyde 023 */ 024public class ParameterExpr extends ExpBase { 025 026 private Parameter parameter; 027 028 /** 029 * Creates a ParameterExpr. 030 * 031 * @param parameter Parameter 032 */ 033 public ParameterExpr(Parameter parameter) 034 { 035 this.parameter = parameter; 036 } 037 038 public Type getType() { 039 return parameter.getType(); 040 } 041 042 public int getCategory() { 043 return TypeUtil.typeToCategory(parameter.getType()); 044 } 045 046 public Exp accept(Validator validator) { 047 // There must be some Parameter with this name registered with the 048 // Query. After clone(), there will be many copies of the same 049 // parameter, and we rely on this method to bring them down to one. 050 // So if this object is not the registered vesion, that's fine, go with 051 // the other one. The registered one will be resolved after everything 052 // else in the query has been resolved. 053 String parameterName = parameter.getName(); 054 final SchemaReader schemaReader = 055 validator.getQuery().getSchemaReader(false); 056 Parameter p = schemaReader.getParameter(parameterName); 057 if (p == null) { 058 this.parameter = 059 validator.createOrLookupParam( 060 true, 061 parameter.getName(), 062 parameter.getType(), 063 parameter.getDefaultExp(), 064 parameter.getDescription()); 065 } else { 066 this.parameter = p; 067 } 068 return this; 069 } 070 071 public Calc accept(ExpCompiler compiler) { 072 return ((ParameterCompilable) parameter).compile(compiler); 073 } 074 075 public Object accept(MdxVisitor visitor) { 076 return visitor.visit(this); 077 } 078 079 public ParameterExpr clone() { 080 return new ParameterExpr(parameter); 081 } 082 083 /** 084 * Unparses the definition of this Parameter. 085 * 086 * <p>The first usage of a parameter in a query becomes a call to the 087 * <code>Parameter(paramName, description, defaultValue)</code> 088 * function, and subsequent usages become calls to 089 * <code>ParamRef(paramName)</code> 090 * 091 * @param pw PrintWriter 092 */ 093 public void unparse(PrintWriter pw) { 094 // Is this the first time we've seen a statement parameter? If so, 095 // we will generate a call to the Parameter() function, to define 096 // the parameter. 097 final boolean def; 098 if (pw instanceof QueryPrintWriter 099 && parameter.getScope() == Parameter.Scope.Statement) 100 { 101 def = ((QueryPrintWriter) pw).parameters.add(parameter); 102 } else { 103 def = false; 104 } 105 final String name = parameter.getName(); 106 final Type type = parameter.getType(); 107 final int category = TypeUtil.typeToCategory(type); 108 if (def) { 109 pw.print("Parameter(" + Util.quoteForMdx(name) + ", "); 110 switch (category) { 111 case Category.String: 112 case Category.Numeric: 113 pw.print(Category.instance.getName(category).toUpperCase()); 114 break; 115 case Category.Member: 116 pw.print(uniqueName(type)); 117 break; 118 case Category.Set: 119 Type elementType = ((SetType) type).getElementType(); 120 pw.print(uniqueName(elementType)); 121 break; 122 default: 123 throw Category.instance.badValue(category); 124 } 125 pw.print(", "); 126 final Object value = parameter.getValue(); 127 if (value == null) { 128 parameter.getDefaultExp().unparse(pw); 129 } else if (value instanceof String) { 130 String s = (String) value; 131 pw.print(Util.quoteForMdx(s)); 132 } else if (value instanceof List) { 133 List list = (List) value; 134 pw.print("{"); 135 int i = -1; 136 for (Object o : list) { 137 ++i; 138 if (i > 0) { 139 pw.print(", "); 140 } 141 pw.print(o); 142 } 143 pw.print("}"); 144 } else { 145 pw.print(value); 146 } 147 final String description = parameter.getDescription(); 148 if (description != null) { 149 pw.print(", " + Util.quoteForMdx(description)); 150 } 151 pw.print(")"); 152 } else { 153 pw.print("ParamRef(" + Util.quoteForMdx(name) + ")"); 154 } 155 } 156 157 /** 158 * Returns the unique name of the level, hierarchy, or dimension of this 159 * type, whichever is most specific. 160 * 161 * @param type Type 162 * @return Most specific description of type 163 */ 164 private String uniqueName(Type type) { 165 if (type.getLevel() != null) { 166 return type.getLevel().getUniqueName(); 167 } else if (type.getHierarchy() != null) { 168 return type.getHierarchy().getUniqueName(); 169 } else { 170 return type.getDimension().getUniqueName(); 171 } 172 } 173 174 // For the purposes of type inference and expression substitution, a 175 // parameter is atomic; therefore, we ignore the child member, if any. 176 public Object[] getChildren() { 177 return null; 178 } 179 180 /** 181 * Returns whether this parameter is equal to another, based upon name, 182 * type and value 183 */ 184 public boolean equals(Object other) { 185 if (!(other instanceof ParameterExpr)) { 186 return false; 187 } 188 ParameterExpr that = (ParameterExpr) other; 189 return this.parameter == that.parameter; 190 } 191 192 public int hashCode() { 193 return parameter.hashCode(); 194 } 195 196 /** 197 * Returns whether the parameter can be modified. 198 * 199 * @return whether parameter can be modified 200 */ 201 public boolean isModifiable() { 202 return true; 203 } 204 205 /** 206 * Returns the parameter used by this expression. 207 * 208 * @return parameter used by this expression 209 */ 210 public Parameter getParameter() { 211 return parameter; 212 } 213} 214 215// End ParameterExpr.java