<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
<META NAME="GENERATOR" CONTENT="GtkHTML/3.18.3">
</HEAD>
<BODY>
Khanh,<BR>
<BR>
I saw you added a 'MondrianProperties props' member to FunctionTest. The <BR>
<BR>
T save = MondrianProperties.property.get();<BR>
try {<BR>
MondrianProperties.instance().property.set(newValue);<BR>
<< test >><BR>
} finally {<BR>
MondrianProperties.instance().property.set(save);<BR>
}<BR>
<BR>
pattern has become ubiquitous in mondrian tests, so I have introduced mondrian.test.PropertySaver to do deal with it. Just create a PropertySaver as a protected final member variable, set properties via the saver, and make sure your test has a tearDown() method that calls PropertySaver.reset().<BR>
<BR>
See change 11828 <A HREF="http://p4web.eigenbase.org/@md=d&c=6PU@//11768?ac=10">http://p4web.eigenbase.org/@md=d&c=6PU@//11828?ac=10</A><BR>
<BR>
Others,<BR>
<BR>
Please use PropertySaver when you see this pattern. Please also convert existing code that you see.<BR>
<BR>
Julian<BR>
<BR>
<BR>
<BR>
On Sun, 2008-10-19 at 11:40 -0700, Khanh Vu wrote:
<BLOCKQUOTE TYPE=CITE>
<PRE>
<A HREF="http://p4web.eigenbase.org/@md=d&c=6PU@//11768?ac=10">http://p4web.eigenbase.org/@md=d&c=6PU@//11768?ac=10</A>
Change 11768 by <A HREF="mailto:kvu@kvu.shada.eigenbase">kvu@kvu.shada.eigenbase</A> on 2008/10/19 11:39:47
        MONDRIAN: itegrates change 11758 to mondrian head
