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) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2009 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap.fun; 012 013import mondrian.calc.Calc; 014import mondrian.calc.ExpCompiler; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.*; 017import mondrian.olap.type.*; 018import mondrian.olap.type.DimensionType; 019import mondrian.olap.type.LevelType; 020 021import java.io.PrintWriter; 022 023/** 024 * <code>FunDefBase</code> is the default implementation of {@link FunDef}. 025 * 026 * <h3>Signatures</h3> 027 * 028 * <p>A function is defined by the following:</p> 029 * 030 * <table border="1"> 031 * <tr><th>Parameter</th><th>Meaning</th><th>Example</th></tr> 032 * <tr> 033 * <td>name</td><td>Name of the function</td><td>"Members"</td> 034 * </tr> 035 * <tr> 036 * <td>signature</td> 037 * <td>Signature of the function</td> 038 * <td>"<Dimension>.Members"</td> 039 * </tr> 040 * <tr> 041 * <td>description</td> 042 * <td>Description of the function</td> 043 * <td>"Returns the set of all members in a dimension."</td> 044 * </tr> 045 * <tr> 046 * <td>flags</td> 047 * <td>Encoding of the syntactic type, return type, and parameter 048 * types of this operator. The encoding is described below.</td> 049 * <td>"pxd"</tr> 050 * </table> 051 * 052 * The <code>flags</code> field is an string which encodes 053 * the syntactic type, return type, and parameter types of this operator. 054 * <ul> 055 * <li>The first character determines the syntactic type, as described by 056 * {@link FunUtil#decodeSyntacticType(String)}. 057 * <li>The second character determines the return type, as described by 058 * {@link FunUtil#decodeReturnCategory(String)}. 059 * <li>The third and subsequence characters determine the types of the 060 * arguments arguments, as described by 061 * {@link FunUtil#decodeParameterCategories(String)}. 062 * </ul><p/> 063 * 064 * For example, <code>"pxd"</code> means "an operator with 065 * {@link Syntax#Property property} syntax (p) which returns a set 066 * (x) and takes a dimension (d) as its argument".<p/> 067 * 068 * The arguments are always read from left to right, regardless of the 069 * syntactic type of the operator. For example, the 070 * <code>"<Set>.Item(<Index>)"</code> operator 071 * (signature <code>"mmxn"</code>) has the 072 * syntax of a method-call, and takes two parameters: 073 * a set (x) and a numeric (n).<p/> 074 * 075 * @author jhyde 076 * @since 26 February, 2002 077 */ 078public abstract class FunDefBase extends FunUtil implements FunDef { 079 protected final int flags; 080 private final String name; 081 final String signature; 082 private final String description; 083 protected final int returnCategory; 084 protected final int[] parameterCategories; 085 086 /** 087 * Creates an operator. 088 * 089 * @param name Name of the function, for example "Members". 090 * @param signature Signature of the function, for example 091 * "<Dimension>.Members". 092 * @param description Description of the function, for example 093 * "Returns the set of all members in a dimension." 094 * @param syntax Syntactic type of the operator (for 095 * example, function, method, infix operator) 096 * @param returnCategory The {@link Category} of the value returned by this 097 * operator. 098 * @param parameterCategories An array of {@link Category} codes, one for 099 * each parameter. 100 */ 101 FunDefBase( 102 String name, 103 String signature, 104 String description, 105 Syntax syntax, 106 int returnCategory, 107 int[] parameterCategories) 108 { 109 assert name != null; 110 assert syntax != null; 111 this.name = name; 112 this.signature = signature; 113 this.description = description; 114 this.flags = syntax.ordinal(); 115 this.returnCategory = returnCategory; 116 this.parameterCategories = parameterCategories; 117 } 118 119 /** 120 * Creates an operator. 121 * 122 * @param name Name of the function, for example "Members". 123 * @param description Description of the function, for example 124 * "Returns the set of all members in a dimension." 125 * @param flags Encoding of the syntactic type, return type, 126 * and parameter types of this operator. The 127 * "Members" operator has a syntactic type 128 * "pxd" which means "an operator with 129 * {@link Syntax#Property property} syntax (p) which 130 * returns a set (x) and takes a dimension (d) as its 131 * argument". 132 * See {@link FunUtil#decodeSyntacticType(String)}, 133 * {@link FunUtil#decodeReturnCategory(String)}, 134 * {@link FunUtil#decodeParameterCategories(String)}. 135 */ 136 protected FunDefBase( 137 String name, 138 String description, 139 String flags) 140 { 141 this( 142 name, 143 null, 144 description, 145 decodeSyntacticType(flags), 146 decodeReturnCategory(flags), 147 decodeParameterCategories(flags)); 148 } 149 150 /** 151 * Creates an operator with an explicit signature. 152 * 153 * <p>In most cases, the signature can be generated automatically, and 154 * you should use the constructor which creates an implicit signature, 155 * {@link #FunDefBase(String, String, String, String)} 156 * instead. 157 * 158 * @param name Name of the function, for example "Members". 159 * @param signature Signature of the function, for example 160 * "<Dimension>.Members". 161 * @param description Description of the function, for example 162 * "Returns the set of all members in a dimension." 163 * @param flags Encoding of the syntactic type, return type, and 164 * parameter types of this operator. The "Members" 165 * operator has a syntactic type "pxd" which means "an 166 * operator with {@link Syntax#Property property} syntax 167 * (p) which returns a set (x) and takes a dimension (d) 168 * as its argument". See 169 * {@link FunUtil#decodeSyntacticType(String)}, 170 * {@link FunUtil#decodeReturnCategory(String)}, 171 * {@link FunUtil#decodeParameterCategories(String)}. 172 */ 173 protected FunDefBase( 174 String name, 175 String signature, 176 String description, 177 String flags) 178 { 179 this( 180 name, 181 signature, 182 description, 183 decodeSyntacticType(flags), 184 decodeReturnCategory(flags), 185 decodeParameterCategories(flags)); 186 } 187 188 /** 189 * Convenience constructor when we are created by a {@link Resolver}. 190 * 191 * @param resolver Resolver 192 * @param returnType Return type 193 * @param parameterTypes Parameter types 194 */ 195 FunDefBase(Resolver resolver, int returnType, int[] parameterTypes) { 196 this( 197 resolver.getName(), 198 null, 199 null, 200 resolver.getSyntax(), 201 returnType, 202 parameterTypes); 203 } 204 205 /** 206 * Copy constructor. 207 * 208 * @param funDef Function definition to copy 209 */ 210 FunDefBase(FunDef funDef) { 211 this( 212 funDef.getName(), funDef.getSignature(), 213 funDef.getDescription(), funDef.getSyntax(), 214 funDef.getReturnCategory(), funDef.getParameterCategories()); 215 } 216 217 public String getName() { 218 return name; 219 } 220 221 public String getDescription() { 222 return description; 223 } 224 225 public Syntax getSyntax() { 226 return Syntax.class.getEnumConstants()[flags]; 227 } 228 229 public int getReturnCategory() { 230 return returnCategory; 231 } 232 233 public int[] getParameterCategories() { 234 return parameterCategories; 235 } 236 237 public Exp createCall(Validator validator, Exp[] args) { 238 int[] categories = getParameterCategories(); 239 Util.assertTrue(categories.length == args.length); 240 for (int i = 0; i < args.length; i++) { 241 args[i] = validateArg(validator, args, i, categories[i]); 242 } 243 final Type type = getResultType(validator, args); 244 if (type == null) { 245 throw Util.newInternal("could not derive type"); 246 } 247 return new ResolvedFunCall(this, args, type); 248 } 249 250 /** 251 * Validates an argument to a call to this function. 252 * 253 * <p>The default implementation of this method adds an implicit 254 * conversion to the correct type. Derived classes may override. 255 * 256 * @param validator Validator 257 * @param args Arguments to this function 258 * @param i Ordinal of argument 259 * @param category Expected {@link Category category} of argument 260 * @return Validated argument 261 */ 262 protected Exp validateArg( 263 Validator validator, 264 Exp[] args, 265 int i, 266 int category) 267 { 268 return args[i]; 269 } 270 271 /** 272 * Converts a type to a different category, maintaining as much type 273 * information as possible. 274 * 275 * For example, given <code>LevelType(dimension=Time, hierarchy=unknown, 276 * level=unkown)</code> and category=Hierarchy, returns 277 * <code>HierarchyType(dimension=Time)</code>. 278 * 279 * @param type Type 280 * @param category Desired category 281 * @return Type after conversion to desired category 282 */ 283 static Type castType(Type type, int category) { 284 switch (category) { 285 case Category.Logical: 286 return new BooleanType(); 287 case Category.Numeric: 288 return new NumericType(); 289 case Category.Numeric | Category.Integer: 290 return new DecimalType(Integer.MAX_VALUE, 0); 291 case Category.String: 292 return new StringType(); 293 case Category.DateTime: 294 return new DateTimeType(); 295 case Category.Symbol: 296 return new SymbolType(); 297 case Category.Value: 298 return new ScalarType(); 299 case Category.Cube: 300 if (type instanceof Cube) { 301 return new CubeType((Cube) type); 302 } 303 return null; 304 case Category.Dimension: 305 if (type != null) { 306 return DimensionType.forType(type); 307 } 308 return null; 309 case Category.Hierarchy: 310 if (type != null) { 311 return HierarchyType.forType(type); 312 } 313 return null; 314 case Category.Level: 315 if (type != null) { 316 return LevelType.forType(type); 317 } 318 return null; 319 case Category.Member: 320 if (type != null) { 321 final MemberType memberType = TypeUtil.toMemberType(type); 322 if (memberType != null) { 323 return memberType; 324 } 325 } 326 // Take a wild guess. 327 return MemberType.Unknown; 328 case Category.Tuple: 329 if (type != null) { 330 final Type memberType = TypeUtil.toMemberOrTupleType(type); 331 if (memberType != null) { 332 return memberType; 333 } 334 } 335 return null; 336 case Category.Set: 337 if (type != null) { 338 final Type memberType = TypeUtil.toMemberOrTupleType(type); 339 if (memberType != null) { 340 return new SetType(memberType); 341 } 342 } 343 return null; 344 case Category.Empty: 345 return new EmptyType(); 346 default: 347 throw Category.instance.badValue(category); 348 } 349 } 350 351 /** 352 * Returns the type of a call to this function with a given set of 353 * arguments.<p/> 354 * 355 * The default implementation makes the coarse assumption that the return 356 * type is in some way related to the type of the first argument. 357 * Operators whose arguments don't follow the requirements of this 358 * implementation should override this method.<p/> 359 * 360 * If the function definition says it returns a literal type (numeric, 361 * string, symbol) then it's a fair guess that the function call 362 * returns the same kind of value.<p/> 363 * 364 * If the function definition says it returns an object type (cube, 365 * dimension, hierarchy, level, member) then we check the first 366 * argument of the function. Suppose that the function definition says 367 * that it returns a hierarchy, and the first argument of the function 368 * happens to be a member. Then it's reasonable to assume that this 369 * function returns a member. 370 * 371 * @param validator Validator 372 * @param args Arguments to the call to this operator 373 * @return result type of a call this function 374 */ 375 public Type getResultType(Validator validator, Exp[] args) { 376 Type firstArgType = 377 args.length > 0 378 ? args[0].getType() 379 : null; 380 Type type = castType(firstArgType, getReturnCategory()); 381 if (type != null) { 382 return type; 383 } 384 throw Util.newInternal( 385 "Cannot deduce type of call to function '" + this.name + "'"); 386 } 387 388 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 389 throw Util.newInternal( 390 "function '" + getSignature() 391 + "' has not been implemented"); 392 } 393 394 public String getSignature() { 395 return getSyntax().getSignature( 396 getName(), 397 getReturnCategory(), 398 getParameterCategories()); 399 } 400 401 public void unparse(Exp[] args, PrintWriter pw) { 402 getSyntax().unparse(getName(), args, pw); 403 } 404} 405 406// End FunDefBase.java