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) 2010-2012 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap4j; 011 012import mondrian.olap.*; 013import mondrian.olap.Property; 014import mondrian.olap.fun.FunInfo; 015import mondrian.rolap.*; 016import mondrian.xmla.RowsetDefinition; 017import mondrian.xmla.XmlaHandler; 018 019import org.olap4j.*; 020import org.olap4j.Cell; 021import org.olap4j.metadata.*; 022import org.olap4j.metadata.Cube; 023import org.olap4j.metadata.Hierarchy; 024import org.olap4j.metadata.Level; 025import org.olap4j.metadata.Member; 026import org.olap4j.metadata.Schema; 027 028import java.sql.ResultSet; 029import java.sql.SQLException; 030import java.util.*; 031 032/** 033 * Provides access to internals of mondrian's olap4j driver that are not part 034 * of the olap4j API. 035 * 036 * @author jhyde 037 * @since Nov 12, 2010 038 */ 039class MondrianOlap4jExtra implements XmlaHandler.XmlaExtra { 040 static final MondrianOlap4jExtra INSTANCE = new MondrianOlap4jExtra(); 041 042 public ResultSet executeDrillthrough( 043 OlapStatement olapStatement, 044 String mdx, 045 boolean advanced, 046 String tabFields, 047 int[] rowCountSlot) throws SQLException 048 { 049 return ((MondrianOlap4jStatement) olapStatement).executeQuery2( 050 mdx, 051 advanced, 052 tabFields, 053 rowCountSlot); 054 } 055 056 public void setPreferList(OlapConnection connection) { 057 ((MondrianOlap4jConnection) connection).setPreferList(true); 058 } 059 060 public Date getSchemaLoadDate(Schema schema) { 061 return ((MondrianOlap4jSchema) schema).schema.getSchemaLoadDate(); 062 } 063 064 public int getLevelCardinality(Level level) throws OlapException { 065 if (level instanceof MondrianOlap4jLevel) { 066 // Improved implementation if the provider is mondrian. 067 final MondrianOlap4jLevel olap4jLevel = (MondrianOlap4jLevel) level; 068 final mondrian.olap.SchemaReader schemaReader = 069 olap4jLevel.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData 070 .olap4jConnection.getMondrianConnection().getSchemaReader() 071 .withLocus(); 072 return schemaReader.getLevelCardinality( 073 olap4jLevel.level, true, true); 074 } else { 075 return level.getCardinality(); 076 } 077 } 078 079 public void getSchemaFunctionList( 080 List<FunctionDefinition> funDefs, 081 Schema schema, 082 Util.Functor1<Boolean, String> functionFilter) 083 { 084 final FunTable funTable = 085 ((MondrianOlap4jSchema) schema).schema.getFunTable(); 086 StringBuilder buf = new StringBuilder(50); 087 for (FunInfo fi : funTable.getFunInfoList()) { 088 switch (fi.getSyntax()) { 089 case Empty: 090 case Internal: 091 case Parentheses: 092 continue; 093 } 094 final Boolean passes = functionFilter.apply(fi.getName()); 095 if (passes == null || !passes) { 096 continue; 097 } 098 099 int[][] paramCategories = fi.getParameterCategories(); 100 int[] returnCategories = fi.getReturnCategories(); 101 102 // Convert Windows newlines in 'description' to UNIX format. 103 String description = fi.getDescription(); 104 if (description != null) { 105 description = Util.replace( 106 fi.getDescription(), 107 "\r", 108 ""); 109 } 110 if ((paramCategories == null) 111 || (paramCategories.length == 0)) 112 { 113 funDefs.add( 114 new FunctionDefinition( 115 fi.getName(), 116 description, 117 "(none)", 118 1, 119 1, 120 // TODO WHAT VALUE should this have 121 "", 122 fi.getName())); 123 } else { 124 for (int i = 0; i < paramCategories.length; i++) { 125 int[] pc = paramCategories[i]; 126 int returnCategory = returnCategories[i]; 127 128 buf.setLength(0); 129 for (int j = 0; j < pc.length; j++) { 130 int v = pc[j]; 131 if (j > 0) { 132 buf.append(", "); 133 } 134 buf.append( 135 Category.instance.getDescription( 136 v & Category.Mask)); 137 } 138 139 RowsetDefinition.MdschemaFunctionsRowset.VarType varType = 140 RowsetDefinition.MdschemaFunctionsRowset.VarType 141 .forCategory(returnCategory); 142 funDefs.add( 143 new FunctionDefinition( 144 fi.getName(), 145 description, 146 buf.toString(), 147 //TODO: currently FunInfo can not tell us which 148 // functions are MDX and which are UDFs. 149 varType.ordinal(), 150 1, 151 // TODO: Name of the interface for UDF and Group 152 // name for the MDX functions. 153 // TODO WHAT VALUE should this have 154 "", 155 fi.getName())); 156 } 157 } 158 } 159 } 160 161 public int getHierarchyCardinality(Hierarchy hierarchy) 162 throws OlapException 163 { 164 final MondrianOlap4jHierarchy olap4jHierarchy = 165 (MondrianOlap4jHierarchy) hierarchy; 166 final mondrian.olap.SchemaReader schemaReader = 167 olap4jHierarchy.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData 168 .olap4jConnection.getMondrianConnection().getSchemaReader() 169 .withLocus(); 170 return RolapMemberBase.getHierarchyCardinality( 171 schemaReader, olap4jHierarchy.hierarchy); 172 } 173 174 public int getHierarchyStructure(Hierarchy hierarchy) { 175 final MondrianOlap4jHierarchy olap4jHierarchy = 176 (MondrianOlap4jHierarchy) hierarchy; 177 return ((HierarchyBase) olap4jHierarchy.hierarchy).isRagged() ? 1 : 0; 178 } 179 180 public boolean isHierarchyParentChild(Hierarchy hierarchy) { 181 Level nonAllFirstLevel = hierarchy.getLevels().get(0); 182 if (nonAllFirstLevel.getLevelType() == Level.Type.ALL) { 183 nonAllFirstLevel = hierarchy.getLevels().get(1); 184 } 185 MondrianOlap4jLevel olap4jLevel = 186 (MondrianOlap4jLevel) nonAllFirstLevel; 187 return ((RolapLevel) olap4jLevel.level).isParentChild(); 188 } 189 190 public int getMeasureAggregator(Member member) { 191 MondrianOlap4jMeasure olap4jMeasure = 192 (MondrianOlap4jMeasure) member; 193 Object aggProp = 194 olap4jMeasure.member.getPropertyValue( 195 Property.AGGREGATION_TYPE.name); 196 if (aggProp == null) { 197 return 198 RowsetDefinition.MdschemaMeasuresRowset 199 .MDMEASURE_AGGR_CALCULATED; 200 } 201 RolapAggregator agg = (RolapAggregator) aggProp; 202 if (agg == RolapAggregator.Sum) { 203 return RowsetDefinition.MdschemaMeasuresRowset.MDMEASURE_AGGR_SUM; 204 } else if (agg == RolapAggregator.Count) { 205 return RowsetDefinition.MdschemaMeasuresRowset.MDMEASURE_AGGR_COUNT; 206 } else if (agg == RolapAggregator.Min) { 207 return RowsetDefinition.MdschemaMeasuresRowset.MDMEASURE_AGGR_MIN; 208 } else if (agg == RolapAggregator.Max) { 209 return RowsetDefinition.MdschemaMeasuresRowset.MDMEASURE_AGGR_MAX; 210 } else if (agg == RolapAggregator.Avg) { 211 return RowsetDefinition.MdschemaMeasuresRowset.MDMEASURE_AGGR_AVG; 212 } else { 213 //TODO: what are VAR and STD 214 return RowsetDefinition.MdschemaMeasuresRowset 215 .MDMEASURE_AGGR_UNKNOWN; 216 } 217 } 218 219 public void checkMemberOrdinal(Member member) throws OlapException { 220 if (member.getOrdinal() == -1) { 221 MondrianOlap4jMember olap4jMember = 222 (MondrianOlap4jMember) member; 223 final mondrian.olap.SchemaReader schemaReader = 224 olap4jMember.olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData 225 .olap4jConnection.getMondrianConnection().getSchemaReader() 226 .withLocus(); 227 RolapMemberBase.setOrdinals(schemaReader, olap4jMember.member); 228 } 229 } 230 231 public boolean shouldReturnCellProperty( 232 CellSet cellSet, 233 org.olap4j.metadata.Property cellProperty, 234 boolean evenEmpty) 235 { 236 MondrianOlap4jCellSet olap4jCellSet = (MondrianOlap4jCellSet) cellSet; 237 Query query = olap4jCellSet.query; 238 return 239 (evenEmpty 240 && query.isCellPropertyEmpty()) 241 || query.hasCellProperty(cellProperty.getName()); 242 } 243 244 public List<String> getSchemaRoleNames(Schema schema) { 245 MondrianOlap4jSchema olap4jSchema = (MondrianOlap4jSchema) schema; 246 // TODO: this returns ALL roles, no the current user's roles 247 return new ArrayList<String>( 248 ((RolapSchema) olap4jSchema.schema).roleNames()); 249 } 250 251 public String getSchemaId(Schema schema) { 252 return ((MondrianOlap4jSchema)schema).schema.getId(); 253 } 254 255 public String getCubeType(Cube cube) { 256 return 257 (cube instanceof MondrianOlap4jCube) 258 && ((RolapCube) ((MondrianOlap4jCube) cube).cube).isVirtual() 259 ? RowsetDefinition.MdschemaCubesRowset.MD_CUBTYPE_VIRTUAL_CUBE 260 : RowsetDefinition.MdschemaCubesRowset.MD_CUBTYPE_CUBE; 261 } 262 263 public boolean isLevelUnique(Level level) { 264 MondrianOlap4jLevel olap4jLevel = (MondrianOlap4jLevel) level; 265 return (olap4jLevel.level instanceof RolapLevel) 266 && ((RolapLevel) olap4jLevel.level).isUnique(); 267 } 268 269 public List<org.olap4j.metadata.Property> getLevelProperties(Level level) { 270 MondrianOlap4jLevel olap4jLevel = (MondrianOlap4jLevel) level; 271 return olap4jLevel.getProperties(false); 272 } 273 274 public boolean isPropertyInternal(org.olap4j.metadata.Property property) { 275 MondrianOlap4jProperty olap4jProperty = 276 (MondrianOlap4jProperty) property; 277 return olap4jProperty.property.isInternal(); 278 } 279 280 public List<Map<String, Object>> getDataSources(OlapConnection connection) 281 throws OlapException 282 { 283 MondrianOlap4jConnection olap4jConnection = 284 (MondrianOlap4jConnection) connection; 285 MondrianServer server = 286 MondrianServer.forConnection( 287 olap4jConnection.getMondrianConnection()); 288 return server.getDatabases(olap4jConnection.getMondrianConnection()); 289 } 290 291 public Map<String, Object> getAnnotationMap(MetadataElement element) 292 throws SQLException 293 { 294 if (element instanceof OlapWrapper) { 295 OlapWrapper wrapper = (OlapWrapper) element; 296 if (wrapper.isWrapperFor(Annotated.class)) { 297 final Annotated annotated = wrapper.unwrap(Annotated.class); 298 final Map<String, Object> map = new HashMap<String, Object>(); 299 for (Map.Entry<String, Annotation> entry 300 : annotated.getAnnotationMap().entrySet()) 301 { 302 map.put(entry.getKey(), entry.getValue().getValue()); 303 } 304 return map; 305 } 306 } 307 return Collections.emptyMap(); 308 } 309 310 public boolean canDrillThrough(Cell cell) { 311 return ((MondrianOlap4jCell)cell).cell.canDrillThrough(); 312 } 313 314 public int getDrillThroughCount(Cell cell) { 315 return ((MondrianOlap4jCell)cell).cell.getDrillThroughCount(); 316 } 317 318 public void flushSchemaCache(OlapConnection conn) throws OlapException { 319 try { 320 conn.unwrap(RolapConnection.class) 321 .getCacheControl(null).flushSchemaCache(); 322 } catch (SQLException e) { 323 throw new OlapException(e); 324 } 325 } 326 327 public Object getMemberKey(Member m) throws OlapException { 328 try { 329 return ((MondrianOlap4jMember)m) 330 .unwrap(RolapMemberBase.class).getKey(); 331 } catch (SQLException e) { 332 throw new OlapException(e); 333 } 334 } 335 336 public Object getOrderKey(Member m) throws OlapException { 337 try { 338 return ((MondrianOlap4jMember)m) 339 .unwrap(RolapMemberBase.class).getOrderKey(); 340 } catch (SQLException e) { 341 throw new OlapException(e); 342 } 343 } 344} 345 346// End MondrianOlap4jExtra.java