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) 2003-2005 Julian Hyde
008// Copyright (C) 2005-2012 Pentaho
009// All Rights Reserved.
010*/
011package mondrian.olap;
012
013import mondrian.calc.Calc;
014import mondrian.rolap.RolapHierarchy;
015import mondrian.rolap.RolapSchema;
016
017import java.util.List;
018import java.util.Map;
019
020import javax.sql.DataSource;
021
022/**
023 * A <code>SchemaReader</code> queries schema objects ({@link Schema},
024 * {@link Cube}, {@link Dimension}, {@link Hierarchy}, {@link Level},
025 * {@link Member}).
026 *
027 * <p>It is generally created using {@link Connection#getSchemaReader},
028 * but also via {@link Cube#getSchemaReader(Role)}.</p>
029 *
030 * <p>SchemaReader is deprecated for code outside of mondrian. For new code,
031 * use the metadata provided by olap4j, for example
032 * {@link mondrian.olap4j.MondrianOlap4jSchema#getCubes()}.
033 *
034 * <p>If you use a SchemaReader from outside of a mondrian statement, you may
035 * get a {@link java.util.EmptyStackException} indicating that mondrian cannot
036 * deduce the current locus (statement context). If you get that error, call
037 * {@link #withLocus()} to create a SchemaReader that automatically provides a
038 * locus whenever a call is made.</p>
039 *
040 * @author jhyde
041 * @since Feb 24, 2003
042 */
043public interface SchemaReader {
044    /**
045     * Returns the schema.
046     *
047     * @return Schema, never null
048     */
049    RolapSchema getSchema();
050
051    /**
052     * Returns the access-control profile that this <code>SchemaReader</code>
053     * is implementing.
054     */
055    Role getRole();
056
057    /**
058     * Returns the accessible dimensions of a cube.
059     *
060     * @pre dimension != null
061     * @post return != null
062     */
063    List<Dimension> getCubeDimensions(Cube cube);
064
065    /**
066     * Returns the accessible hierarchies of a dimension.
067     *
068     * @pre dimension != null
069     * @post return != null
070     */
071    List<Hierarchy> getDimensionHierarchies(Dimension dimension);
072
073    /**
074     * Returns an array of the root members of <code>hierarchy</code>.
075     *
076     * @param hierarchy Hierarchy
077     * @see #getCalculatedMembers(Hierarchy)
078     */
079    List<Member> getHierarchyRootMembers(Hierarchy hierarchy);
080
081    /**
082     * Returns number of children parent of a member,
083     * if the information can be retrieved from cache, otherwise -1.
084     */
085    int getChildrenCountFromCache(Member member);
086
087    /**
088     * Returns the number of members in a level, returning an approximation if
089     * acceptable.
090     *
091     * @param level Level
092     * @param approximate Whether an approximation is acceptable
093     * @param materialize Whether to go to disk if no approximation
094     *   for the count is available and the members are not in
095     *   cache. If false, returns {@link Integer#MIN_VALUE} if value
096     *   is not in cache.
097     */
098    int getLevelCardinality(
099        Level level, boolean approximate, boolean materialize);
100
101    /**
102     * Substitutes a member with an equivalent member which enforces the
103     * access control policy of this SchemaReader.
104     */
105    Member substitute(Member member);
106
107    /**
108     * Returns direct children of <code>member</code>.
109     * @pre member != null
110     * @post return != null
111     */
112    List<Member> getMemberChildren(Member member);
113
114    /**
115     * Returns direct children of <code>member</code>, optimized
116     * for NON EMPTY.
117     * <p>
118     * If <code>context == null</code> then
119     * there is no context and all members are returned - then
120     * its identical to {@link #getMemberChildren(Member)}.
121     * If <code>context</code> is not null, the resulting members
122     * <em>may</em> be restricted to those members that have a
123     * non empty row in the fact table for <code>context</code>.
124     * Wether or not optimization is possible depends
125     * on the SchemaReader implementation.
126     */
127    List<Member> getMemberChildren(Member member, Evaluator context);
128
129    /**
130     * Returns direct children of each element of <code>members</code>.
131     *
132     * @param members Array of members
133     * @return array of child members
134     *
135     * @pre members != null
136     * @post return != null
137     */
138    List<Member> getMemberChildren(List<Member> members);
139
140    /**
141     * Returns direct children of each element of <code>members</code>
142     * which is not empty in <code>context</code>.
143     *
144     * @param members Array of members
145     * @param context Evaluation context
146     * @return array of child members
147     *
148     * @pre members != null
149     * @post return != null
150     */
151    List<Member> getMemberChildren(List<Member> members, Evaluator context);
152
153    /**
154     * Returns a list of contributing children of a member of a parent-child
155     * hierarchy.
156     *
157     * @param dataMember Data member for a member of the parent-child hierarcy
158     * @param hierarchy Hierarchy
159     * @param list List of members to populate
160     */
161    void getParentChildContributingChildren(
162        Member dataMember,
163        Hierarchy hierarchy,
164        List<Member> list);
165
166    /**
167     * Returns the parent of <code>member</code>.
168     *
169     * @param member Member
170     * @pre member != null
171     * @return null if member is a root member
172     */
173    Member getMemberParent(Member member);
174
175    /**
176     * Returns a list of ancestors of <code>member</code>, in depth order.
177     *
178     * <p>For example, for [Store].[USA].[CA], returns
179     * {[Store].[USA], [Store].[All Stores]}.
180     *
181     * @param member Member
182     * @param ancestorList List of ancestors
183     */
184    void getMemberAncestors(Member member, List<Member> ancestorList);
185
186    /**
187     * Returns the depth of a member.
188     *
189     * <p>This may not be the same as
190     * <code>member.{@link Member#getLevel getLevel}().
191     * {@link Level#getDepth getDepth}()</code>
192     * for three reasons:<ol>
193     * <li><b>Access control</b>. The most senior <em>visible</em> member has
194     *   level 0. If the client is not allowed to see the "All" and "Nation"
195     *   levels of the "Store" hierarchy, then members of the "State" level will
196     *   have depth 0.</li>
197     * <li><b>Parent-child hierarchies</b>. Suppose Fred reports to Wilma, and
198     *   Wilma reports to no one. "All Employees" has depth 0, Wilma has depth
199     *   1, and Fred has depth 2. Fred and Wilma are both in the "Employees"
200     *   level, which has depth 1.</li>
201     * <li><b>Ragged hierarchies</b>. If Israel has only one, hidden, province
202     * then the depth of Tel Aviv, Israel is 2, whereas the depth of another
203     * city, San Francisco, CA, USA is 3.</li>
204     * </ol>
205     */
206    int getMemberDepth(Member member);
207
208    /**
209     * Finds a member based upon its unique name.
210     *
211     * @param uniqueNameParts Unique name of member
212     * @param failIfNotFound Whether to throw an error, as opposed to returning
213     *   <code>null</code>, if there is no such member.
214     * @param matchType indicates the match mode; if not specified, EXACT
215     * @return The member, or null if not found
216     */
217    Member getMemberByUniqueName(
218        List<Id.Segment> uniqueNameParts,
219        boolean failIfNotFound,
220        MatchType matchType);
221
222    /**
223     * Finds a member based upon its unique name, requiring an exact match.
224     *
225     * <p>This method is equivalent to calling
226     * {@link #getMemberByUniqueName(java.util.List, boolean, MatchType)}
227     * with {@link MatchType#EXACT}.
228     *
229     * @param uniqueNameParts Unique name of member
230     * @param failIfNotFound Whether to throw an error, as opposed to returning
231     *   <code>null</code>, if there is no such member.
232     * @return The member, or null if not found
233     */
234    Member getMemberByUniqueName(
235        List<Id.Segment> uniqueNameParts,
236        boolean failIfNotFound);
237
238    /**
239     * Looks up an MDX object by name, specifying how to
240     * match if no object exactly matches the name.
241     *
242     * <p>Resolves a name such as
243     * '[Products]&#46;[Product Department]&#46;[Produce]' by resolving the
244     * components ('Products', and so forth) one at a time.
245     *
246     * @param parent Parent element to search in
247     * @param names Exploded compound name, such as {"Products",
248     *     "Product Department", "Produce"}
249     * @param failIfNotFound If the element is not found, determines whether
250     *      to return null or throw an error
251     * @param category Type of returned element, a {@link Category} value;
252     *      {@link Category#Unknown} if it doesn't matter.
253     * @param matchType indicates the match mode; if not specified, EXACT
254     *
255     * @pre parent != null
256     * @post !(failIfNotFound && return == null)
257     */
258    OlapElement lookupCompound(
259        OlapElement parent,
260        List<Id.Segment> names,
261        boolean failIfNotFound,
262        int category,
263        MatchType matchType);
264
265    /**
266     * Looks up an MDX object by name.
267     *
268     * <p>Resolves a name such as
269     * '[Products]&#46;[Product Department]&#46;[Produce]' by resolving the
270     * components ('Products', and so forth) one at a time.
271     *
272     * @param parent Parent element to search in
273     * @param names Exploded compound name, such as {"Products",
274     *     "Product Department", "Produce"}
275     * @param failIfNotFound If the element is not found, determines whether
276     *      to return null or throw an error
277     * @param category Type of returned element, a {@link Category} value;
278     *      {@link Category#Unknown} if it doesn't matter.
279     *
280     * @pre parent != null
281     * @post !(failIfNotFound && return == null)
282     */
283    OlapElement lookupCompound(
284        OlapElement parent,
285        List<Id.Segment> names,
286        boolean failIfNotFound,
287        int category);
288
289    /**
290     * Should only be called by implementations of
291     * {@link #lookupCompound(OlapElement, java.util.List, boolean, int, MatchType)}.
292     *
293     * @param parent Parent element to search in
294     * @param names Exploded compound name, such as {"Products",
295     *     "Product Department", "Produce"}
296     * @param failIfNotFound If the element is not found, determines whether
297     *      to return null or throw an error
298     * @param category Type of returned element, a {@link Category} value;
299     *      {@link Category#Unknown} if it doesn't matter.
300     * @param matchType indicates the match mode; if not specified, EXACT
301     * @return Found element
302
303    OlapElement lookupCompoundInternal(
304        OlapElement parent,
305        List<Id.Segment> names,
306        boolean failIfNotFound,
307        int category,
308        MatchType matchType);
309    */
310
311    /**
312     * Looks up a calculated member by name. If the name is not found in the
313     * current scope, returns null.
314     */
315    Member getCalculatedMember(List<Id.Segment> nameParts);
316
317    /**
318     * Looks up a set by name. If the name is not found in the current scope,
319     * returns null.
320     */
321    NamedSet getNamedSet(List<Id.Segment> nameParts);
322
323    /**
324     * Appends to <code>list</code> all members between <code>startMember</code>
325     * and <code>endMember</code> (inclusive) which belong to
326     * <code>level</code>.
327     */
328    void getMemberRange(
329        Level level, Member startMember, Member endMember, List<Member> list);
330
331    /**
332     * Returns a member <code>n</code> further along in the same level from
333     * <code>member</code>.
334     *
335     * @pre member != null
336     */
337    Member getLeadMember(Member member, int n);
338
339    /**
340     * Compares a pair of {@link Member}s according to their order in a prefix
341     * traversal. (that is, it
342     * is an ancestor or a earlier), is a sibling, or comes later in a prefix
343     * traversal.
344     * @return A negative integer if <code>m1</code> is an ancestor, an earlier
345     *   sibling of an ancestor, or a descendent of an earlier sibling, of
346     *   <code>m2</code>;
347     *   zero if <code>m1</code> is a sibling of <code>m2</code>;
348     *   a positive integer if <code>m1</code> comes later in the prefix
349     *   traversal then <code>m2</code>.
350     */
351    int compareMembersHierarchically(Member m1, Member m2);
352
353    /**
354     * Looks up the child of <code>parent</code> called <code>name</code>, or
355     * an approximation according to <code>matchType</code>, returning
356     * null if no element is found.
357     *
358     * @param parent Parent element to search in
359     * @param name Compound in compound name, such as "[Product]" or "&[1]"
360     * @param matchType Match type
361     *
362     * @return Element with given name, or null
363     */
364    OlapElement getElementChild(
365        OlapElement parent,
366        Id.Segment name,
367        MatchType matchType);
368
369    /**
370     * Looks up the child of <code>parent</code> <code>name</code>, returning
371     * null if no element is found.
372     *
373     * <p>Always equivalent to
374     * <code>getElementChild(parent, name, MatchType.EXACT)</code>.
375     *
376     * @param parent Parent element to search in
377     * @param name Compound in compound name, such as "[Product]" or "&[1]"
378     *
379     * @return Element with given name, or null
380     */
381    OlapElement getElementChild(
382        OlapElement parent,
383        Id.Segment name);
384
385    /**
386     * Returns the members of a level, optionally including calculated members.
387     */
388    List<Member> getLevelMembers(
389        Level level,
390        boolean includeCalculated);
391
392    /**
393     * Returns the members of a level, optionally filtering out members which
394     * are empty.
395     *
396     * @param level Level
397     * @param context Context for filtering
398     * @return Members of this level
399     */
400    List<Member> getLevelMembers(
401        Level level,
402        Evaluator context);
403
404    /**
405     * Returns the accessible levels of a hierarchy.
406     *
407     * @param hierarchy Hierarchy
408     *
409     * @pre hierarchy != null
410     * @post return.length >= 1
411     */
412    List<Level> getHierarchyLevels(Hierarchy hierarchy);
413
414    /**
415     * Returns the default member of a hierarchy. If the default member is in
416     * an inaccessible level, returns the nearest ascendant/descendant member.
417     *
418     * @param hierarchy Hierarchy
419     *
420     * @return Default member of hierarchy
421     */
422    Member getHierarchyDefaultMember(Hierarchy hierarchy);
423
424    /**
425     * Returns whether a member has visible children.
426     */
427    boolean isDrillable(Member member);
428
429    /**
430     * Returns whether a member is visible.
431     */
432    boolean isVisible(Member member);
433
434    /**
435     * Returns the list of accessible cubes.
436     */
437    Cube[] getCubes();
438
439    /**
440     * Returns a list of calculated members in a given hierarchy.
441     */
442    List<Member> getCalculatedMembers(Hierarchy hierarchy);
443
444    /**
445     * Returns a list of calculated members in a given level.
446     */
447    List<Member> getCalculatedMembers(Level level);
448
449    /**
450     * Returns the list of calculated members.
451     */
452    List<Member> getCalculatedMembers();
453
454    /**
455     * Finds a child of a member with a given name.
456     */
457    Member lookupMemberChildByName(
458        Member parent,
459        Id.Segment childName,
460        MatchType matchType);
461
462    /**
463     * Returns an object which can evaluate an expression in native SQL, or
464     * null if this is not possible.
465     *
466     * @param fun Function
467     * @param args Arguments to the function
468     * @param evaluator Evaluator, provides context
469     * @param calc
470     */
471    NativeEvaluator getNativeSetEvaluator(
472        FunDef fun,
473        Exp[] args,
474        Evaluator evaluator,
475        Calc calc);
476
477    /**
478     * Returns the definition of a parameter with a given name, or null if not
479     * found.
480     */
481    Parameter getParameter(String name);
482
483    /**
484     * Returns the data source.
485     *
486     * @return data source
487     */
488    DataSource getDataSource();
489
490    /**
491     * Returns a similar schema reader that has no access control.
492     *
493     * @return Schema reader that has a similar perspective (e.g. cube) but
494     * no access control
495     */
496    SchemaReader withoutAccessControl();
497
498    /**
499     * Returns the default cube in which to look for dimensions etc.
500     *
501     * @return Default cube
502     */
503    Cube getCube();
504
505    /**
506     * Returns a schema reader that automatically assigns a locus to each
507     * operation.
508     *
509     * <p>It is less efficient; use this only if the operation is occurring
510     * outside the context of a statement. If you get the internal error
511     * "no locus", that's a sign you should use this method.</p>
512     *
513     * @return Schema reader that assigns a locus to each operation
514     */
515    SchemaReader withLocus();
516
517    /**
518     * Returns a list of namespaces to search when resolving elements by name.
519     *
520     * <p>For example, a schema reader from the perspective of a cube will
521     * return cube and schema namespaces.</p>
522     *
523     * @return List of namespaces
524     */
525    List<NameResolver.Namespace> getNamespaces();
526
527    /**
528     * Similar to {@link #getMemberChildren(Member, Evaluator)}
529     * but returns a map of the grand-children and their access details
530     * and costs more to invoke because of the access controls.
531     *
532     * Called by {@link RolapHierarchy} when determining the lowest access
533     * level of a Role within a hierarchy.
534     */
535    Map<? extends Member, Access>
536        getMemberChildrenWithDetails(Member member, Evaluator evaluator);
537}
538
539// End SchemaReader.java