Affected files ...
... //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#154 integrate
... //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#112 integrate
... //open/mondrian/src/main/mondrian/olap/fun/OrderSetFunDef.java#1 branch
... //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#136 integrate
... //open/mondrian/testsrc/main/mondrian/test/Main.java#96 integrate
... //open/mondrian/testsrc/main/mondrian/test/clearview/OrderSetTest.java#1 branch
... //open/mondrian/testsrc/main/mondrian/test/clearview/OrderSetTest.ref.xml#1 branch
... //open/mondrian/testsrc/main/mondrian/xmla/XmlaBasicTest.ref.xml#67 integrate
Differences ...
==== //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#154 (ktext) ====
2c2
< // $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#153 $
---
> // $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#154 $
42c42
< * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#153 $
---
> * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#154 $
1091a1092
> define(OrderSetFunDef.Resolver);
==== //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#112 (ktext) ====
2c2
< // $Id: //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#111 $
---
> // $Id: //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#112 $
20a21,22
> import mondrian.calc.MemberCalc;
> import mondrian.calc.impl.*;
36c38
< * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#111 $
---
> * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/FunUtil.java#112 $
256a259
> ;
328c331
< static Map<Member, Object> evaluateMembers(
---
> static Map<Object, Object> evaluateMembers(
338c341
< Map<Member, Object> mapMemberToValue = new HashMap<Member, Object>();
---
> Map<Object, Object> mapMemberToValue = new HashMap<Object, Object>();
420a424,611
> * For each tuple/member in a list, evaluates the member value expression
> * and populates a map from tuples/members to members
> *
> * @param <T> Generic type, can take a member or a tuple
> * @param evaluator Evaluation context
> * @param exp Expression to evaluate
> * @param members List of members
> * @param parentsToo If true, evaluate the expression for all ancestors
> * of the members as well
> * @return the map from members or tuples to members
> */
> static <T> Map<Object, Object> evaluateMemberValueExps(
> Evaluator evaluator,
> Calc exp,
> List<T> members,
> boolean parentsToo)
> {
> MemberCalc mcalc = (MemberCalc) exp;
> Map<Object, Object> mapMemberToMember = new HashMap<Object, Object>();
>
> // try to optimize when exp is currentMember
> boolean isCurrMemExp = mcalc instanceof DimensionCurrentMemberFunDef.CalcImpl;
> int idx = -1;
> if (isCurrMemExp) {
> Object first = members.get(0);
> if (first instanceof Member[]) {
> Member[] firstMem = (Member[]) first;
> int n = firstMem.length;
> Dimension dim = mcalc.getType().getDimension();
> for (int i = 0; i < n; i++) {
> if (dim.equals(firstMem[i].getDimension())) {
> idx = i;
> break;
> }
> }
> assert idx != -1;
> }
> }
> // populate the map
> Object obj;
> Member result;
> for (int i = 0, n = members.size(); i < n; i++) {
> obj = members.get(i);
> if (obj instanceof Member) {
> while (true) {
> if (isCurrMemExp) {
> mapMemberToMember.put(obj, obj);
> } else {
> evaluator.setContext((Member) obj);
> result = mcalc.evaluateMember(evaluator);
> if (result == null) {
> result = NullMember;
> }
> mapMemberToMember.put(obj, result);
> }
> if (!parentsToo) {
> break;
> }
> obj = ((Member) obj).getParentMember();
> if (obj == null) {
> break;
> }
> if (mapMemberToMember.containsKey((Member) obj)) {
> break;
> }
> }
> } else if (obj instanceof Member[]) {
> evaluator.setContext((Member[]) obj);
> if (isCurrMemExp) {
> mapMemberToMember.put(
> new ArrayHolder<Member>((Member[]) obj), ((Member[]) obj)[idx]);
> } else {
> // populate tuples map
> result = mcalc.evaluateMember(evaluator);
> if (result == null) {
> result = NullMember;
> }
> mapMemberToMember.put(
> new ArrayHolder<Member>((Member[]) obj), result);
> }
> }
> }
> return mapMemberToMember;
> }
>
> /**
> * Populates the list of maps from tuples/members to values/members.
> * Each member of the list corresponds to a sort key. Since it is
> * unlikely that all sort keys will be used to compare any pair
> * of members, prepopulate the first half only
> *
> * @param <T> Generic type; can be member or tuple
> * @param listMapMemberToValue List of maps
> * @param evaluator Evaluation context
> * @param members List of members
> * @param keySpecList List of sort key specifications
> */
> static <T> void populateMembersMap(
> List<Map<Object, Object>> listMapMemberToValue,
> Evaluator evaluator,
> List<T> members,
> List<SortKeySpec> keySpecList)
> {
> final int keyCount = keySpecList.size();
> // magic number - pre-populate the map
> // for one plus the first half of sort keys
> final int depth = keyCount / 2 + 1;
> Object first = members.get(0);
> for (int i = 0; i < depth; i++) {
> SortKeySpec sortKey = keySpecList.get(i);
> if (sortKey.isMemberValueExp()) {
> // get member
> listMapMemberToValue.add(
> evaluateMemberValueExps(
> evaluator,
> sortKey.getKey(),
> members,
> !sortKey.getDirection().brk));
> } else {
> // get value
> if (first instanceof Member) {
> listMapMemberToValue.add(
> evaluateMembers(
> evaluator,
> sortKey.getKey(),
> (List<Member>) members,
> !sortKey.getDirection().brk));
> } else {
> // populate map for tuples only
> // meaning optimize for break hierarchy comparison only
> listMapMemberToValue.add(
> evaluateTuples(
> evaluator,
> sortKey.getKey(),
> (List<Member[]>) members));
> }
> }
> }
> for (int i = depth; i < keyCount; i++) {
> listMapMemberToValue.add(new HashMap<Object, Object>());
> }
> }
>
> /**
> * Gets the value from the map or evaluates the member using the expression
> * if the value is not ready
> *
> * @param member Key of the map
> * @param exp Expression to evaluate
> * @param evaluator Evaluation context
> * @param mapTuples Map of members or tuples to members or cell values
> * @return Value from the map
> */
> static Object getFromMapOrEvaluate(
> Object member,
> Calc exp,
> Evaluator evaluator,
> boolean isMemValExp,
> Map<Object, Object> mapTuples)
> {
> Object key;
> boolean isTuple = (member instanceof Member[]);
> if (isTuple) {
> key = new ArrayHolder<Member>((Member[]) member);
> } else {
> key = member;
> }
> Object val = mapTuples.get(key);
> if (val == null) {
> if (isTuple) {
> evaluator.setContext((Member[]) member);
> } else {
> evaluator.setContext((Member) member);
> }
> val = exp.evaluate(evaluator);
> if (val == null) {
> if (isMemValExp) {
> val = NullMember;
> } else {
> val = Util.nullValue;
> }
> }
> mapTuples.put(key, val);
> }
> return val;
> }
>
> /**
436c627
< Map<Member, Object> mapMemberToValue;
---
> Map<Object, Object> mapMemberToValue;
483a675,707
> * Helper function to sortMembers a list of members according to a list
> * of expressions and a list of sorting flags.
> *
> * <p>NOTE: This function does not preserve the contents of the validator.
> */
> public static void sortMembers(
> Evaluator evaluator, List<Member> members, List<SortKeySpec> keySpecList)
> {
> if (members.isEmpty()) {
> return;
> }
> Object first = members.get(0);
> List<Map<Object, Object>> listMapMemberToValue =
> new ArrayList<Map<Object, Object>>();
> populateMembersMap(
> listMapMemberToValue, evaluator, members, keySpecList);
> if (first instanceof Member) {
> Comparator<Member> comparator =
> new MultiKeysMemberComparator(
> evaluator, keySpecList, listMapMemberToValue).wrap();
> Collections.sort(members, comparator);
> } else {
> Util.assertTrue(first instanceof Member[]);
> List<Member[]> tupleList = Util.cast(members);
> final int arity = ((Member[]) first).length;
> Comparator<Member[]> comparator =
> new MultiKeysArrayComparator(
> evaluator, keySpecList, listMapMemberToValue, arity).wrap();
> Collections.sort(tupleList, comparator);
> }
> }
>
> /**
1633a1858,1948
> public static int compareMembersByOrderKeys(
> Member m1, Member m2)
> {
> // calculated members collate after non-calculated
> final boolean calculated1 = m1.isCalculatedInQuery();
> final boolean calculated2 = m2.isCalculatedInQuery();
> if (calculated1) {
> if (!calculated2) {
> return 1;
> }
> } else {
> if (calculated2) {
> return -1;
> }
> }
> final Comparable k1 = m1.getOrderKey();
> final Comparable k2 = m2.getOrderKey();
> if ((k1 != null) && (k2 != null)) {
> return k1.compareTo(k2);
> } else {
> return m1.compareTo(m2);
> }
> }
>
> public static int compareMembers(
> Member m1,
> Member m2,
> Evaluator evaluator,
> Calc exp,
> boolean isMemValExp,
> Map<Object, Object> mapMemberToValue)
> {
> if (isMemValExp) {
> return FunUtil.compareMembersByOrderKeys(m1, m2);
> } else {
> Member old = evaluator.setContext(m1);
> Object v1 = getFromMapOrEvaluate(
> m1, exp, evaluator, false, mapMemberToValue);
> Object v2 = getFromMapOrEvaluate(
> m2, exp, evaluator, false, mapMemberToValue);
> // important to restore the evaluator state -- and this is faster
> // than calling evaluator.push()
> evaluator.setContext(old);
> return FunUtil.compareValues(v1, v2);
> }
> }
>
> public static int compareMembersHierarchically(
> Member m1,
> Member m2,
> Evaluator evaluator,
> Calc exp,
> boolean desc,
> boolean isMemValExp,
> Map<Object, Object> mapMemberToValue)
> {
> if (FunUtil.equals(m1, m2)) {
> return 0;
> }
> while (true) {
> int depth1 = m1.getDepth(),
> depth2 = m2.getDepth();
> if (depth1 < depth2) {
> m2 = m2.getParentMember();
> if (FunUtil.equals(m1, m2)) {
> return -1;
> }
> } else if (depth1 > depth2) {
> m1 = m1.getParentMember();
> if (FunUtil.equals(m1, m2)) {
> return 1;
> }
> } else {
> Member prev1 = m1, prev2 = m2;
> m1 = m1.getParentMember();
> m2 = m2.getParentMember();
> if (FunUtil.equals(m1, m2)) {
> // including case where both parents are null
> int c = FunUtil.compareMembers(
> prev1, prev2, evaluator, exp, isMemValExp, mapMemberToValue);
> // skip the below compare if isMemValExp is true
> if ((c == 0) && !(isMemValExp)) {
> c = FunUtil.compareMembersByOrderKeys(
> prev1, prev2);
> }
> return desc ? -c : c;
> }
> }
> }
> }
>
1829c2144
< List <Member> memberList =
---
> List<Member> memberList =
1880c2195
< Map<Member, Object> mapMemberToValue;
---
> Map<Object, Object> mapMemberToValue;
1881a2197
> Evaluator evaluator;
1883c2199
< MemberComparator(Map<Member, Object> mapMemberToValue, boolean desc) {
---
> MemberComparator(Map<Object, Object> mapMemberToValue, boolean desc) {
1887a2204,2210
> MemberComparator(
> Evaluator evaluator,
> List<SortKeySpec> keySpecList)
> {
> this.evaluator = evaluator;
> }
>
1890c2213
< if (LOGGER.isDebugEnabled()) {
---
> if (LOGGER.isDebugEnabled() && (mapMemberToValue != null)) {
1961c2284
< Map<Member, Object> mapMemberToValue, boolean desc)
---
> Map<Object, Object> mapMemberToValue, boolean desc)
1972c2295
< BreakMemberComparator(Map<Member, Object> mapMemberToValue, boolean desc) {
---
> BreakMemberComparator(Map<Object, Object> mapMemberToValue, boolean desc) {
1980a2304,2365
> private static class MultiKeysMemberComparator extends MemberComparator
> {
> List<SortKeySpec> keySpecList;
> List<Map<Object, Object>> listMapMemberToValue;
> int keySpecCount;
>
> MultiKeysMemberComparator(
> Evaluator evaluator,
> List<SortKeySpec> keySpecList,
> List<Map<Object, Object>> listMapMemberToValue)
> {
> super(evaluator, keySpecList);
> this.keySpecList = keySpecList;
> this.listMapMemberToValue = listMapMemberToValue;
> this.keySpecCount = keySpecList.size();
> }
>
> public final int compare(Member m1, Member m2)
> {
> int c = 0;
> for (int i = 0; i < keySpecCount; i++) {
> SortKeySpec sortKey = keySpecList.get(i);
> Calc exp = sortKey.key;
> Flag flag = sortKey.direction;
> boolean isMemValExp = sortKey.isMemberValExp;
> Map<Object, Object> mapMemberToValue =
> listMapMemberToValue.get(i);
> //this.evaluator.push(); //check if this is needed
> Member tm1 = null, tm2 = null;
> if (isMemValExp) {
> tm1 = (Member) getFromMapOrEvaluate(
> m1, exp, evaluator, true, mapMemberToValue);
> tm2 = (Member) getFromMapOrEvaluate(
> m2, exp, evaluator, true, mapMemberToValue);
> }
> if (flag.brk) {
> int c1 = compareMembers(
> isMemValExp ? tm1 : m1,
> isMemValExp ? tm2 : m2,
> evaluator,
> exp,
> isMemValExp,
> mapMemberToValue);
> c = flag.descending ? -c1 : c1;
> } else {
> c = compareMembersHierarchically(
> isMemValExp ? tm1 : m1,
> isMemValExp ? tm2 : m2,
> evaluator,
> exp,
> flag.descending,
> isMemValExp,
> mapMemberToValue);
> }
> if (c != 0) {
> return c;
> }
> }
> return c;
> }
> }
>
2044c2429
< final Calc calc;
---
> Calc calc;
2050a2436,2442
>
> ArrayExpComparator(
> Evaluator evaluator,
> int arity) {
> super(arity);
> this.evaluator = evaluator;
> }
2142a2535,2640
> private static class MultiKeysArrayComparator
> extends ArrayExpComparator
> {
> List<SortKeySpec> keySpecList;
> List<Map<Object, Object>> listMapMemberToValue;
> int keySpecCount;
>
> MultiKeysArrayComparator(
> Evaluator evaluator,
> List<SortKeySpec> keySpecList,
> List<Map<Object, Object>> listMapMemberToValue,
> int arity)
> {
> super(evaluator, arity);
> this.keySpecList = keySpecList;
> this.keySpecCount = keySpecList.size();
> this.listMapMemberToValue = listMapMemberToValue;
> }
>
> public int compare(Member[] a1, Member[] a2) {
> int c = 0;
> for (int i = 0; i < keySpecCount; i++) {
> SortKeySpec sortKey = keySpecList.get(i);
> if (sortKey.direction.brk) {
> c = compareBreakHierarchy(
> a1,
> a2,
> sortKey.key,
> sortKey.direction.descending,
> sortKey.isMemberValExp,
> listMapMemberToValue.get(i));
> } else {
> c = compareHierarchically(
> a1,
> a2,
> sortKey.key,
> sortKey.direction.descending,
> sortKey.isMemberValExp,
> listMapMemberToValue.get(i));
> }
> if (c != 0) {
> return c;
> }
> }
> return c;
> }
>
> public int compareBreakHierarchy(
> Member[] a1,
> Member[] a2,
> Calc exp,
> boolean desc,
> boolean isMemValExp,
> Map<Object, Object> mapTupleToValue)
> {
> if (isMemValExp) {
> Member m1 = (Member) getFromMapOrEvaluate(
> a1, exp, evaluator, true, mapTupleToValue);
> Member m2 = (Member) getFromMapOrEvaluate(
> a2, exp, evaluator, true, mapTupleToValue);
> return desc ?
> - compareMembersByOrderKeys(m1, m2) :
> compareMembersByOrderKeys(m1, m2);
> } else {
> Object v1 = getFromMapOrEvaluate(
> a1, exp, evaluator, false, mapTupleToValue);
> Object v2 = getFromMapOrEvaluate(
> a2, exp, evaluator, false, mapTupleToValue);
> return desc ?
> - compareValues(v1, v2) :
> compareValues(v1, v2);
> }
> }
>
> public int compareHierarchically(
> Member[] a1,
> Member[] a2,
> Calc exp,
> boolean desc,
> boolean isMemValExp,
> Map<Object, Object> mapTupleToValue)
> {
> int c = 0;
> if (isMemValExp) {
> Member m1 = (Member) getFromMapOrEvaluate(
> a1, exp, evaluator, true, mapTupleToValue);
> Member m2 = (Member) getFromMapOrEvaluate(
> a2, exp, evaluator, true, mapTupleToValue);
> c = compareMembersHierarchically(
> m1, m2, evaluator, exp, desc, isMemValExp, mapTupleToValue);
> } else {
> for (int i = 0; i < arity; i++) {
> Member m1 = a1[i],
> m2 = a2[i];
> c = compareMembersHierarchically(
> m1, m2, evaluator, exp, desc, isMemValExp, mapTupleToValue);
> if (c != 0) {
> break;
> }
> evaluator.setContext(m1);
> }
> }
> return c;
> }
> }
>
2386a2885,2946
>
> /**
> * Enumeration of the flags allowed to the <code>ORDER</code> MDX function.
> */
> enum Flag {
> ASC(false, false),
> DESC(true, false),
> BASC(false, true),
> BDESC(true, true);
>
> final boolean descending;
> final boolean brk;
>
> Flag(boolean descending, boolean brk) {
> this.descending = descending;
> this.brk = brk;
> }
>
> public static String[] getNames() {
> List<String> names = new ArrayList<String>();
> for (Flag flags : Flag.class.getEnumConstants()) {
> names.add(flags.name());
> }
> return names.toArray(new String[names.size()]);
> }
> }
>
> class SortKeySpec {
> private Calc key;
> private boolean isMemberValExp = true;
> private Flag direction;
>
> SortKeySpec(Calc key, boolean memberValExp, Flag dir) {
> this.key = key;
> this.isMemberValExp = memberValExp;
> this.direction = dir;
> }
>
> Calc getKey() {
> return this.key;
> }
>
> boolean isMemberValueExp() {
> return this.isMemberValExp;
> }
>
> Flag getDirection() {
> return this.direction;
> }
>
> void setKey(Calc key) {
> this.key = key;
> }
>
> void setMemberValueExp(boolean m) {
> this.isMemberValExp = m;
> }
>
> void setDirection(Flag dir) {
> this.direction = dir;
> }
> }
==== //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#136 (ktext) ====
2c2
< // $Id: //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#135 $
---
> // $Id: //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#136 $
34c34
< * @version $Id: //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#135 $
---
> * @version $Id: //open/mondrian/testsrc/main/mondrian/olap/fun/FunctionTest.java#136 $
37a38,39
> private MondrianProperties props;
>
161a164
> props = MondrianProperties.instance();
165a169
> props = MondrianProperties.instance();
5982a5987,6434
> public void testOrderSetEmpty() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {}," +
> " [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n"));
> }
>
> public void testOrderOne() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}," +
> " [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "Row #0: 75\n"));
> }
>
> public void testOrderSetMemberMemberValueExpNew() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> boolean saved = props.CompareSiblingsByOrderKey.get();
> props.CompareSiblingsByOrderKey.set(true);
> Connection conn = null;
> try {
> // Use a fresh connection to make sure bad member ordinals haven't
> // been assigned by previous tests.
> conn = getTestContext().getFoodMartConnection(false);
> TestContext context = getTestContext(conn);
> context.assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n"));
> } finally {
> props.CompareSiblingsByOrderKey.set(saved);
> if (conn != null) {
> conn.close();
> }
> }
> }
>
> public void testOrderSetMemberDefaultFlag1() {
> // flags not specified default to ASC
> String query =
> "with \n" +
> " Member [Measures].[Zero] as '0' \n" +
> "select \n" +
> " OrderSet(" +
> " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Customers].currentMember) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n"));
> }
>
> public void testOrderSetMemberDefaultFlag2() {
> // flags not specified default to ASC
> String query =
> "with \n" +
> " Member [Measures].[Zero] as '0' \n" +
> "select \n" +
> " OrderSet(" +
> " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Measures].[Store Cost]) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetMemberMemberValueExpHierarchy() {
> // Santa Monica and Woodland Hills both don't have orderkey
> // members are sorted by the order of their keys
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Customers].currentMember, DESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetMemberMultiKeysMemberValueExp1() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Measures].[Unit Sales], BDESC, [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetMemberMultiKeysMemberValueExp2() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Customers].currentMember.Parent.Parent, BASC, [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> boolean saved = props.CompareSiblingsByOrderKey.get();
> props.CompareSiblingsByOrderKey.set(true);
> Connection conn = null;
> try {
> // Use a fresh connection to make sure bad member ordinals haven't
> // been assigned by previous tests.
> conn = getTestContext().getFoodMartConnection(false);
> TestContext context = getTestContext(conn);
> context.assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> } finally {
> props.CompareSiblingsByOrderKey.set(saved);
> if (conn != null) {
> conn.close();
> }
> }
> }
>
> public void testOrderSetMemberMultiKeysMemberValueExpDepends() {
> // should preserve order of Abe and Adeline (note second key is [Time])
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Measures].[Unit Sales], BDESC, [Time].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetTupleSingleKeysNew() {
> String query =
> "with \n" +
> " set [NECJ] as \n" +
> " 'NonEmptyCrossJoin( \n" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " {[Store].[USA].[WA].[Seattle],\n" +
> " [Store].[USA].[CA],\n" +
> " [Store].[USA].[OR]})'\n" +
> "select \n" +
> " OrderSet([NECJ], [Customers].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> boolean saved = props.CompareSiblingsByOrderKey.get();
> props.CompareSiblingsByOrderKey.set(true);
> Connection conn = null;
> try {
> // Use a fresh connection to make sure bad member ordinals haven't
> // been assigned by previous tests.
> conn = getTestContext().getFoodMartConnection(false);
> TestContext context = getTestContext(conn);
> context.assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun], [Store].[All Stores].[USA].[CA]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young], [Store].[All Stores].[USA].[CA]}\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel], [Store].[All Stores].[USA].[WA].[Seattle]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> } finally {
> props.CompareSiblingsByOrderKey.set(saved);
> if (conn != null) {
> conn.close();
> }
> }
> }
>
> public void testOrderSetTupleMultiKeys1() {
> String query =
> "with \n" +
> " set [NECJ] as \n" +
> " 'NonEmptyCrossJoin( \n" +
> " {[Store].[USA].[CA],\n" +
> " [Store].[USA].[WA]},\n" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n" +
> "select \n" +
> " OrderSet([NECJ], [Store].currentMember, BDESC, [Measures].[Unit Sales], BDESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Store].[All Stores].[USA].[WA], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetTupleMultiKeys2() {
> String query =
> "with \n" +
> " set [NECJ] as \n" +
> " 'NonEmptyCrossJoin( \n" +
> " {[Store].[USA].[CA],\n" +
> " [Store].[USA].[WA]},\n" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n" +
> "select \n" +
> " OrderSet([NECJ], [Measures].[Unit Sales], BDESC, Ancestor([Customers].currentMember, [Customers].[Name]), BDESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Store].[All Stores].[USA].[WA], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetTupleMultiKeys3() {
> // WA unit sales is greater than CA unit sales
> // Santa Monica unit sales (2660) is greater that Woodland hills (2516)
> String query =
> "with \n" +
> " set [NECJ] as \n" +
> " 'NonEmptyCrossJoin( \n" +
> " {[Store].[USA].[CA],\n" +
> " [Store].[USA].[WA]},\n" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n" +
> "select \n" +
> " OrderSet([NECJ], [Measures].[Unit Sales], DESC, Ancestor([Customers].currentMember, [Customers].[Name]), BDESC) \n" +
> "on 0 from [Sales]";
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Store].[All Stores].[USA].[WA], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Store].[All Stores].[USA].[CA], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "Row #0: 33\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n"));
> }
>
> public void testOrderSetTupleMultiKeyswithVCube() {
> // WA unit sales is greater than CA unit sales
> String query =
> "with \n" +
> " set [CJ] as \n" +
> " 'CrossJoin( \n" +
> " {[Position].[Store Management].children},\n" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]})' \n" +
> "select \n" +
> " [Measures].[Org Salary] on columns, \n" +
> " OrderSet([CJ], [Position].currentMember, BASC, Ancestor([Customers].currentMember, [Customers].[Name]), BDESC) \n" +
> "on rows \n" +
> "from [Sales vs HR]";
>
> boolean saved = props.CompareSiblingsByOrderKey.get();
> props.CompareSiblingsByOrderKey.set(true);
> Connection conn = null;
> try {
> // Use a fresh connection to make sure bad member ordinals haven't
> // been assigned by previous tests.
> conn = getTestContext().getFoodMartConnection(false);
> TestContext context = getTestContext(conn);
> // a non-sense cube just to test ordering by order key
> context = context.create(
> null, null,
> "<VirtualCube name=\"Sales vs HR\">\n" +
> "<VirtualCubeDimension cubeName=\"Sales\" name=\"Customers\"/>\n" +
> "<VirtualCubeDimension cubeName=\"HR\" name=\"Position\"/>\n" +
> "<VirtualCubeMeasure cubeName=\"HR\" name=\"[Measures].[Org Salary]\"/>\n" +
> "</VirtualCube>",
> null, null, null);
>
> context.assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Measures].[Org Salary]}\n" +
> "Axis #2:\n" +
> "{[Position].[All Position].[Store Management].[Store Manager], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Position].[All Position].[Store Management].[Store Manager], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Position].[All Position].[Store Management].[Store Manager], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Position].[All Position].[Store Management].[Store Assistant Manager], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Position].[All Position].[Store Management].[Store Assistant Manager], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Position].[All Position].[Store Management].[Store Assistant Manager], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Position].[All Position].[Store Management].[Store Shift Supervisor], [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "{[Position].[All Position].[Store Management].[Store Shift Supervisor], [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Position].[All Position].[Store Management].[Store Shift Supervisor], [Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "Row #0: \n" +
> "Row #1: \n" +
> "Row #2: \n" +
> "Row #3: \n" +
> "Row #4: \n" +
> "Row #5: \n" +
> "Row #6: \n" +
> "Row #7: \n" +
> "Row #8: \n"));
> } finally {
> props.CompareSiblingsByOrderKey.set(saved);
> if (conn != null) {
> conn.close();
> }
> }
> }
>
> public void testOrderSetConstant1() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Customers].[USA], BDESC) \n" +
> "on 0 from [Sales]";
>
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> }
>
> public void testOrderSetDiffrentDim() {
> String query =
> "select \n" +
> " OrderSet(" +
> " {[Customers].[USA].[WA].[Issaquah].[Abe Tramel]," +
> " [Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]," +
> " [Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}," +
> " [Product].currentMember, BDESC, [Gender].currentMember, BDESC) \n" +
> "on 0 from [Sales]";
>
> assertQueryReturns(query,
> fold(
> "Axis #0:\n" +
> "{}\n" +
> "Axis #1:\n" +
> "{[Customers].[All Customers].[USA].[WA].[Issaquah].[Abe Tramel]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Woodland Hills].[Abel Young]}\n" +
> "{[Customers].[All Customers].[USA].[CA].[Santa Monica].[Adeline Chun]}\n" +
> "Row #0: 33\n" +
> "Row #0: 75\n" +
> "Row #0: 33\n"));
> }
>
==== //open/mondrian/testsrc/main/mondrian/test/Main.java#96 (ktext) ====
2c2
< // $Id: //open/mondrian/testsrc/main/mondrian/test/Main.java#95 $
---
> // $Id: //open/mondrian/testsrc/main/mondrian/test/Main.java#96 $
49c49
< * @version $Id: //open/mondrian/testsrc/main/mondrian/test/Main.java#95 $
---
> * @version $Id: //open/mondrian/testsrc/main/mondrian/test/Main.java#96 $
198a199
> addTest(suite, OrderSetTest.class, "suite");
==== //open/mondrian/testsrc/main/mondrian/xmla/XmlaBasicTest.ref.xml#67 (ktext) ====
5626a5627,5636
> <FUNCTION_NAME>OrderSet</FUNCTION_NAME>
> <DESCRIPTION>Arranges members of a set,
> optionally preserving or breaking the hierarchy.</DESCRIPTION>
> <PARAMETER_LIST>(none)</PARAMETER_LIST>
> <RETURN_TYPE>1</RETURN_TYPE>
> <ORIGIN>1</ORIGIN>
> <INTERFACE_NAME/>
> <CAPTION>OrderSet</CAPTION>
> </row>
> <row>
</PRE>
</BLOCKQUOTE>
</BODY>
</HTML>