Index: demo/FoodMart.xml.AEAT
===================================================================
--- demo/FoodMart.xml.AEAT	
+++ demo/FoodMart.xml.AEAT	
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<Schema name="FoodMart">
+<!--  <Cube name="Sales" cache="true" enabled="true">  -->
+  <Cube name="Sales">
+    <Table name="Autoliquidaciones_2006" schema="foodmart"> 
+    </Table> 
+
+    <Dimension name="Modelo" highCardinality="true"> 
+      <Hierarchy hasAll="true" allMemberName="Modelo (todos)"> 
+        <Level approxRowCount="69" name="Modelo" column="ALD013" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+      </Hierarchy> 
+    </Dimension> 
+
+    <Dimension name="NIF" highCardinality="true"> 
+      <Hierarchy hasAll="true" allMemberName="NIF (todos)"> 
+        <Table name="Autoliquidaciones_2006" schema="foodmart"/> 
+        <Level approxRowCount="19527760" name="NIF"
+               column="ALD001" type="Numeric" uniqueMembers="true" 
+               levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+      </Hierarchy> 
+    </Dimension> 
+
+    <Dimension name="Fecha"> 
+      <Hierarchy hasAll="true" allMemberName="Fecha (todas)"> 
+        <Level approxRowCount="7" name="Anio" column="ALD009" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+        <Level approxRowCount="37" name="Mes" column="ALD010" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+        <Level approxRowCount="679" name="Dia" column="ALD011" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+      </Hierarchy> 
+    </Dimension> 
+
+    <Dimension foreignKey="ALD015" name="Concepto"> 
+      <Hierarchy hasAll="true" allMemberName="Concepto (todos)" 
+                 primaryKey="Concepto"> 
+        <Table name="OLAP_Concepto" schema="foodmart"> 
+        </Table> 
+        <Level name="Concepto" column="Descripcion" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
+        </Level> 
+      </Hierarchy> 
+    </Dimension> 
+
+    <Dimension foreignKey="ALD051" name="DomicilioFiscal"> 
+      <Hierarchy hasAll="true" allMemberName="DomicilioFiscal (todos)" 
+                 primaryKey="Administracion"> 
+        <Table name="OLAP_Administracion" schema="foodmart"> 
+        </Table> 
+        <Level approxRowCount="20" name="DelegacionEspecial" 
+               table="OLAP_Administracion" column="DelegacionEspecial" 
+               nameColumn="Descripcion_DelegacionEspecial" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
+        </Level> 
+        <Level approxRowCount="60" name="DelegacionProvincial" 
+               table="OLAP_Administracion" column="DelegacionProvincial" 
+               nameColumn="Descripcion_DelegacionProvincial" type="String" 
+               uniqueMembers="true" levelType="Regular" hideMemberIf="Never">
+        </Level> 
+        <Level approxRowCount="400" name="Administracion" 
+               table="OLAP_Administracion" column="Administracion"
+               nameColumn="Descripcion" type="String" uniqueMembers="true"
+               levelType="Regular" hideMemberIf="Never"> 
+        </Level> 
+      </Hierarchy> 
+    </Dimension> 
+
+    <Measure name="Autoliquidaciones" column="ALAK" datatype="Numeric" 
+             aggregator="count"> 
+    </Measure> 
+    <Measure name="Importe" column="ALD043" datatype="Numeric" 
+             aggregator="sum"> 
+    </Measure> 
+    <Measure name="Total" column="ALD044" datatype="Numeric" aggregator="sum"> 
+    </Measure> 
+    <Measure name="Saldo" column="ALD055" datatype="Numeric" aggregator="sum"> 
+    </Measure> 
+  </Cube> 
+
+</Schema>
Index: demo/foodmart.properties
===================================================================
--- demo/foodmart.properties	
+++ demo/foodmart.properties	
@@ -0,0 +1,33 @@
+##############################################################################
+#
+# Example properties file
+#
+# $Id: //open/mondrian/doc/cmdrunner.html#11 $
+##############################################################################
+# Environment
+mondrian.catalogURL=demo/FoodMart.xml
+
+jdbc=jdbc:omysql://localhost/foodmart?user=foodmart&password=foodmart
+# mysql
+mondrian.test.jdbcURL=jdbc:mysql://localhost/foodmart?user=foodmart&password=foodmart
+mondrian.jdbcDrivers=com.mysql.jdbc.Driver
+
+# Use MD5 based caching for the RolapSchema instance
+mondrian.catalog.content.cache.enabled=true
+
+# both read and use aggregate tables
+mondrian.rolap.aggregates.Use=true
+mondrian.rolap.aggregates.Read=true
+
+# generate aggregate sql (for every mdx query)
+#mondrian.rolap.aggregates.generateSql=true
+
+# pretty print sql (if log level for mondrian.rolap.RolapUtil is DEBUG)
+mondrian.rolap.generate.formatted.sql=true
+
+# by default the aggregate table with the smallest number of rows
+# (rather than rows times size of each row) is used
+#mondrian.rolap.aggregates.ChooseByVolume=true
+
+mondrian.result.limit=1000000
+mondrian.result.highCardChunkSize=9
Index: demo/FoodMart.xml
===================================================================
--- demo/FoodMart.xml	
+++ demo/FoodMart.xml	
@@ -567,7 +567,7 @@
       <Level name="Media Type" column="media_type" uniqueMembers="true"/>
     </Hierarchy>
   </Dimension>
-  <Dimension name="Promotions" foreignKey="promotion_id">
+  <Dimension name="Promotions" foreignKey="promotion_id" highCardinality="true">
     <Hierarchy hasAll="true" allMemberName="All Promotions" primaryKey="promotion_id">
       <Table name="promotion"/>
       <Level name="Promotion Name" column="promotion_name" uniqueMembers="true"/>
Index: testsrc/main/mondrian/test/MondrianTestRunner.java
===================================================================
--- testsrc/main/mondrian/test/MondrianTestRunner.java	
+++ testsrc/main/mondrian/test/MondrianTestRunner.java	
@@ -134,9 +134,9 @@
                         }
                         if (result.shouldStop())
                             break;
-                    }
+                     }
                 }
-
+        
             }, "Test thread " + i);
             threads[i].start();
         }
Index: testsrc/main/mondrian/test/comp/ResultComparatorTest.java
===================================================================
--- testsrc/main/mondrian/test/comp/ResultComparatorTest.java	
+++ testsrc/main/mondrian/test/comp/ResultComparatorTest.java	
@@ -111,18 +111,18 @@
 
         Document doc = db.parse(file);
 
-        Element queryNode = (Element) doc.getElementsByTagName("mdxQuery").item(0);
-        String queryString = XMLUtility.decodeEncodedString(queryNode.getFirstChild()
-                .getNodeValue());
+        Element queryNode = (Element) doc.getElementsByTagName("mdxQuery")
+                .item(0);
+        String queryString = XMLUtility.decodeEncodedString(
+                queryNode.getFirstChild().getNodeValue());
 
         Connection cxn = TestContext.instance().getFoodMartConnection();
         try {
             Query query = cxn.parseQuery(queryString);
             Result result = cxn.execute(query);
+            ResultComparator comp = new ResultComparator((Element) 
+                    doc.getElementsByTagName("dataResult").item(0), result);
 
-            ResultComparator comp = new ResultComparator((Element) doc.getElementsByTagName(
-                    "dataResult").item(0), result);
-
             comp.compareResults();
         } finally {
             cxn.close();
@@ -135,8 +135,10 @@
         String filePattern = properties.QueryFilePattern.get();
         String fileDirectory = properties.QueryFileDirectory.get();
 
-        final Pattern pattern = filePattern == null ? null : Pattern.compile(filePattern);
-        final String directory = fileDirectory == null ? "testsrc" + File.separatorChar + "queryFiles" : fileDirectory;
+        final Pattern pattern = filePattern == null ? null 
+                : Pattern.compile(filePattern);
+        final String directory = fileDirectory == null ? "testsrc" 
+                + File.separatorChar + "queryFiles" : fileDirectory;
 
         File[] files = new File(directory).listFiles(
             new FilenameFilter() {
Index: testsrc/main/mondrian/test/Main.java
===================================================================
--- testsrc/main/mondrian/test/Main.java	
+++ testsrc/main/mondrian/test/Main.java	
@@ -169,6 +169,8 @@
                 suite.addTest((Test) o);
             }
         } else {
+            suite.addTestSuite(CacheMapTest.class);
+            suite.addTestSuite(HighDimensionsTest.class);
             suite.addTestSuite(IndexedValuesTest.class);
             suite.addTestSuite(MemoryMonitorTest.class);
             suite.addTestSuite(ObjectPoolTest.class);
@@ -237,7 +239,7 @@
             suite.addTestSuite(SharedDimensionTest.class);
             suite.addTestSuite(CellPropertyTest.class);
             suite.addTestSuite(QueryTest.class);
-
+            
             boolean testNonEmpty = isRunOnce();
             if (!MondrianProperties.instance().EnableNativeNonEmpty.get()) {
                 testNonEmpty = false;
Index: testsrc/main/mondrian/test/loader/insert.sql
===================================================================
--- testsrc/main/mondrian/test/loader/insert.sql	
+++ testsrc/main/mondrian/test/loader/insert.sql	
@@ -0,0 +1,464 @@
+# $Id: //open/mondrian/testsrc/main/mondrian/test/loader/insert.sql#8 $
+# This software is subject to the terms of the Common Public License
+# Agreement, available at the following URL:
+# http://www.opensource.org/licenses/cpl.html.
+# (C) Copyright 2004-2006 Julian Hyde
+# All Rights Reserved.
+# You must accept the terms of that agreement to use this software.
+
+##################################################################
+## agg_pl_01_sales_fact_1997 done
+##################################################################
+# physical
+# lost "promotion_id" "store_id"
+
+INSERT INTO "agg_pl_01_sales_fact_1997" (
+    "product_id", 
+    "time_id",
+    "customer_id",
+    "store_sales_sum", 
+    "store_cost_sum", 
+    "unit_sales_sum", 
+    "fact_count"
+) SELECT
+    "product_id" AS "product_id",
+    "time_id" AS "time_id",
+    "customer_id" AS "customer_id",
+    SUM("store_sales") AS "store_sales",
+    SUM("store_cost") AS "store_cost",
+    SUM("unit_sales") AS "unit_sales",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997"
+GROUP BY "product_id", "time_id", "customer_id";
+
+
+INSERT INTO "agg_ll_01_sales_fact_1997" (
+    "product_id", 
+    "time_id",
+    "customer_id",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "product_id" AS "product_id",
+    "time_id" AS "time_id",
+    "customer_id" AS "customer_id",
+    SUM("store_sales") AS "store_sales",
+    SUM("store_cost") AS "store_cost",
+    SUM("unit_sales") AS "unit_sales",
+    COUNT(*) AS "fact_count"
+FROM "sales_fact_1997"
+GROUP BY "product_id", "time_id", "customer_id";
+
+##################################################################
+## agg_l_03_sales_fact_1997 done
+##################################################################
+# logical
+# lost "product_id" "promotion_id" "store_id"
+
+
+INSERT INTO "agg_l_03_sales_fact_1997" (
+    "customer_id", 
+    "time_id",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "customer_id",
+    "time_id",
+    SUM("store_sales") AS "store_sales",
+    SUM("store_cost") AS "store_cost",
+    SUM("unit_sales") AS "unit_sales",
+    COUNT(*) AS "fact_count"
+FROM "sales_fact_1997"
+GROUP BY "customer_id", "time_id";
+
+##################################################################
+## agg_lc_06_sales_fact_1997 done
+##################################################################
+# collapse "customer_id"
+# lost "product_id" "promotion_id" "store_id"
+
+
+INSERT INTO "agg_lc_06_sales_fact_1997" (
+    "time_id",
+    "city",
+    "state_province",
+    "country",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "B"."time_id",
+    "D"."city",
+    "D"."state_province",
+    "D"."country",
+    SUM("B"."store_sales") AS "store_sales",
+    SUM("B"."store_cost") AS "store_cost",
+    SUM("B"."unit_sales") AS "unit_sales",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997" "B", "customer" "D"
+WHERE 
+    "B"."customer_id" = "D"."customer_id"
+GROUP BY 
+         "B"."time_id",
+         "D"."city",
+         "D"."state_province",
+         "D"."country";
+
+##################################################################
+## agg_l_04_sales_fact_1997 done
+##################################################################
+# logical
+# lost "customer_id" "product_id" "promotion_id" "store_id"
+
+INSERT INTO "agg_l_04_sales_fact_1997" (
+    "time_id",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "customer_count", 
+    "fact_count"
+) SELECT
+    "time_id",
+    SUM("store_sales") AS "store_sales",
+    SUM("store_cost") AS "store_cost",
+    SUM("unit_sales") AS "unit_sales",
+    COUNT(DISTINCT "customer_id") AS "customer_count",
+    COUNT(*) AS "fact_count"
+FROM "sales_fact_1997"
+GROUP BY "time_id";
+
+##################################################################
+## agg_c_10_sales_fact_1997 done
+##################################################################
+# collapse "time_id"
+# lost "customer_id" "product_id" "promotion_id" "store_id"
+
+
+INSERT INTO "agg_c_10_sales_fact_1997" (
+    "month_of_year",
+    "quarter",
+    "the_year",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "customer_count", 
+    "fact_count"
+) SELECT
+    "D"."month_of_year",
+    "D"."quarter",
+    "D"."the_year",
+    SUM("B"."store_sales") AS "store_sales",
+    SUM("B"."store_cost") AS "store_cost",
+    SUM("B"."unit_sales") AS "unit_sales",
+    COUNT(DISTINCT "customer_id") AS "customer_count",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997" "B", "time_by_day" "D"
+WHERE 
+    "B"."time_id" = "D"."time_id"
+GROUP BY 
+         "D"."month_of_year",
+         "D"."quarter",
+         "D"."the_year";
+
+##################################################################
+## agg_l_05_sales_fact_1997 done
+##################################################################
+# logical
+# lost "time_id"
+
+
+INSERT INTO "agg_l_05_sales_fact_1997" (
+    "product_id",
+    "customer_id",
+    "promotion_id",
+    "store_id",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "product_id",
+    "customer_id",
+    "promotion_id",
+    "store_id",
+    SUM("store_sales") AS "store_sales",
+    SUM("store_cost") AS "store_cost",
+    SUM("unit_sales") AS "unit_sales",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997"
+GROUP BY "product_id", "customer_id", "promotion_id", "store_id";
+
+
+
+##################################################################
+## agg_c_14_sales_fact_1997 done
+##################################################################
+# collapse "time_id"
+
+
+INSERT INTO "agg_c_14_sales_fact_1997" (
+    "product_id", 
+    "customer_id",
+    "promotion_id",
+    "store_id",
+    "month_of_year",
+    "quarter",
+    "the_year",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "B"."product_id",
+    "B"."customer_id",
+    "B"."promotion_id",
+    "B"."store_id",
+    "D"."month_of_year",
+    "D"."quarter",
+    "D"."the_year",
+    SUM("B"."store_sales") AS "store_sales",
+    SUM("B"."store_cost") AS "store_cost",
+    SUM("B"."unit_sales") AS "unit_sales",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997" "B", "time_by_day" "D"
+WHERE 
+    "B"."time_id" = "D"."time_id"
+GROUP BY "B"."product_id", 
+         "B"."customer_id", 
+         "B"."promotion_id",
+         "B"."store_id", 
+         "D"."month_of_year",
+         "D"."quarter",
+         "D"."the_year";
+
+
+##################################################################
+## agg_lc_100_sales_fact_1997 done
+##################################################################
+# drop "promotion_id"
+# drop "store_id"
+# collapse "time_id"
+
+
+INSERT INTO "agg_lc_100_sales_fact_1997" (
+    "product_id", 
+    "customer_id",
+    "quarter",
+    "the_year",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "fact_count"
+) SELECT
+    "B"."product_id",
+    "B"."customer_id",
+    "D"."quarter",
+    "D"."the_year",
+    SUM("B"."store_sales") AS "store_sales",
+    SUM("B"."store_cost") AS "store_cost",
+    SUM("B"."unit_sales") AS "unit_sales",
+    COUNT(*) AS fact_count
+FROM "sales_fact_1997" "B", "time_by_day" "D"
+WHERE 
+    "B"."time_id" = "D"."time_id"
+GROUP BY "B"."product_id", 
+         "B"."customer_id", 
+         "D"."quarter",
+         "D"."the_year";
+
+
+##################################################################
+##################################################################
+## SPECIAL
+##################################################################
+##################################################################
+## agg_c_special_sales_fact_1997 done
+## based upon agg_c_14_sales_fact_1997
+##################################################################
+# collapse "time_id"
+
+
+INSERT INTO "agg_c_special_sales_fact_1997" (
+    "product_id", 
+    "customer_id",
+    "promotion_id",
+    "store_id",
+    "time_month",
+    "time_quarter",
+    "time_year",
+    "store_sales_sum", 
+    "store_cost_sum", 
+    "unit_sales_sum", 
+    "fact_count"
+) SELECT
+    "B"."product_id",
+    "B"."customer_id",
+    "B"."promotion_id",
+    "B"."store_id",
+    "D"."month_of_year",
+    "D"."quarter",
+    "D"."the_year",
+    SUM("B"."store_sales") AS "store_sales_sum",
+    SUM("B"."store_cost") AS "store_cost_sum",
+    SUM("B"."unit_sales") AS "unit_sales_sum",
+    COUNT(*) AS "fact_count"
+FROM "sales_fact_1997" "B", "time_by_day" "D"
+WHERE 
+    "B"."time_id" = "D"."time_id"
+GROUP BY "B"."product_id", 
+         "B"."customer_id", 
+         "B"."promotion_id",
+         "B"."store_id", 
+         "D"."month_of_year",
+         "D"."quarter",
+         "D"."the_year";
+
+##################################################################
+# agg_gender_ms_state_sales_fact_1997
+##################################################################
+
+INSERT INTO "agg_g_ms_pcat_sales_fact_1997" (
+    "gender", 
+    "marital_status",
+    "product_family",
+    "product_department",
+    "product_category",
+    "month_of_year",
+    "quarter",
+    "the_year",
+    "store_sales", 
+    "store_cost", 
+    "unit_sales", 
+    "customer_count", 
+    "fact_count"
+) SELECT
+    "C"."gender",
+    "C"."marital_status",
+    "PC"."product_family",
+    "PC"."product_department",
+    "PC"."product_category",
+    "T"."month_of_year",
+    "T"."quarter",
+    "T"."the_year",
+    SUM("B"."store_sales") AS "store_sales",
+    SUM("B"."store_cost") AS "store_cost",
+    SUM("B"."unit_sales") AS "unit_sales",
+    COUNT(DISTINCT "C"."customer_id") AS "customer_count",
+    COUNT(*) AS "fact_count"
+FROM "sales_fact_1997" "B",
+    "time_by_day" "T",
+    "product" "P",
+    "product_class" "PC",
+    "customer" "C"
+WHERE 
+    "B"."time_id" = "T"."time_id"
+AND "B"."customer_id" = "C"."customer_id"
+AND "B"."product_id" = "P"."product_id"
+AND "P"."product_class_id" = "PC"."product_class_id"
+GROUP BY 
+    "C"."gender",
+    "C"."marital_status",
+    "PC"."product_family",
+    "PC"."product_department",
+    "PC"."product_category",
+    "T"."month_of_year",
+    "T"."quarter",
+    "T"."the_year";
+
+# Above query, rephrased for Access (which does not support
+# COUNT(DISTINCT ...) explicitly.
+#
+#INSERT INTO "agg_g_ms_pcat_sales_fact_1997" (
+#    "gender", 
+#    "marital_status",
+#    "product_family",
+#    "product_department",
+#    "product_category",
+#    "month_of_year",
+#    "quarter",
+#    "the_year",
+#    "store_sales", 
+#    "store_cost", 
+#    "unit_sales", 
+#    "customer_count", 
+#    "fact_count"
+#) SELECT
+#    "C"."gender",
+#    "C"."marital_status",
+#    "PC"."product_family",
+#    "PC"."product_department",
+#    "PC"."product_category",
+#    "T"."month_of_year",
+#    "T"."quarter",
+#    "T"."the_year",
+#    SUM("B"."store_sales") AS "store_sales",
+#    SUM("B"."store_cost") AS "store_cost",
+#    SUM("B"."unit_sales") AS "unit_sales",
+#    (
+#    SELECT COUNT("customer_id")
+#    FROM (
+#        SELECT DISTINCT
+#            "DC"."gender",
+#            "DC"."marital_status",
+#            "DPC"."product_family",
+#            "DPC"."product_department",
+#            "DPC"."product_category",
+#            "DT"."month_of_year",
+#            "DT"."quarter",
+#            "DT"."the_year",
+#            "DB"."customer_id"
+#        FROM
+#            "sales_fact_1997" "DB",
+#            "time_by_day" "DT",
+#            "product" "DP",
+#            "product_class" "DPC",
+#            "customer" "DC"
+#        WHERE 
+#            "DB"."time_id" = "DT"."time_id"
+#        AND "DB"."customer_id" = "DC"."customer_id"
+#        AND "DB"."product_id" = "DP"."product_id"
+#        AND "DP"."product_class_id" = "DPC"."product_class_id") AS "CDC"
+#    WHERE "CDC"."gender" = "C"."gender"
+#    AND "CDC"."marital_status" = "C"."marital_status"
+#    AND "CDC"."product_family" = "PC"."product_family"
+#    AND "CDC"."product_department" = "PC"."product_department"
+#    AND "CDC"."product_category" = "PC"."product_category"
+#    AND "CDC"."month_of_year" = "T"."month_of_year"
+#    AND "CDC"."quarter" = "T"."quarter"
+#    AND "CDC"."the_year" = "T"."the_year"
+#    GROUP BY 
+#        "gender",
+#        "marital_status",
+#        "product_family",
+#        "product_department",
+#        "product_category",
+#        "month_of_year",
+#        "quarter",
+#        "the_year") AS "customer_count",
+#    COUNT(*) AS "fact_count"
+#FROM "sales_fact_1997" "B",
+#    "time_by_day" "T",
+#    "product" "P",
+#    "product_class" "PC",
+#    "customer" "C"
+#WHERE 
+#    "B"."time_id" = "T"."time_id"
+#AND "B"."customer_id" = "C"."customer_id"
+#AND "B"."product_id" = "P"."product_id"
+#AND "P"."product_class_id" = "PC"."product_class_id"
+#GROUP BY 
+#    "C"."gender",
+#    "C"."marital_status",
+#    "PC"."product_family",
+#    "PC"."product_department",
+#    "PC"."product_category",
+#    "T"."month_of_year",
+#    "T"."quarter",
+#    "T"."the_year";
+
+# End insert.sql
Index: testsrc/main/mondrian/olap/fun/MemberHelperTest.java
===================================================================
--- testsrc/main/mondrian/olap/fun/MemberHelperTest.java	
+++ testsrc/main/mondrian/olap/fun/MemberHelperTest.java	
@@ -14,6 +14,8 @@
 
 import junit.framework.TestCase;
 
+import java.util.*;
+
 /**
  * <code>MemberHelperTest</code> tests {@link MemberHelper}.
  *
@@ -49,20 +51,20 @@
 
 
     public void testEqualsMemberArray() {
-        Member[] a1 = new Member[]{
+        List<Member> a1 = Arrays.asList(new Member[]{
             new TestMember("blah"),
             new TestMember("foo"),
             new TestMember("bar"),
-        };
-        Member[] a2 = new Member[]{
+        });
+        List<Member> a2 = Arrays.asList(new Member[]{
             new TestMember("blah"),
             new TestMember("foo"),
             new TestMember("bar"),
-        };
-        Member[] a3 = new Member[]{
+        });
+        List<Member> a3 = Arrays.asList(new Member[]{
             new TestMember("blah"),
             new TestMember("bar"),
-        };
+        });
 
         MemberHelper mh1 = new MemberHelper(a1);
         MemberHelper mh2 = new MemberHelper(a2);
@@ -107,8 +109,8 @@
             return name.hashCode();
         }
 
-        public Member[] getAncestorMembers() {
-            return new Member[0];
+        public List<Member> getAncestorMembers() {
+            return new ArrayList<Member>();
         }
 
         public String getCaption() {
Index: testsrc/main/mondrian/olap/fun/TestMember.java
===================================================================
--- testsrc/main/mondrian/olap/fun/TestMember.java	
+++ testsrc/main/mondrian/olap/fun/TestMember.java	
@@ -10,6 +10,9 @@
 package mondrian.olap.fun;
 
 import mondrian.olap.*;
+
+import java.util.*;
+
 /**
  *
  *
@@ -85,7 +88,7 @@
         throw new UnsupportedOperationException();
     }
 
-    public Member[] getAncestorMembers() {
+    public List<Member> getAncestorMembers() {
         throw new UnsupportedOperationException();
     }
 
@@ -163,6 +166,53 @@
     }
 
     public Dimension getDimension() {
-        throw new UnsupportedOperationException();
+        return new Dimension() {
+            public Hierarchy[] getHierarchies() {
+                throw new UnsupportedOperationException();
+            }
+            public boolean isMeasures() {
+                throw new UnsupportedOperationException();
+            }
+            public DimensionType getDimensionType() {
+                throw new UnsupportedOperationException();
+            }
+            public int getOrdinal(Cube cube) {
+                throw new UnsupportedOperationException();
+            }
+            public Schema getSchema() {
+                throw new UnsupportedOperationException();
+            }
+            public boolean isHighCardinality() { return false; }
+
+            public String getUniqueName() {
+                throw new UnsupportedOperationException();
+            }
+            public String getName() {
+                throw new UnsupportedOperationException();
+            }
+            public String getDescription() {
+                throw new UnsupportedOperationException();
+            }
+            public OlapElement lookupChild(SchemaReader schemaReader, 
+                    Id.Segment s) {
+                throw new UnsupportedOperationException();
+            }
+            public OlapElement lookupChild(SchemaReader schemaReader, 
+                    Id.Segment s, MatchType matchType) {
+                throw new UnsupportedOperationException();
+            }
+            public String getQualifiedName() {
+                throw new UnsupportedOperationException();
+            }
+            public String getCaption() {
+                throw new UnsupportedOperationException();
+            }
+            public Hierarchy getHierarchy() {
+                throw new UnsupportedOperationException();
+            }
+            public Dimension getDimension() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 }
Index: testsrc/main/mondrian/olap/fun/CrossJoinTest.java
===================================================================
--- testsrc/main/mondrian/olap/fun/CrossJoinTest.java	
+++ testsrc/main/mondrian/olap/fun/CrossJoinTest.java	
@@ -34,32 +34,40 @@
 
 public class CrossJoinTest extends FoodMartTestCase {
 
-    static Member[] m1 = new Member[] {
+    static List<Member> m1 = Arrays.asList(new Member[] {
         new TestMember("a"),
         new TestMember("b"),
         new TestMember("c"),
-    };
-    static Member[] m2 = new Member[] {
+    });
+    static List<Member> m2 = Arrays.asList(new Member[] {
         new TestMember("A"),
         new TestMember("B"),
         new TestMember("C"),
         new TestMember("D"),
-    };
-    static Member[][] m3 = new Member[][] {
-        { new TestMember("k"), new TestMember("l") },
-        { new TestMember("m"), new TestMember("n") },
-    };
-    static Member[][] m4 = new Member[][] {
-        { new TestMember("U"), new TestMember("V") },
-        { new TestMember("W"), new TestMember("X") },
-        { new TestMember("Y"), new TestMember("Z") },
-    };
+    });
+    static List<List<Member>> m3 = new ArrayList<List<Member>>();
+    static {
+        m3.add(Arrays.asList(
+                new Member[] { new TestMember("k"), new TestMember("l") }));
+        m3.add(Arrays.asList(
+                new Member[] { new TestMember("m"), new TestMember("n") }));
+    }
+    
+    static List<List<Member>> m4 = new ArrayList<List<Member>>();
+    static {
+        m4.add(Arrays.asList(new Member[]{ 
+                new TestMember("U"), new TestMember("V") }));
+        m4.add(Arrays.asList(new Member[]{ 
+                new TestMember("W"), new TestMember("X") }));
+        m4.add(Arrays.asList(new Member[]{ 
+                new TestMember("Y"), new TestMember("Z") }));
+    }
 
-    static final Comparator<Member[]> memberComparator =
-        new Comparator<Member[]>() {
-            public int compare(Member[] ma1, Member[] ma2) {
-                for (int i = 0; i < ma1.length; i++) {
-                    int c = ma1[i].compareTo(ma2[i]);
+    static final Comparator<List<Member>> memberComparator =
+        new Comparator<List<Member>>() {
+            public int compare(List<Member> ma1, List<Member> ma2) {
+                for (int i = 0; i < ma1.size(); i++) {
+                    int c = ma1.get(i).compareTo(ma2.get(i));
                     if (c < 0) {
                         return c;
                     } else if (c > 0) {
@@ -148,14 +156,14 @@
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
-        Iterable<Member[]> iter = calc.makeIterable(l1, l2);
+        Iterable<List<Member>> iter = calc.makeIterable(l1, l2);
         String s = toString(iter);
         String e = "{[a,A],[a,B],[a,C],[a,D],[b,A],[b,B],[b,C],[b,D],[c,A],[c,B],[c,C],[c,D]}";
 //System.out.println("iter="+s);
         Assert.assertEquals(s, e);
     }
     ////////////////////////////////////////////////////////////////////////
-    // Member Member[]
+    // Member List<Member>
     ////////////////////////////////////////////////////////////////////////
 
     public void testIterMemberIterMemberArrayIterCalc() {
@@ -209,20 +217,20 @@
 //System.out.println("l1="+s1);
         Assert.assertEquals(s1, e1);
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
         Assert.assertEquals(s3, e3);
 
-        Iterable<Member[]> iter = calc.makeIterable(l1, l3);
+        Iterable<List<Member>> iter = calc.makeIterable(l1, l3);
         String s = toString(iter);
         String e = "{[a,k,l],[a,m,n],[b,k,l],[b,m,n],[c,k,l],[c,m,n]}";
 //System.out.println("iter="+s);
         Assert.assertEquals(s, e);
     }
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member
+    // List<Member> Member
     ////////////////////////////////////////////////////////////////////////
     public void testIterMemberArrayIterMemberIterCalc() {
 if (! Util.PreJdk15) {
@@ -268,7 +276,7 @@
     protected void doMemberArrayMemberIterTest(
             CrossJoinFunDef.BaseMemberArrayMemberIterCalc calc) {
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
@@ -280,14 +288,14 @@
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
-        Iterable<Member[]> iter = calc.makeIterable(l3, l2);
+        Iterable<List<Member>> iter = calc.makeIterable(l3, l2);
         String s = toString(iter);
         String e = "{[k,l,A],[k,l,B],[k,l,C],[k,l,D],[m,n,A],[m,n,B],[m,n,C],[m,n,D]}";
         Assert.assertEquals(s, e);
 //System.out.println("iter="+s);
     }
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member[]
+    // List<Member> List<Member>
     ////////////////////////////////////////////////////////////////////////
     public void testIterMemberArrayIterMemberArrayIterCalc() {
 if (! Util.PreJdk15) {
@@ -333,19 +341,19 @@
     protected void doMemberArrayMemberArrayIterTest(
             CrossJoinFunDef.BaseMemberArrayMemberArrayIterCalc calc) {
 
-        List<Member[]> l4 = makeListMemberArray(m4);
+        List<List<Member>> l4 = makeListMemberArray(m4);
         String s4 = toString(l4);
         String e4 = "{[U,V],[W,X],[Y,Z]}";
 //System.out.println("l4="+s4);
         Assert.assertEquals(s4, e4);
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
         Assert.assertEquals(s3, e3);
 
-        Iterable<Member[]> iter = calc.makeIterable(l4, l3);
+        Iterable<List<Member>> iter = calc.makeIterable(l4, l3);
         String s = toString(iter);
         String e = "{[U,V,k,l],[U,V,m,n],[W,X,k,l],[W,X,m,n],[Y,Z,k,l],[Y,Z,m,n]}";
 //System.out.println("iter="+s);
@@ -385,13 +393,13 @@
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
-        List<Member[]> list = calc.makeList(l1, l2);
+        List<List<Member>> list = calc.makeList(l1, l2);
         String s = toString(list);
         String e = "{[a,A],[a,B],[a,C],[a,D],[b,A],[b,B],[b,C],[b,D],[c,A],[c,B],[c,C],[c,D]}";
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        List<Member[]> subList = list.subList(0, 12);
+        List<List<Member>> subList = list.subList(0, 12);
         s = toString(subList);
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
@@ -460,7 +468,7 @@
         Assert.assertEquals(s, e);
     }
     ////////////////////////////////////////////////////////////////////////
-    // Member Member[]
+    // Member List<Member>
     ////////////////////////////////////////////////////////////////////////
     public void testImmutableListMemberListMemberArrayListCalc() {
         CrossJoinFunDef.ImmutableListMemberListMemberArrayListCalc calc =
@@ -480,19 +488,19 @@
 //System.out.println("l1="+s1);
         Assert.assertEquals(s1, e1);
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
         Assert.assertEquals(s3, e3);
 
-        List<Member[]> list = calc.makeList(l1, l3);
+        List<List<Member>> list = calc.makeList(l1, l3);
         String s = toString(list);
         String e = "{[a,k,l],[a,m,n],[b,k,l],[b,m,n],[c,k,l],[c,m,n]}";
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        List<Member[]> subList = list.subList(0, 6);
+        List<List<Member>> subList = list.subList(0, 6);
         s = toString(subList);
 //System.out.println("subList="+s);
 //System.out.println("expect ="+e);
@@ -540,7 +548,7 @@
     }
 
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member
+    // List<Member> Member
     ////////////////////////////////////////////////////////////////////////
     public void testImmutableListMemberArrayListMemberListCalc() {
         CrossJoinFunDef.ImmutableListMemberArrayListMemberListCalc calc =
@@ -554,7 +562,7 @@
     protected void doMemberArrayMemberListTest(
             CrossJoinFunDef.BaseListCalc calc) {
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
@@ -566,13 +574,13 @@
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
-        List<Member[]> list = calc.makeList(l3, l2);
+        List<List<Member>> list = calc.makeList(l3, l2);
         String s = toString(list);
         String e = "{[k,l,A],[k,l,B],[k,l,C],[k,l,D],[m,n,A],[m,n,B],[m,n,C],[m,n,D]}";
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        List<Member[]> subList = list.subList(0, 8);
+        List<List<Member>> subList = list.subList(0, 8);
         s = toString(subList);
 //System.out.println("subList="+s);
 //System.out.println("expect ="+e);
@@ -653,7 +661,7 @@
     }
 
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member[]
+    // List<Member> List<Member>
     ////////////////////////////////////////////////////////////////////////
 
     public void testImmutableListMemberArrayListMemberArrayListCalc() {
@@ -668,25 +676,25 @@
     protected void doMemberArrayMemberArrayListTest(
             CrossJoinFunDef.BaseListCalc calc) {
 
-        List<Member[]> l4 = makeListMemberArray(m4);
+        List<List<Member>> l4 = makeListMemberArray(m4);
         String s4 = toString(l4);
         String e4 = "{[U,V],[W,X],[Y,Z]}";
 //System.out.println("l4="+s4);
         Assert.assertEquals(s4, e4);
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
         Assert.assertEquals(s3, e3);
 
-        List<Member[]> list = calc.makeList(l4, l3);
+        List<List<Member>> list = calc.makeList(l4, l3);
         String s = toString(list);
         String e = "{[U,V,k,l],[U,V,m,n],[W,X,k,l],[W,X,m,n],[Y,Z,k,l],[Y,Z,m,n]}";
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        List<Member[]> subList = list.subList(0, 6);
+        List<List<Member>> subList = list.subList(0, 6);
         s = toString(subList);
 //System.out.println("subList="+s);
 //System.out.println("expect ="+e);
@@ -792,7 +800,7 @@
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
-        List<Member[]> list = calc.makeList(l1, l2);
+        List<List<Member>> list = calc.makeList(l1, l2);
         String s = toString(list);
         String e = "{[a,A],[a,B],[a,C],[a,D],[b,A],[b,B],[b,C],[b,D],[c,A],[c,B],[c,C],[c,D]}";
 //System.out.println("list="+s);
@@ -805,15 +813,15 @@
         Assert.assertEquals(s, e);
 
         // sort
-        Comparator<Member[]> c = new Comparator<Member[]>() {
-            public int compare(Member[] ma1, Member[] ma2) {
-                int c = ma1[0].compareTo(ma2[0]);
+        Comparator<List<Member>> c = new Comparator<List<Member>>() {
+            public int compare(List<Member> ma1, List<Member> ma2) {
+                int c = ma1.get(0).compareTo(ma2.get(0));
                 if (c < 0) {
                     return c;
                 } else if (c > 0) {
                     return c;
                 } else {
-                    return ma1[1].compareTo(ma2[1]);
+                    return ma1.get(1).compareTo(ma2.get(1));
                 }
             }
         };
@@ -823,7 +831,7 @@
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        Member[] members = list.remove(1);
+        List<Member> members = list.remove(1);
         String m = toString(members);
 //System.out.println("members="+m);
         s = toString(list);
@@ -833,7 +841,7 @@
     }
 
     ////////////////////////////////////////////////////////////////////////
-    // Member Member[]
+    // Member List<Member>
     ////////////////////////////////////////////////////////////////////////
     public void testMutableListMemberListMemberArrayListCalc() {
         CrossJoinFunDef.MutableListMemberListMemberArrayListCalc calc =
@@ -853,13 +861,13 @@
 //System.out.println("l1="+s1);
         Assert.assertEquals(s1, e1);
 
-        List<Member[]> l3 = makeListMemberArray(m3);
+        List<List<Member>> l3 = makeListMemberArray(m3);
         String s3 = toString(l3);
         String e3 = "{[k,l],[m,n]}";
 //System.out.println("l3="+s3);
         Assert.assertEquals(s3, e3);
 
-        List<Member[]> list = calc.makeList(l1, l3);
+        List<List<Member>> list = calc.makeList(l1, l3);
         String s = toString(list);
         String e = "{[a,k,l],[a,m,n],[b,k,l],[b,m,n],[c,k,l],[c,m,n]}";
 //System.out.println("list="+s);
@@ -878,7 +886,7 @@
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        Member[] members = list.remove(1);
+        List<Member> members = list.remove(1);
 //        String m = toString(members);
 //System.out.println("members="+m);
         s = toString(list);
@@ -888,7 +896,7 @@
     }
 
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member
+    // List<Member> Member
     ////////////////////////////////////////////////////////////////////////
     public void testMutableListMemberArrayListMemberListCalc() {
         CrossJoinFunDef.MutableListMemberArrayListMemberListCalc calc =
@@ -902,7 +910,7 @@
     protected void doMMemberArrayMemberListTest(
             CrossJoinFunDef.BaseListCalc calc) {
 
-        List<Member[]> l1 = makeListMemberArray(m3);
+        List<List<Member>> l1 = makeListMemberArray(m3);
         String s1 = toString(l1);
         String e1 = "{[k,l],[m,n]}";
 //System.out.println("l1="+s1);
@@ -915,7 +923,7 @@
         Assert.assertEquals(s2, e2);
 
 
-        List<Member[]> list = calc.makeList(l1, l2);
+        List<List<Member>> list = calc.makeList(l1, l2);
         String s = toString(list);
         String e = "{[k,l,a],[k,l,b],[k,l,c],[m,n,a],[m,n,b],[m,n,c]}";
 //System.out.println("list="+s);
@@ -934,7 +942,7 @@
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        Member[] members = list.remove(1);
+        List<Member> members = list.remove(1);
 //        String m = toString(members);
 //System.out.println("members="+m);
         s = toString(list);
@@ -944,7 +952,7 @@
     }
 
     ////////////////////////////////////////////////////////////////////////
-    // Member[] Member[]
+    // List<Member> List<Member>
     ////////////////////////////////////////////////////////////////////////
 
     public void testMutableListMemberArrayListMemberArrayListCalc() {
@@ -959,20 +967,20 @@
     protected void doMMemberArrayMemberArrayListTest(
             CrossJoinFunDef.BaseListCalc calc) {
 
-        List<Member[]> l1 = makeListMemberArray(m3);
+        List<List<Member>> l1 = makeListMemberArray(m3);
         String s1 = toString(l1);
         String e1 = "{[k,l],[m,n]}";
 //System.out.println("l1="+s1);
         Assert.assertEquals(s1, e1);
 
-        List<Member[]> l2 = makeListMemberArray(m4);
+        List<List<Member>> l2 = makeListMemberArray(m4);
         String s2 = toString(l2);
         String e2 = "{[U,V],[W,X],[Y,Z]}";
 //System.out.println("l2="+s2);
         Assert.assertEquals(s2, e2);
 
 
-        List<Member[]> list = calc.makeList(l1, l2);
+        List<List<Member>> list = calc.makeList(l1, l2);
         String s = toString(list);
         String e = "{[k,l,U,V],[k,l,W,X],[k,l,Y,Z],[m,n,U,V],[m,n,W,X],[m,n,Y,Z]}";
 //System.out.println("list="+s);
@@ -991,7 +999,7 @@
 //System.out.println("list="+s);
         Assert.assertEquals(s, e);
 
-        Member[] members = list.remove(1);
+        List<Member> members = list.remove(1);
 //        String m = toString(members);
 //System.out.println("members="+m);
         s = toString(list);
@@ -1013,7 +1021,7 @@
             if (o instanceof Member) {
                 buf.append(o);
             } else {
-                Member[] members = (Member[]) o;
+                List<Member> members = (List<Member>) o;
                 buf.append('[');
                 boolean firstTimeInner = true;
                 for (Member m: members) {
@@ -1030,7 +1038,7 @@
         buf.append('}');
         return buf.toString();
     }
-    protected String toString(Member[] members) {
+    protected String toString1(List<Member> members) {
         StringBuffer buf = new StringBuffer(100);
         buf.append('[');
         boolean firstTimeInner = true;
@@ -1044,16 +1052,16 @@
         buf.append(']');
         return buf.toString();
     }
-    protected List<Member> makeListMember(Member[] ms) {
+    protected List<Member> makeListMember(List<Member> ms) {
         List<Member> l = new ArrayList<Member>();
         for(Member member: ms) {
             l.add(member);
         }
         return l;
     }
-    protected List<Member[]> makeListMemberArray(Member[][] ms) {
-        List<Member[]> l = new ArrayList<Member[]>();
-        for(Member[] members: ms) {
+    protected List<List<Member>> makeListMemberArray(List<List<Member>> ms) {
+        List<List<Member>> l = new ArrayList<List<Member>>();
+        for(List<Member> members: ms) {
             l.add(members);
         }
         return l;
Index: testsrc/main/mondrian/rolap/RolapAxisTest.java
===================================================================
--- testsrc/main/mondrian/rolap/RolapAxisTest.java	
+++ testsrc/main/mondrian/rolap/RolapAxisTest.java	
@@ -13,6 +13,7 @@
 import mondrian.olap.fun.TestMember;
 import mondrian.olap.Member;
 import mondrian.olap.Position;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Iterator;
@@ -67,22 +68,22 @@
         Assert.assertEquals(s, e);
     }
     public void testMemberArrayList() {
-        List<Member[]> list = new ArrayList<Member[]>();
-        list.add(new Member[] {
+        List<List<Member>> list = new ArrayList<List<Member>>();
+        list.add(Arrays.asList(new Member[] {
             new TestMember("a"),
             new TestMember("b"),
             new TestMember("c")
-        });
-        list.add(new Member[] {
+        }));
+        list.add(Arrays.asList(new Member[] {
             new TestMember("d"),
             new TestMember("e"),
             new TestMember("f")
-        });
-        list.add(new Member[] {
+        }));
+        list.add(Arrays.asList(new Member[] {
             new TestMember("g"),
             new TestMember("h"),
             new TestMember("i")
-        });
+        }));
 
         StringBuffer buf = new StringBuffer(100);
 
@@ -163,22 +164,22 @@
         Assert.assertEquals(s, e);
     }
     public void testMemberArrayIterable() {
-        List<Member[]> list = new ArrayList<Member[]>();
-        list.add(new Member[] {
+        List<List<Member>> list = new ArrayList<List<Member>>();
+        list.add(Arrays.asList(new Member[]{
             new TestMember("a"),
             new TestMember("b"),
             new TestMember("c")
-        });
-        list.add(new Member[] {
+        }));
+        list.add(Arrays.asList(new Member[] {
             new TestMember("d"),
             new TestMember("e"),
             new TestMember("f")
-        });
-        list.add(new Member[] {
+        }));
+        list.add(Arrays.asList(new Member[] {
             new TestMember("g"),
             new TestMember("h"),
             new TestMember("i")
-        });
+        }));
 
         StringBuffer buf = new StringBuffer(100);
 
Index: testsrc/main/mondrian/rolap/DataSourceChangeListenerTest.java
===================================================================
--- testsrc/main/mondrian/rolap/DataSourceChangeListenerTest.java	
+++ testsrc/main/mondrian/rolap/DataSourceChangeListenerTest.java	
@@ -15,6 +15,7 @@
 
 import mondrian.olap.Id;
 import mondrian.olap.Connection;
+import mondrian.olap.Member;
 import mondrian.olap.Query;
 import mondrian.olap.Result;
 import mondrian.olap.Util;
@@ -90,11 +91,11 @@
         smr.mapLevelToMembers.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapLevel, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapMemberToChildren.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapMember, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapKeyToMember = new HardSmartCache<Object, RolapMember>();
 
         // Create a dummy DataSource which will throw a 'bomb' if it is asked
Index: testsrc/main/mondrian/rolap/HighDimensionsTest.java
===================================================================
--- testsrc/main/mondrian/rolap/HighDimensionsTest.java	
+++ testsrc/main/mondrian/rolap/HighDimensionsTest.java	
@@ -0,0 +1,164 @@
+/*
+// $Id: //open/mondrian/testsrc/main/mondrian/rolap/NoCacheHighDimensionsTest.java#7 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2006-2007 Julian Hyde
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.rolap;
+
+import mondrian.calc.ResultStyle;
+import mondrian.olap.*;
+import mondrian.olap.*;
+import mondrian.test.FoodMartTestCase;
+import mondrian.test.TestContext;
+import mondrian.test.DiffRepository;
+
+import java.util.*;
+import java.lang.ref.*;
+
+/**
+ * Unit-test for non cacheable elementos of high dimensions.
+ *
+ * @author jlopez, lcanals
+ * @version $Id: //open/mondrian/testsrc/main/mondrian/rolap/NoCacheHighDimensionsTest.java#7 $
+ * @since Oct, 2007
+ */
+public class HighDimensionsTest extends FoodMartTestCase {
+    public HighDimensionsTest() {
+
+    }
+
+    public HighDimensionsTest(String name) {
+        super(name);
+    }
+
+    
+    public void testPromotionsTwoDimensions() throws Exception {
+        execHighCardTest("select {[Measures].[Unit Sales]} on columns,\n"
+                    + "{[Promotions].[Promotion Name].Members} on rows\n"
+                    + "from [Sales Ragged]", 1);
+    }
+
+
+
+    //
+    // Private Stuff --------------------------------------------
+    //
+
+    /**
+     * Executes query test trying to [Promotions].[Promotion Name] elements
+     * into an axis from the results.
+     */
+    private void execHighCardTest(final String queryString, final int axisIndex)
+            throws Exception {
+        final int old = MondrianProperties.instance()
+                    .ResultLimit.get();
+        try {
+            MondrianProperties.instance().ResultLimit.set(40);
+            final Connection connection =
+                    TestContext.instance().getFoodMartConnection();
+            Query query = connection.parseQuery(queryString);
+            query.setResultStyle(ResultStyle.ITERABLE);
+            Result result = connection.execute(query);
+            final StringBuffer buffer = new StringBuffer();
+
+            final List<SoftReference> softReferences = 
+                    new ArrayList<SoftReference>();
+            // Tests results aren't got from database before this point 
+            int ii = 0;
+            for(final Position o : result.getAxes()[axisIndex].getPositions()) {
+                assertNotNull(o.get(0));
+                ii++;
+                softReferences.add(new SoftReference(o.get(0)));
+                buffer.append(o.get(0).toString());
+            }
+            assertEquals(buffer.toString(), highCardResults);
+ 
+            // Tests that really results over ResultLimit are erased from 
+            // memory
+            final List overloader = new ArrayList();
+            try {
+                for(;;) overloader.add(new long[99999999]);
+            } catch(OutOfMemoryError out) {
+                // OK, outofmemory
+            }
+            System.gc();
+
+            for(int i=5; i<10; i++) {
+                assertNull(softReferences.get(i).get());
+            }
+
+            for(int i=0; i<10; i++) {
+                try {
+                    result.getAxes()[axisIndex].getPositions().get(0).get(0);
+                    assert false;
+                } catch(RuntimeException nsee) {
+                }
+            }
+
+            assertEquals(51, result.getAxes()[axisIndex].getPositions().size());
+        } finally {
+            MondrianProperties.instance().ResultLimit.set(old);
+        }
+    }
+
+
+
+    private static final String highCardResults =
+                "[Promotions].[All Promotions].[Bag Stuffers]"
+                + "[Promotions].[All Promotions].[Best Savings]"
+                + "[Promotions].[All Promotions].[Big Promo]"
+                + "[Promotions].[All Promotions].[Big Time Discounts]"
+                + "[Promotions].[All Promotions].[Big Time Savings]"
+                + "[Promotions].[All Promotions].[Bye Bye Baby]"
+                + "[Promotions].[All Promotions].[Cash Register Lottery]"
+                + "[Promotions].[All Promotions].[Coupon Spectacular]"
+                + "[Promotions].[All Promotions].[Dimes Off]"
+                + "[Promotions].[All Promotions].[Dollar Cutters]"
+                + "[Promotions].[All Promotions].[Dollar Days]"
+                + "[Promotions].[All Promotions].[Double Down Sale]"
+                + "[Promotions].[All Promotions].[Double Your Savings]"
+                + "[Promotions].[All Promotions].[Fantastic Discounts]"
+                + "[Promotions].[All Promotions].[Free For All]"
+                + "[Promotions].[All Promotions].[Go For It]"
+                + "[Promotions].[All Promotions].[Green Light Days]"
+                + "[Promotions].[All Promotions].[Green Light Special]"
+                + "[Promotions].[All Promotions].[High Roller Savings]"
+                + "[Promotions].[All Promotions].[I Cant Believe It Sale]"
+                + "[Promotions].[All Promotions].[Money Grabbers]"
+                + "[Promotions].[All Promotions].[Money Savers]"
+                + "[Promotions].[All Promotions].[Mystery Sale]"
+                + "[Promotions].[All Promotions].[No Promotion]"
+                + "[Promotions].[All Promotions].[One Day Sale]"
+                + "[Promotions].[All Promotions].[Pick Your Savings]"
+                + "[Promotions].[All Promotions].[Price Cutters]"
+                + "[Promotions].[All Promotions].[Price Destroyers]"
+                + "[Promotions].[All Promotions].[Price Savers]"
+                + "[Promotions].[All Promotions].[Price Slashers]"
+                + "[Promotions].[All Promotions].[Price Smashers]"
+                + "[Promotions].[All Promotions].[Price Winners]"
+                + "[Promotions].[All Promotions].[Sale Winners]"
+                + "[Promotions].[All Promotions].[Sales Days]"
+                + "[Promotions].[All Promotions].[Sales Galore]"
+                + "[Promotions].[All Promotions].[Save-It Sale]"
+                + "[Promotions].[All Promotions].[Saving Days]"
+                + "[Promotions].[All Promotions].[Savings Galore]"
+                + "[Promotions].[All Promotions].[Shelf Clearing Days]"
+                + "[Promotions].[All Promotions].[Shelf Emptiers]"
+                + "[Promotions].[All Promotions].[Super Duper Savers]"
+                + "[Promotions].[All Promotions].[Super Savers]"
+                + "[Promotions].[All Promotions].[Super Wallet Savers]"
+                + "[Promotions].[All Promotions].[Three for One]"
+                + "[Promotions].[All Promotions].[Tip Top Savings]"
+                + "[Promotions].[All Promotions].[Two Day Sale]"
+                + "[Promotions].[All Promotions].[Two for One]"
+                + "[Promotions].[All Promotions].[Unbeatable Price Savers]"
+                + "[Promotions].[All Promotions].[Wallet Savers]"
+                + "[Promotions].[All Promotions].[Weekend Markdown]"
+                + "[Promotions].[All Promotions].[You Save Days]";
+
+
+}
Index: testsrc/main/mondrian/rolap/NonEmptyTest.java
===================================================================
--- testsrc/main/mondrian/rolap/NonEmptyTest.java	
+++ testsrc/main/mondrian/rolap/NonEmptyTest.java	
@@ -14,6 +14,7 @@
 import java.util.ArrayList;
 
 import junit.framework.Assert;
+import mondrian.calc.ResultStyle;
 import mondrian.olap.Axis;
 import mondrian.olap.Cell;
 import mondrian.olap.Connection;
@@ -920,7 +921,6 @@
                 "select {[Measures].[Store Sales]} ON COLUMNS, "
                         + "NON EMPTY Crossjoin([Product].[(All)].Members, [Promotion Media].[All Media].Children) ON ROWS "
                         + "from [Sales]");
-
     }
 
     /**
@@ -1584,11 +1584,11 @@
         smr.mapLevelToMembers.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapLevel, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapMemberToChildren.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapMember, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         // smr.mapKeyToMember = new HardSmartCache();
         smr.mapKeyToMember.clear();
         RolapResult result = (RolapResult) executeQuery(
@@ -1731,11 +1731,11 @@
         smr.mapLevelToMembers.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapLevel, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapMemberToChildren.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapMember, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         TestCase c = new TestCase(
                 50,
                 21,
@@ -1782,11 +1782,11 @@
         smr.mapLevelToMembers.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapLevel, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapMemberToChildren.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapMember, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         Result r = executeQuery("select \n"
                 + "{[Measures].[Unit Sales]} ON columns,\n"
                 + "{[Customers].[All Customers], [Customers].[Name].Members} ON rows\n"
@@ -1956,11 +1956,11 @@
         smr.mapLevelToMembers.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapLevel, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         smr.mapMemberToChildren.setCache(
             new HardSmartCache<
                 SmartMemberListCache.Key2<RolapMember, Object>,
-                List<RolapMember>>());
+                List<? extends Member>>());
         TestCase c = new TestCase(
                 con,
                 45,
@@ -3144,6 +3144,7 @@
 
     Result executeQuery(String mdx, Connection connection) {
         Query query = connection.parseQuery(mdx);
+        query.setResultStyle(ResultStyle.LIST);
         return connection.execute(query);
     }
 
Index: testsrc/main/mondrian/rolap/BatchTestCase.java
===================================================================
--- testsrc/main/mondrian/rolap/BatchTestCase.java	
+++ testsrc/main/mondrian/rolap/BatchTestCase.java	
@@ -18,8 +18,7 @@
 import mondrian.rolap.sql.SqlQuery;
 import mondrian.olap.*;
 
-import java.util.List;
-import java.util.ArrayList;
+import java.util.*;
 
 /**
  * To support all <code>Batch</code> related tests.
@@ -111,7 +110,7 @@
                 fieldValues, cubeName,
                 measure);
         GroupingSetsCollector collector = new GroupingSetsCollector(true);
-        batch.loadAggregation(collector);
+        batch.loadAggregation(collector, null);
         return collector.getGroupingSets().get(0);
     }
 
@@ -157,25 +156,23 @@
             // Create a dummy DataSource which will throw a 'bomb' if it is
             // asked to execute a particular SQL statement, but will otherwise
             // behave exactly the same as the current DataSource.
-            RolapUtil.threadHooks.set(new TriggerHook(trigger));
-            Bomb bomb;
-            try {
-                FastBatchingCellReader fbcr =
-                    new FastBatchingCellReader(getCube(cubeName));
-                for (CellRequest request : requests) {
-                    fbcr.recordCellRequest(request);
-                }
-                fbcr.loadAggregations();
-                bomb = null;
-            } catch (Bomb e) {
-                bomb = e;
-            } finally {
-                RolapUtil.threadHooks.set(null);
+            final String[] sqlDetected = new String[1];
+            final Observer observer = new Observer() {
+                    public void update(final Observable o, final Object arg) {
+                        sqlDetected[0] = (String) arg;
+                    }
+                };
+            RolapUtil.threadHooks.set(new TriggerHook(trigger, observer));
+            FastBatchingCellReader fbcr =
+                new FastBatchingCellReader(getCube(cubeName));
+            for (CellRequest request : requests) {
+                fbcr.recordCellRequest(request);
             }
-            assertTrue(bomb != null);
-            TestContext.assertEqualsVerbose(
-                replaceQuotes(sql),
-                replaceQuotes(bomb.sql));
+            fbcr.loadAggregations();
+            RolapUtil.threadHooks.set(null);
+            assertTrue(sqlDetected[0]!=null);
+            TestContext.assertEqualsVerbose(replaceQuotes(sql),
+                replaceQuotes(sqlDetected[0]));
         }
     }
 
@@ -274,27 +271,26 @@
             // Create a dummy DataSource which will throw a 'bomb' if it is
             // asked to execute a particular SQL statement, but will otherwise
             // behave exactly the same as the current DataSource.
-            RolapUtil.threadHooks.set(new TriggerHook(trigger));
+            final String[] detectedSql = new String[1];
+            final Observer observer = new Observer() {
+                    public void update(final Observable o, final Object arg) {
+                        detectedSql[0] = (String) arg;
+                    }
+                };
+            RolapUtil.threadHooks.set(new TriggerHook(trigger, observer));
 
-            Bomb bomb;
-            try {
-                final Result result = connection.execute(query);
-                Util.discard(result);
-                bomb = null;
-            } catch (Bomb e) {
-                bomb = e;
-            } finally {
-                RolapUtil.threadHooks.set(null);
-            }
+            final Result result = connection.execute(query);
+            Util.discard(result);
+            RolapUtil.threadHooks.set(null);
             if (negative) {
-                if (bomb != null) {
+                if (detectedSql[0]!= null) {
                     fail("forbidden query [" + sql + "] detected");
                 }
             } else {
-                if (bomb == null) {
+                if (detectedSql[0] == null) {
                     fail("expected query [" + sql + "] did not occur");
                 }
-                assertEquals(replaceQuotes(sql), replaceQuotes(bomb.sql));
+                assertEquals(replaceQuotes(sql), replaceQuotes(detectedSql[0]));
             }
         }
     }
@@ -385,25 +381,14 @@
         return (RolapCube) connection.getSchema().lookupCube(cube, fail);
     }
 
-    /**
-     * Fake exception to interrupt the test when we see the desired query.
-     * It is an {@link Error} because we need it to be unchecked
-     * ({@link Exception} is checked), and we don't want handlers to handle
-     * it.
-     */
-    static class Bomb extends Error {
-        final String sql;
 
-        Bomb(final String sql) {
-            this.sql = sql;
-        }
-    }
-
     private static class TriggerHook implements RolapUtil.ExecuteQueryHook {
         private final String trigger;
+        private final Observer observer;
 
-        public TriggerHook(String trigger) {
+        public TriggerHook(String trigger, final Observer observer) {
             this.trigger = trigger;
+            this.observer = observer;
         }
 
         private boolean matchTrigger(String sql) {
@@ -419,7 +404,7 @@
 
         public void onExecuteQuery(String sql) {
             if (matchTrigger(sql)) {
-                throw new Bomb(sql);
+                observer.update(null, sql);
             }
         }
     }
Index: testsrc/main/mondrian/rolap/FastBatchingCellReaderTest.java
===================================================================
--- testsrc/main/mondrian/rolap/FastBatchingCellReaderTest.java	
+++ testsrc/main/mondrian/rolap/FastBatchingCellReaderTest.java	
@@ -705,7 +705,7 @@
             };
         compositeBatch.add(summaryBatch);
 
-        compositeBatch.loadAggregation();
+        compositeBatch.loadAggregation(null);
 
         assertEquals(2, groupingSets.size());
         assertEquals(detailedBatch.constrainedColumnsBitKey,
Index: testsrc/main/mondrian/util/CacheMapTest.java
===================================================================
--- testsrc/main/mondrian/util/CacheMapTest.java	
+++ testsrc/main/mondrian/util/CacheMapTest.java	
@@ -0,0 +1,31 @@
+/*
+// $Id: //open/mondrian/testsrc/main/mondrian/util/Base64Test.java#2 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2006-2006 Julian Hyde and others
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+
+package mondrian.util;
+
+import java.util.*;
+import junit.framework.TestCase;
+
+/**
+ * Test case for {@link CacheMap}.
+ *
+ * @version $Id: //open/mondrian/testsrc/main/mondrian/util/CacheMapTest.java#2 $
+ * @author luis f. canals
+ */
+public class CacheMapTest extends TestCase {
+    public void testOverload() throws Exception {
+        final Map<Integer, int[]> cache = new CacheMap<Integer, int[]>(10);
+        for(int i=0; i<1024; i++) {
+            final int[] kk = new int[999999];
+            cache.put(i, kk);
+        }
+    }
+}
Index: testsrc/queryFiles/queryTest_memberOrdinal.xml
===================================================================
--- testsrc/queryFiles/queryTest_memberOrdinal.xml	
+++ testsrc/queryFiles/queryTest_memberOrdinal.xml	
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mdbTest>
+    <mdxQuery>select {[Product]} on columns, Hierarchize(crossjoin([Measures].allMembers, [Time].children)) on rows from [Sales 2]</mdxQuery>
+    <dataResult>
+        <slicer>
+            <dimensions>
+                <dim>[Time]</dim>
+                <dim>[Product]</dim>
+            </dimensions>
+            <tuples>
+                <tuple>
+                    <member>[Time].[1997]</member>
+                    <member>[Product].[All Products]</member>
+                </tuple>
+            </tuples>
+        </slicer>
+        <columns>
+            <dimensions>
+                <dim>[Product]</dim>
+            </dimensions>
+            <tuples>
+                <tuple>
+                    <member>[Product].[All Products]</member>
+                </tuple>
+            </tuples>
+        </columns>
+        <rows>
+            <dimensions>
+                <dim>[Measures]</dim>
+                <dim>[Time]</dim>
+            </dimensions>
+            <tuples>
+                <tuple>
+                    <member>[Measures].[Sales Count]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Sales Count]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Sales Count]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Sales Count]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Unit Sales]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Unit Sales]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Unit Sales]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Unit Sales]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Store Sales]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Sales]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Sales]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Sales]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Profit]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Profit last Period]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit last Period]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit last Period]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Profit last Period]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Store Cost]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Cost]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Cost]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Store Cost]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+                <tuple>
+                    <member>[Measures].[Customer Count]</member>
+                    <member>[Time].[1997].[Q1]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Customer Count]</member>
+                    <member>[Time].[1997].[Q2]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Customer Count]</member>
+                    <member>[Time].[1997].[Q3]</member>
+                </tuple>
+                <tuple>
+                    <member>[Measures].[Customer Count]</member>
+                    <member>[Time].[1997].[Q4]</member>
+                </tuple>
+
+            </tuples>
+        </rows>
+
+        <data>
+            <drow>
+                <cell>21588</cell>
+            </drow>
+            <drow>
+                <cell>20368</cell>
+            </drow>
+            <drow>
+                <cell>21453</cell>
+            </drow>
+            <drow>
+               <cell>23428</cell>
+            </drow>
+
+            <drow>
+               <cell>66291</cell>
+            </drow>
+            <drow>
+               <cell>62610</cell>
+            </drow>
+            <drow>
+               <cell>65848</cell>
+            </drow>
+            <drow>
+               <cell>72024</cell>
+            </drow>
+
+            <drow>
+               <cell>139628.35</cell>
+            </drow>
+            <drow>
+               <cell>132666.27</cell>
+            </drow>
+            <drow>
+               <cell>140271.89</cell>
+            </drow>
+            <drow>
+               <cell>152671.62</cell>
+            </drow>
+
+            <drow>
+               <cell>83876.11</cell>
+            </drow>
+            <drow>
+               <cell>79702.0452</cell>
+            </drow>
+            <drow>
+               <cell>84367.02</cell>
+            </drow>
+            <drow>
+               <cell>91665.7211</cell>
+            </drow>
+
+            <drow>
+               <cell>83876.11</cell>
+            </drow>
+            <drow>
+               <cell>83876.11</cell>
+            </drow>
+            <drow>
+               <cell>79702.0452</cell>
+            </drow>
+            <drow>
+               <cell>84367.02</cell>
+            </drow>
+
+            <drow>
+               <cell>55752.24</cell>
+            </drow>
+            <drow>
+               <cell>52964.2248</cell>
+            </drow>
+            <drow>
+               <cell>55904.87</cell>
+            </drow>
+            <drow>
+               <cell>61005.8989</cell>
+            </drow>
+
+            <drow>
+               <cell>2981</cell>
+            </drow>
+            <drow>
+               <cell>2973</cell>
+            </drow>
+            <drow>
+               <cell>3026</cell>
+            </drow>
+            <drow>
+               <cell>3261</cell>
+            </drow>
+        </data>
+
+    </dataResult>
+</mdbTest>
Index: src/main/mondrian/tui/CmdRunner.java
===================================================================
--- src/main/mondrian/tui/CmdRunner.java	
+++ src/main/mondrian/tui/CmdRunner.java	
@@ -752,6 +752,7 @@
             try {
                 in.close();
             } catch (Exception ex) {
+ex.printStackTrace();
                 // ignore
             }
         }
@@ -1507,6 +1508,7 @@
                             this.connectString = null;
                         }
                     } catch (Exception ex) {
+ex.printStackTrace();
                         setError(ex);
                     }
                 } else {
@@ -1659,6 +1661,7 @@
                 try {
                     commandLoop(new File(this.filename));
                 } catch (IOException ex) {
+ex.printStackTrace();
                     setError(ex);
                     buf.append("Error: ").append(ex);
                 }
@@ -2064,6 +2067,7 @@
             return resultString;
 
         } catch (Exception ex) {
+ex.printStackTrace();
             setError(ex);
             //return error;
             return null;
@@ -2208,6 +2212,7 @@
                     buf.append(resultString);
 
                 } catch (Exception ex) {
+ex.printStackTrace();
                     setError(ex);
                     buf.append("Error: ").append(ex);
                 }
@@ -2246,6 +2251,7 @@
             return resultString;
 
         } catch (Exception ex) {
+ex.printStackTrace();
             setError(ex);
             //return error;
             return null;
Index: src/main/mondrian/xmla/XmlaHandler.java
===================================================================
--- src/main/mondrian/xmla/XmlaHandler.java	
+++ src/main/mondrian/xmla/XmlaHandler.java	
@@ -1259,8 +1259,9 @@
             final String advancedFlag =
                 properties.get(PropertyDefinition.AdvancedFlag.name());
             if ("true".equals(advancedFlag)) {
-                final Position position = result.getAxes()[0].getPositions().get(0);
-                Member[] members = position.toArray(new Member[position.size()]);
+                final Position position = result.getAxes()[0]
+                        .getPositions().get(0);
+                List<Member> members = position;
 
                 final CellRequest cellRequest =
                     RolapAggregationManager.makeRequest(members);
Index: src/main/mondrian/xmla/RowsetDefinition.java
===================================================================
--- src/main/mondrian/xmla/RowsetDefinition.java	
+++ src/main/mondrian/xmla/RowsetDefinition.java	
@@ -2283,9 +2283,9 @@
                         }
                     }
 
-                    RolapMember[] rms = cube.getMeasuresMembers();
-                    for (int k = 1; k < rms.length; k++) {
-                        RolapMember member = rms[k];
+                    List<? extends Member> rms = cube.getMeasuresMembers();
+                    for (int k = 1; k < rms.size(); k++) {
+                        Member member = rms.get(k);
 
                         // null == true for regular cubes
                         // virtual cubes do not set the visible property
@@ -4988,8 +4988,8 @@
                     }
                     String levelListStr = buf.toString();
 
-                    Member[] storedMembers =
-                        schemaReader.getLevelMembers(measuresLevel, false);
+                    Member[] storedMembers = schemaReader.getLevelMembers(
+                            measuresLevel, false).toArray(new Member[0]);
                     for (Member member : storedMembers) {
                         String name = member.getName();
                         String unique = member.getUniqueName();
@@ -5373,8 +5373,9 @@
                     }
                     // Get members of this level, without access control, but
                     // including calculated members.
-                    Member[] members =
-                        cube.getSchemaReader(null).getLevelMembers(level, true);
+                    final List<? extends Member> members = 
+                            cube.getSchemaReader(null)
+                            .getLevelMembers(level,true);
                     outputMembers(
                         schemaReader, members, catalogName, cube, rows);
                 }
@@ -5437,17 +5438,17 @@
                 }
 
                 Level level = levels[levelNumber];
-                Member[] members =
-                    schemaReader.getLevelMembers(level, false);
+                final List<? extends Member> members = 
+                        schemaReader.getLevelMembers(level, false);
                 outputMembers(schemaReader, members, catalogName, cube, rows);
             } else {
                 // At this point we get ALL of the members associated with
                 // the Hierarchy (rather than getting them one at a time).
                 // The value returned is not used at this point but they are
                 // now cached in the SchemaReader.
-                Member[][] membersArray =
-                    RolapMember.getAllMembers(schemaReader, hierarchy);
-                for (Member[] members : membersArray) {
+                List<List<? extends Member>> membersArray =
+                        RolapMember.getAllMembers(schemaReader, hierarchy);
+                for(List<? extends Member> members : membersArray) {
                     outputMembers(schemaReader, members,
                         catalogName, cube, rows);
                 }
@@ -5483,10 +5484,10 @@
             if (mask(treeOp, Enumeration.TreeOp.Siblings.userOrdinal())) {
                 final Member parent =
                     schemaReader.getMemberParent(member);
-                final Member[] siblings = (parent == null)
-                    ?  schemaReader.getHierarchyRootMembers(member.getHierarchy())
+                final List<? extends Member> siblings = (parent == null)
+                    ?  schemaReader.getHierarchyRootMembers
+                            (member.getHierarchy())
                     : schemaReader.getMemberChildren(parent);
-
                 for (Member sibling : siblings) {
                     if (sibling == member) {
                         continue;
@@ -5499,7 +5500,8 @@
             }
             // Visit node's descendants or its immediate children, but not both.
             if (mask(treeOp, Enumeration.TreeOp.Descendants.userOrdinal())) {
-                final Member[] children = schemaReader.getMemberChildren(member);
+                final List<? extends Member> children = 
+                        schemaReader.getMemberChildren(member);
                 for (Member child : children) {
                     populateMember(
                         schemaReader, catalogName,
@@ -5508,9 +5510,9 @@
                             Enumeration.TreeOp.Descendants.userOrdinal(),
                         rows);
                 }
-            } else if (mask(treeOp, Enumeration.TreeOp.Children.userOrdinal())) {
-                final Member[] children =
-                    schemaReader.getMemberChildren(member);
+            } else if (mask(treeOp,Enumeration.TreeOp.Children.userOrdinal())) {
+                final List<? extends Member> children =
+                        schemaReader.getMemberChildren(member);
                 for (Member child : children) {
                     populateMember(
                         schemaReader, catalogName,
@@ -5551,12 +5553,9 @@
             return list;
         }
 
-        private void outputMembers(
-            final SchemaReader schemaReader,
-            Member[] members,
-            final String catalogName,
-            Cube cube, List<Row> rows) {
-
+        private void outputMembers(final SchemaReader schemaReader,
+                final List<? extends Member> members, final String catalogName,
+                final Cube cube, final List<Row> rows) {
             for (Member member : members) {
                 outputMember(schemaReader, member, catalogName, cube, rows);
             }
Index: src/main/mondrian/calc/TupleCalc.java
===================================================================
--- src/main/mondrian/calc/TupleCalc.java	
+++ src/main/mondrian/calc/TupleCalc.java	
@@ -11,6 +11,7 @@
 
 import mondrian.olap.Member;
 import mondrian.olap.Evaluator;
+import java.util.*;
 
 /**
  * Expression which yields a tuple.
@@ -37,7 +38,7 @@
      * @param evaluator Evaluation context
      * @return an array of members, or null to represent the null tuple
      */
-    Member[] evaluateTuple(Evaluator evaluator);
+    List<Member> evaluateTuple(Evaluator evaluator);
 }
 
 // End TupleCalc.java
Index: src/main/mondrian/calc/impl/AbstractTupleCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractTupleCalc.java	
+++ src/main/mondrian/calc/impl/AbstractTupleCalc.java	
@@ -43,6 +43,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractTupleCalc type object"; }
 }
 
 // End AbstractTupleCalc.java
Index: src/main/mondrian/calc/impl/AbstractIntegerCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractIntegerCalc.java	
+++ src/main/mondrian/calc/impl/AbstractIntegerCalc.java	
@@ -45,6 +45,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractIntegerCalc type object"; }
 }
 
 // End AbstractIntegerCalc.java
Index: src/main/mondrian/calc/impl/AbstractVoidCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractVoidCalc.java	
+++ src/main/mondrian/calc/impl/AbstractVoidCalc.java	
@@ -41,6 +41,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractVoidCalc type object"; }
 }
 
 // End AbstractVoidCalc.java
Index: src/main/mondrian/calc/impl/TupleValueCalc.java
===================================================================
--- src/main/mondrian/calc/impl/TupleValueCalc.java	
+++ src/main/mondrian/calc/impl/TupleValueCalc.java	
@@ -15,6 +15,8 @@
 import mondrian.calc.impl.MemberValueCalc;
 import mondrian.calc.*;
 
+import java.util.*;
+
 /**
  * Expression which evaluates a tuple expression,
  * sets the dimensional context to the result of that expression,
@@ -32,22 +34,22 @@
  */
 public class TupleValueCalc extends GenericCalc {
     private final TupleCalc tupleCalc;
-    private final Member[] savedMembers;
+    private final List<Member> savedMembers;
 
     public TupleValueCalc(Exp exp, TupleCalc tupleCalc) {
         super(exp);
         this.tupleCalc = tupleCalc;
         final TupleType tupleType = (TupleType) this.tupleCalc.getType();
-        this.savedMembers = new Member[tupleType.elementTypes.length];
+        this.savedMembers = new ArrayList<Member>();
     }
 
     public Object evaluate(Evaluator evaluator) {
-        final Member[] members = tupleCalc.evaluateTuple(evaluator);
+        final List<Member> members = tupleCalc.evaluateTuple(evaluator);
         if (members == null) {
             return null;
         }
-        for (int i = 0; i < members.length; i++) {
-            savedMembers[i] = evaluator.setContext(members[i]);
+        for (int i = 0; i < members.size(); i++) {
+            savedMembers.add(evaluator.setContext(members.get(i)));
         }
         final Object o = evaluator.evaluateCurrent();
         evaluator.setContext(savedMembers);
Index: src/main/mondrian/calc/impl/AbstractIterCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractIterCalc.java	
+++ src/main/mondrian/calc/impl/AbstractIterCalc.java	
@@ -59,6 +59,8 @@
     public ResultStyle getResultStyle() {
         return ResultStyle.ITERABLE;
     }
+
+    public String toString() { return "AbstractIterCalc type object"; }
 }
 
 // End AbstractIterCalc.java
Index: src/main/mondrian/calc/impl/ConstantCalc.java
===================================================================
--- src/main/mondrian/calc/impl/ConstantCalc.java	
+++ src/main/mondrian/calc/impl/ConstantCalc.java	
@@ -146,6 +146,8 @@
                 DimensionType.forDimension(dimension),
                 dimension);
     }
+
+    public String toString() { return "ConstantCalc object"; }
 }
 
 // End ConstantCalc.java
Index: src/main/mondrian/calc/impl/AbstractStringCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractStringCalc.java	
+++ src/main/mondrian/calc/impl/AbstractStringCalc.java	
@@ -43,6 +43,9 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractStringCalc type object"; }
+
 }
 
 // End AbstractStringCalc.java
Index: src/main/mondrian/calc/impl/AbstractMemberCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractMemberCalc.java	
+++ src/main/mondrian/calc/impl/AbstractMemberCalc.java	
@@ -45,6 +45,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractMemberCalc type object"; }
 }
 
 // End AbstractMemberCalc.java
Index: src/main/mondrian/calc/impl/AbstractLevelCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractLevelCalc.java	
+++ src/main/mondrian/calc/impl/AbstractLevelCalc.java	
@@ -45,6 +45,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractLevelCalc type object"; }
 }
 
 // End AbstractLevelCalc.java
Index: src/main/mondrian/calc/impl/AbstractDoubleCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractDoubleCalc.java	
+++ src/main/mondrian/calc/impl/AbstractDoubleCalc.java	
@@ -49,6 +49,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractDoubleCalc type object"; }
 }
 
 // End AbstractDoubleCalc.java
Index: src/main/mondrian/calc/impl/AbstractListCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractListCalc.java	
+++ src/main/mondrian/calc/impl/AbstractListCalc.java	
@@ -78,6 +78,8 @@
             ResultStyle.MUTABLE_LIST :
             ResultStyle.LIST;
     }
+
+    public String toString() { return "AbstractListCalc type object"; }
 }
 
 // End AbstractListCalc.java
Index: src/main/mondrian/calc/impl/AbstractHierarchyCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractHierarchyCalc.java	
+++ src/main/mondrian/calc/impl/AbstractHierarchyCalc.java	
@@ -45,6 +45,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractHierarchyCalc type object"; }
 }
 
 // End AbstractHierarchyCalc.java
Index: src/main/mondrian/calc/impl/AbstractCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractCalc.java	
+++ src/main/mondrian/calc/impl/AbstractCalc.java	
@@ -218,6 +218,8 @@
     public ResultStyle getResultStyle() {
         return ResultStyle.VALUE;
     }
+
+    public String toString() { return "AbstractCalc type object"; }
 }
 
 // End AbstractCalc.java
Index: src/main/mondrian/calc/impl/AbstractBooleanCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractBooleanCalc.java	
+++ src/main/mondrian/calc/impl/AbstractBooleanCalc.java	
@@ -44,6 +44,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractBooleanCalc type object"; }
 }
 
 // End AbstractBooleanCalc.java
Index: src/main/mondrian/calc/impl/MemberValueCalc.java
===================================================================
--- src/main/mondrian/calc/impl/MemberValueCalc.java	
+++ src/main/mondrian/calc/impl/MemberValueCalc.java	
@@ -14,6 +14,8 @@
 import mondrian.olap.type.ScalarType;
 import mondrian.calc.*;
 
+import java.util.Arrays;
+
 /**
  * Expression which evaluates a few member expressions,
  * sets the dimensional context to the result of those expressions,
@@ -57,7 +59,7 @@
             savedMembers[i] = evaluator.setContext(member);
         }
         final Object o = evaluator.evaluateCurrent();
-        evaluator.setContext(savedMembers);
+        evaluator.setContext(Arrays.asList(savedMembers));
         return o;
     }
 
Index: src/main/mondrian/calc/impl/AbstractDimensionCalc.java
===================================================================
--- src/main/mondrian/calc/impl/AbstractDimensionCalc.java	
+++ src/main/mondrian/calc/impl/AbstractDimensionCalc.java	
@@ -44,6 +44,8 @@
     public Calc[] getCalcs() {
         return calcs;
     }
+
+    public String toString() { return "AbstractDimensionCalc object"; }
 }
 
 // End AbstractMemberCalc.java
Index: src/main/mondrian/calc/impl/BetterExpCompiler.java
===================================================================
--- src/main/mondrian/calc/impl/BetterExpCompiler.java	
+++ src/main/mondrian/calc/impl/BetterExpCompiler.java	
@@ -12,8 +12,7 @@
 import mondrian.olap.*;
 import mondrian.calc.*;
 
-import java.util.List;
-import java.util.ArrayList;
+import java.util.*;
 
 /**
  * Enhanced expression compiler. It can generate code to convert between
@@ -60,8 +59,9 @@
         } else if (calc instanceof MemberCalc) {
             final MemberCalc memberCalc = (MemberCalc) calc;
             return new AbstractTupleCalc(exp, new Calc[] {memberCalc}) {
-                public Member[] evaluateTuple(Evaluator evaluator) {
-                    return new Member[] {memberCalc.evaluateMember(evaluator)};
+                public List<Member> evaluateTuple(Evaluator evaluator) {
+                    return Arrays.asList(new Member[] {
+                            memberCalc.evaluateMember(evaluator)});
                 }
             };
         } else {
Index: src/main/mondrian/resource/MondrianResource_en_US.properties
===================================================================
--- src/main/mondrian/resource/MondrianResource_en_US.properties	
+++ src/main/mondrian/resource/MondrianResource_en_US.properties	
@@ -0,0 +1,11 @@
+# This file contains the resources for
+# class '.mondrian.resource.MondrianResource_en_US' and locale 'en_US'.
+# It was generated by class org.eigenbase.resgen.ResourceGen
+# from C:/Documents and Settings/User1/Mis documentos/Trabajo/EclipseWorkSpace/AeatMondrian/trunk/src/mondrian-2.4.2.9831/src/main/mondrian/resource/MondrianResource.xml
+# on Tue Oct 02 12:03:00 CEST 2007.
+
+# This file is intentionally blank. Add property values
+# to this file to override the translations in the base
+# properties file, MondrianResource_en_US.properties
+
+# End .mondrian.resource.MondrianResource_en_US.properties
Index: src/main/mondrian/resource/MondrianResource.properties
===================================================================
--- src/main/mondrian/resource/MondrianResource.properties	
+++ src/main/mondrian/resource/MondrianResource.properties	
@@ -0,0 +1,147 @@
+# This file contains the resources for
+# class '.mondrian.resource.MondrianResource'; the base locale is 'en_US'.
+# It was generated by class org.eigenbase.resgen.ResourceGen
+# from C:/Documents and Settings/User1/Mis documentos/Trabajo/EclipseWorkSpace/AeatMondrian/trunk/src/mondrian-2.4.2.9831/src/main/mondrian/resource/MondrianResource.xml
+# on Tue Oct 02 12:03:00 CEST 2007.
+
+Internal=Internal error: {0}
+MdxCubeNotFound=MDX cube ''{0}'' not found
+MdxChildObjectNotFound=MDX object ''{0}'' not found in {1}
+MdxCubeName=cube ''{0}''
+MdxHierarchyName=hierarchy ''{0}''
+MdxDimensionName=dimension ''{0}''
+MdxLevelName=level ''{0}''
+MdxMemberName=member ''{0}''
+WhileParsingMdx=Error while parsing MDX statement ''{0}''
+WhileParsingMdxExpression=Syntax error in MDX expression ''{0}''
+MdxFatalError=MDX parser cannot recover from previous error(s)
+FailedToParseQuery=Failed to parse query ''{0}''
+MdxError=Error: {0}
+MdxSyntaxError=Syntax error at token ''{0}''
+MdxSyntaxErrorAt=Syntax error at line {1}, column {2}, token ''{0}''
+MdxFatalSyntaxError=Couldn''t repair and continue parse
+MdxCubeSlicerMemberError=Failed to add Cube Slicer with member ''{0}'' for hierarchy ''{1}'' on cube ''{2}''
+MdxCubeSlicerHierarchyError=Failed to add Cube Slicer for hierarchy ''{0}'' on cube ''{1}''
+MdxInvalidMember=Invalid member identifier ''{0}''
+MdxCalculatedHierarchyError=Hierarchy for calculated member ''{0}'' not found
+MdxAxisIsNotSet=Axis ''{0}'' expression is not a set
+MdxMemberExpIsSet=Member expression ''{0}'' must not be a set
+MdxSetExpNotSet=Set expression ''{0}'' must be a set
+MdxFuncArgumentsNum=Function ''{0}'' must have at least 2 arguments
+MdxFuncNotHier=Argument ''{0,number}'' of function ''{1}'' must be a hierarchy
+UnknownParameter=Unknown parameter ''{0}''
+MdxFormulaNotFound=Calculated {0} ''{1}'' has not been found in query ''{2}''
+MdxCantFindMember=Cannot find MDX member ''{0}''. Make sure it is indeed a member and not a level or a hierarchy.
+CalculatedMember=calculated member
+CalculatedSet=calculated set
+MdxCalculatedFormulaUsedOnAxis=Cannot delete {0} ''{1}''. It is used on {2} axis.
+MdxCalculatedFormulaUsedOnSlicer=Cannot delete {0} ''{1}''. It is used on slicer.
+MdxCalculatedFormulaUsedInFormula=Cannot delete {0} ''{1}''. It is used in definition of {2} ''{3}''.
+MdxCalculatedFormulaUsedInQuery=Cannot delete {0} ''{1}''. It is used in query ''{2}''.
+MdxAxisShowSubtotalsNotSupported=Show/hide subtotals operation on axis ''{0,number}'' is not supported.
+NoFunctionMatchesSignature=No function matches signature ''{0}''
+MoreThanOneFunctionMatchesSignature=More than one function matches signature ''{0}''
+MemberNotInLevelHierarchy=The member ''{0}'' is not in the same hierarchy as the level ''{1}''.
+ToggleDrillStateRecursiveNotSupported=''RECURSIVE'' is not supported in ToggleDrillState.
+CompoundSlicer=WHERE clause expression returned set with more than one element.
+EmptySlicer=WHERE clause expression returned NULL or empty set.
+FunctionMbrAndLevelHierarchyMismatch=The <level> and <member> arguments to {0} must be from the same hierarchy. The level was from ''{1}'' but the member was from ''{2}''.
+CousinHierarchyMismatch=The member arguments to the Cousin function must be from the same hierarchy. The members are ''{0}'' and ''{1}''.
+DimensionInIndependentAxes=Dimension ''{0}'' appears in more than one independent axis.
+ArgsMustHaveSameHierarchy=All arguments to function ''{0}'' must have same hierarchy.
+TimeArgNeeded=Argument to function ''{0}'' must belong to Time hierarchy.
+InvalidAxis=Invalid axis specification. The axis number must be an integer between 0 and {0,number}, but it was {1,number}.
+DupDimensionsInTuple=Tuple contains more than one member of dimension ''{0}''.
+VisualTotalsAppliedToTuples=Argument to ''VisualTotals'' function must be a set of members; got set of tuples.
+ParameterIsNotModifiable=Parameter ''{0}'' (defined at ''{1}'' scope) is not modifiable
+ParameterDefinedMoreThanOnce=Parameter ''{0}'' is defined more than once in this statement
+CycleDuringParameterEvaluation=Cycle occurred while evaluating parameter ''{0}''
+CastInvalidType=Unknown type ''{0}''; values are NUMERIC, STRING, BOOLEAN
+NullNotSupported=Function does not support NULL member parameter
+TwoNullsNotSupported=Function does not support two NULL member parameters
+NonTimeLevelInTimeHierarchy=Level ''{0}'' belongs to a time hierarchy, so its level-type must be  ''Years'', ''Quarters'', ''Months'', ''Weeks'' or ''Days''.
+TimeLevelInNonTimeHierarchy=Level ''{0}'' does not belong to a time hierarchy, so its level-type must be ''Standard''.
+MustSpecifyPrimaryKeyForHierarchy=In usage of hierarchy ''{0}'' in cube ''{1}'', you must specify a primary key.
+MustSpecifyPrimaryKeyTableForHierarchy=Must specify a primary key table for hierarchy ''{0}'', because it has more than one table.
+MustSpecifyForeignKeyForHierarchy=In usage of hierarchy ''{0}'' in cube ''{1}'', you must specify a foreign key, because the hierarchy table is different from the fact table.
+LevelMustHaveNameExpression=Level ''{0}'' must have a name expression (a ''column'' attribute or an <Expression> child
+PublicDimensionMustNotHaveForeignKey=Dimension ''{0}'' has a foreign key. This attribute is only valid in private dimensions and dimension usages.
+HierarchyMustNotHaveMoreThanOneSource=Hierarchy ''{0}'' has more than one source (memberReaderClass, <Table>, <Join> or <View>)
+DimensionUsageHasUnknownLevel=In usage of dimension ''{0}'' in cube ''{1}'', the level ''{2}'' is unknown
+CalcMemberHasBadDimension=Unknown dimension ''{0}'' for calculated member ''{1}'' in cube ''{2}''
+CalcMemberNotUnique=Calculated member ''{0}'' already exists in cube ''{1}''
+NeitherExprNorValueForCalcMemberProperty=Member property must have a value or an expression. (Property ''{0}'' of member ''{1}'' of cube ''{2}''.)
+ExprAndValueForMemberProperty=Member property must not have both a value and an expression. (Property ''{0}'' of member ''{1}'' of cube ''{2}''.)
+MemberFormatterLoadFailed=Failed to load formatter class ''{0}'' for level ''{1}''.
+HierarchyMustHaveForeignKey=Hierarchy ''{0}'' in cube ''{1}'' must have a foreign key, since it is not based on the cube's fact table.
+HierarchyInvalidForeignKey=Foreign key ''{0}'' of hierarchy ''{1}'' in cube ''{2}'' is not a column in the fact table.
+UdfClassNotFound=Failed to load user-defined function ''{0}'': class ''{1}'' not found
+UdfClassWrongIface=Failed to load user-defined function ''{0}'': class ''{1}'' does not implement the required interface ''{2}''
+UdfDuplicateName=Duplicate user-defined function ''{0}''
+NamedSetNotUnique=Named set ''{0}'' already exists in cube ''{1}''
+UnknownNamedSetHasBadFormula=Named set in cube ''{0}'' has bad formula
+NamedSetHasBadFormula=Named set ''{0}'' has bad formula
+MeasureOrdinalsNotUnique=Cube ''{0}'': Ordinal {1} is not unique: ''{2}'' and ''{3}''
+BadMeasureSource=Cube ''{0}'': Measure ''{1}'' must contain either a source column or a source expression, but not both
+DuplicateSchemaParameter=Duplicate parameter ''{0}'' in schema
+DuplicateAliasInCube=Duplicate table alias ''{0}'' in cube ''{1}''
+UnknownAggregator=Unknown aggregator ''{0}''; valid aggregators are: {1}
+CreateTableFailed=Mondrian loader could not create table ''{0}''.
+CreateIndexFailed=Mondrian loader could not create index ''{0}'' on table ''{1}''.
+MissingArg=Argument ''{0}'' must be specified.
+InvalidInsertLine=Input line is not a valid INSERT statement; line {0,number}: {1}.
+LimitExceededDuringCrossjoin=Size of CrossJoin result ({0,number}) exceeded limit ({1,number})
+TotalMembersLimitExceeded=Total number of Members in result ({0,number}) exceeded limit ({1,number})
+MemberFetchLimitExceeded=Number of members to be read exceeded limit ({0,number})
+QueryCanceled=Query canceled
+QueryTimeout=Query timeout of {0,number} seconds reached
+IterationLimitExceeded=Number of iterations exceeded limit of {0,number}
+InvalidHierarchyCondition=Hierarchy ''{0}'' is invalid (has no members)
+TooManyMessageRecorderErrors=Context ''{0}'': Exceeded number of allowed errors ''{1,number}''
+ForceMessageRecorderError=Context ''{0}'': Client forcing return with errors ''{1,number}''
+UnknownLevelName=Context ''{0}'': The Hierarchy Level ''{1}'' does not have a Level named ''{2}''
+DuplicateLevelNames=Context ''{0}'': Two levels share the same name ''{1}''
+DuplicateLevelColumnNames=Context ''{0}'': Two levels, ''{1}'' and ''{2}'',  share the same foreign column name ''{3}''
+DuplicateMeasureColumnNames=Context ''{0}'': Two measures, ''{1}'' and ''{2}'',  share the same column name ''{3}''
+DuplicateLevelMeasureColumnNames=Context ''{0}'': The level ''{1}'' and the measuer ''{2}'',  share the same column name ''{3}''
+DuplicateMeasureNames=Context ''{0}'': Two measures share the same name ''{1}''
+DuplicateFactForeignKey=Context ''{0}'': Duplicate fact foreign keys ''{1}'' for key ''{2}''.
+UnknownLeftJoinCondition=Context ''{0}'': Failed to find left join condition in fact table ''{1}'' for foreign key ''{2}''.
+UnknownHierarchyName=Context ''{0}'': The Hierarchy ''{1}'' does not exist"
+BadLevelNameFormat=Context ''{0}'': The Level name ''{1}'' should be [usage hierarchy name].[level name].
+BadMeasureNameFormat=Context ''{0}'': The Measures name ''{1}'' should be [Measures].[measure name].
+BadMeasures=Context ''{0}'': This name ''{1}'' must be the string "Measures".
+UnknownMeasureName=Context ''{0}'': Measures does not have a measure named ''{1}''
+NullAttributeString=Context ''{0}'': The value for the attribute ''{1}'' is null.
+EmptyAttributeString=Context ''{0}'': The value for the attribute ''{1}'' is empty (length is zero).
+MissingDefaultAggRule=There is no default aggregate recognition rule with tag ''{0}''.
+AggRuleParse=Error while parsing default aggregate recognition ''{0}''.
+BadMeasureName=Context ''{0}'': Failed to find Measure name ''{1}'' for cube ''{2}''.
+BadRolapStarLeftJoinCondition=Context ''{0}'': Bad RolapStar left join condition type: ''{1}'' ''{2}''.
+SqlQueryFailed=Context ''{0}'': Sql query failed to run ''{1}''.
+AggLoadingError=Error while loading/reloading aggregates.
+AggLoadingExceededErrorCount=Too many errors, ''{0,number}'', while loading/reloadin aggregates.
+UnknownFactTableColumn=Context ''{0}'': For Fact table ''{1}'', the column ''{2}'' is neither a measure or foreign key".
+AggMultipleMatchingMeasure=Context ''{0}'': Candidate aggregate table ''{1}'' for fact table ''{2}'' has ''{3,number}'' columns matching measure ''{4}'', ''{5}'', ''{6}''".
+CouldNotLoadDefaultAggregateRules=Could not load default aggregate rules ''{0}''.
+FailedCreateNewDefaultAggregateRules=Failed to create new default aggregate rules using property ''{0}'' with value ''{1}''.
+CubeRelationNotTable=The Cube ''{0}'' relation is not a MondrianDef.Table but rather ''{1}''.
+AttemptToChangeTableUsage=JdbcSchema.Table ''{0}'' already set to usage ''{1}'' and can not be reset to usage ''{2}''.
+BadJdbcFactoryClassName=JdbcSchema Factory classname ''{0}'', class not found.
+BadJdbcFactoryInstantiation=JdbcSchema Factory classname ''{0}'', can not instantiate.
+BadJdbcFactoryAccess=JdbcSchema Factory classname ''{0}'', illegal access.
+NonNumericFactCountColumn=Candidate aggregate table ''{0}'' for fact table ''{1}'' has candidate fact count column ''{2}'' has type ''{3}'' that is not numeric.
+TooManyFactCountColumns=Candidate aggregate table ''{0}'' for fact table ''{1}'' has ''{2,number}'' fact count columns.
+NoFactCountColumns=Candidate aggregate table ''{0}'' for fact table ''{1}'' has no fact count columns.
+NoMeasureColumns=Candidate aggregate table ''{0}'' for fact table ''{1}'' has no measure columns.
+TooManyMatchingForeignKeyColumns=Candidate aggregate table ''{0}'' for fact table ''{1}'' had ''{2,number}'' columns matching foreign key ''{3}''
+DoubleMatchForLevel=Double Match for candidate aggregate table ''{0}'' for fact table ''{1}'' and column ''{2}'' matched two hierarchies: 1) table=''{3}'', column=''{4}'' and 2) table=''{5}'', column=''{6}''
+AggUnknownColumn=Candidate aggregate table ''{0}'' for fact table ''{1}'' has a column ''{2}'' with unknown usage.
+NoAggregatorFound=No aggregator found while converting fact table aggregator: for usage\n        ''{0}'', fact aggregator ''{1}'' and sibling aggregator ''{2}''
+NoColumnNameFromExpression=Could not get a column name from a level key expression: ''{0}''.
+AggTableZeroSize=Zero size Aggregate table ''{0}'' for Fact Table ''{1}''.
+CacheFlushRegionMustContainMembers=Region of cells to be flushed must contain measures.
+CacheFlushUnionDimensionalityMismatch=Cannot union cell regions of different dimensionalities. (Dimensionalities are ''{0}'', ''{1}''.)
+CacheFlushCrossjoinDimensionsInCommon=Cannot crossjoin cell regions which have dimensions in common. (Dimensionalities are {0}.)
+NativeEvaluationUnsupported=Native evaluation not supported for this usage of function ''{0}''
+# End .mondrian.resource.MondrianResource.properties
Index: src/main/mondrian/olap/Member.java
===================================================================
--- src/main/mondrian/olap/Member.java	
+++ src/main/mondrian/olap/Member.java	
@@ -13,6 +13,8 @@
 
 package mondrian.olap;
 
+import java.util.*;
+
 /**
  * A <code>Member</code> is a 'point' on a dimension of a cube. Examples are
  * <code>[Time].[1997].[January]</code>,
@@ -103,7 +105,7 @@
     /**
      * Returns array of all members, which are ancestor to <code>this</code>.
      */
-    Member[] getAncestorMembers();
+    List<Member> getAncestorMembers();
 
     /**
      * Returns whether this member is computed from a <code>with member</code>
Index: src/main/mondrian/olap/DelegatingSchemaReader.java
===================================================================
--- src/main/mondrian/olap/DelegatingSchemaReader.java	
+++ src/main/mondrian/olap/DelegatingSchemaReader.java	
@@ -44,7 +44,7 @@
         return schemaReader.getRole();
     }
 
-    public Member[] getHierarchyRootMembers(Hierarchy hierarchy) {
+    public List<? extends Member> getHierarchyRootMembers(Hierarchy hierarchy) {
         return schemaReader.getHierarchyRootMembers(hierarchy);
     }
 
@@ -52,11 +52,12 @@
         return schemaReader.getMemberParent(member);
     }
 
-    public Member[] getMemberChildren(Member member) {
+    public List<? extends Member> getMemberChildren(Member member) {
         return schemaReader.getMemberChildren(member);
     }
 
-    public Member[] getMemberChildren(Member[] members) {
+    public List<? extends Member> getMemberChildren(
+            final List<? extends Member> members) {
         return schemaReader.getMemberChildren(members);
     }
 
@@ -140,7 +141,8 @@
         return schemaReader.getElementChild(parent, name, matchType);
     }
 
-    public Member[] getLevelMembers(Level level, boolean includeCalculated) {
+    public List<? extends Member> getLevelMembers(final Level level, 
+            final boolean includeCalculated) {
         return schemaReader.getLevelMembers(level, includeCalculated);
     }
 
@@ -164,15 +166,15 @@
         return schemaReader.getCubes();
     }
 
-    public List<Member> getCalculatedMembers(Hierarchy hierarchy) {
+    public List<? extends Member> getCalculatedMembers(Hierarchy hierarchy) {
         return schemaReader.getCalculatedMembers(hierarchy);
     }
 
-    public List<Member> getCalculatedMembers(Level level) {
+    public List<? extends Member> getCalculatedMembers(Level level) {
         return schemaReader.getCalculatedMembers(level);
     }
 
-    public List<Member> getCalculatedMembers() {
+    public List<? extends Member> getCalculatedMembers() {
         return schemaReader.getCalculatedMembers();
     }
 
@@ -180,22 +182,23 @@
         return schemaReader.getChildrenCountFromCache(member);
     }
 
-    public int getLevelCardinality(
-        Level level, boolean approximate, boolean materialize)
-    {
-        return schemaReader.getLevelCardinality(
-            level, approximate, materialize);
+    public int getLevelCardinality(final Level level, final boolean approximate,
+            final boolean materialize) {
+        return schemaReader.getLevelCardinality(level,approximate,materialize);
     }
 
-    public Member[] getLevelMembers(Level level, Evaluator context) {
+    public List<? extends Member> getLevelMembers(final Level level, 
+            final Evaluator context) {
       return schemaReader.getLevelMembers(level, context);
     }
 
-    public Member[] getMemberChildren(Member member, Evaluator context) {
+    public List<? extends Member> getMemberChildren(final Member member, 
+            final Evaluator context) {
       return schemaReader.getMemberChildren(member, context);
     }
 
-    public Member[] getMemberChildren(Member[] members, Evaluator context) {
+    public List<? extends Member> getMemberChildren(
+            final List<? extends Member> members, final Evaluator context) {
       return schemaReader.getMemberChildren(members, context);
     }
 
Index: src/main/mondrian/olap/Cube.java
===================================================================
--- src/main/mondrian/olap/Cube.java	
+++ src/main/mondrian/olap/Cube.java	
@@ -38,12 +38,12 @@
     Hierarchy lookupHierarchy(Id.Segment s, boolean unique);
 
     /**
-     * Returns Member[]. It builds Member[] by analyzing cellset, which
+     * Returns List<Member>. It builds List<Member> by analyzing cellset, which
      * gets created by running mdx sQuery.  <code>query</code> has to be in the
      * format of something like "[with calculated members] select *members* on
      * columns from <code>this</code>".
      */
-    Member[] getMembersForQuery(String query, List<Member> calcMembers);
+    List<Member> getMembersForQuery(String query, List<Member> calcMembers);
 
     /**
      * Returns the time dimension for this cube, or <code>null</code>
Index: src/main/mondrian/olap/Mondrian.xml
===================================================================
--- src/main/mondrian/olap/Mondrian.xml	
+++ src/main/mondrian/olap/Mondrian.xml	
@@ -122,6 +122,12 @@
                 public Dimension.
             </Doc>
         </Attribute>
+        <Attribute name="highCardinality" type="Boolean" default="false">
+            <Doc>
+                Flag to manage this dimension as a high cardinality one
+                and avoid caching.
+            </Doc>
+        </Attribute>
         <Code><![CDATA[
             /**
              * Looks up the base dimension of this dimension. If this is a
Index: src/main/mondrian/olap/DimensionBase.java
===================================================================
--- src/main/mondrian/olap/DimensionBase.java	
+++ src/main/mondrian/olap/DimensionBase.java	
@@ -30,19 +30,22 @@
     protected final String uniqueName;
     protected final String description;
     protected final int globalOrdinal;
+    protected final boolean highCardinality;
     protected Hierarchy[] hierarchies;
     protected DimensionType dimensionType;
 
     protected DimensionBase(
-            String name,
-            int globalOrdinal,
-            DimensionType dimensionType)
+            final String name,
+            final int globalOrdinal,
+            final DimensionType dimensionType,
+            final boolean highCardinality)
     {
         this.name = name;
         this.uniqueName = Util.makeFqName(name);
         this.description = null;
         this.globalOrdinal = globalOrdinal;
         this.dimensionType = dimensionType;
+        this.highCardinality = highCardinality;
     }
 
     public String getUniqueName() {
@@ -74,7 +77,8 @@
     }
 
     public String getQualifiedName() {
-        return MondrianResource.instance().MdxDimensionName.str(getUniqueName());
+        return MondrianResource.instance().MdxDimensionName.str(
+                getUniqueName());
     }
 
     public boolean isMeasures() {
@@ -85,8 +89,7 @@
         return dimension == this;
     }
 
-    public OlapElement lookupChild(SchemaReader schemaReader, Id.Segment s)
-    {
+    public OlapElement lookupChild(SchemaReader schemaReader, Id.Segment s) {
         return lookupChild(schemaReader, s, MatchType.EXACT);
     }
 
@@ -124,6 +127,11 @@
         return oe;
     }
 
+
+    public boolean isHighCardinality() { 
+        return this.highCardinality; 
+    }
+
     private Hierarchy lookupHierarchy(Id.Segment s) {
         for (Hierarchy hierarchy : hierarchies) {
             if (hierarchy.getName().equalsIgnoreCase(s.name)) {
Index: src/main/mondrian/olap/MondrianProperties.java
===================================================================
--- src/main/mondrian/olap/MondrianProperties.java	
+++ src/main/mondrian/olap/MondrianProperties.java	
@@ -394,6 +394,13 @@
     public transient final IntegerProperty ResultLimit = new IntegerProperty(
             this, "mondrian.result.limit", 0);
 
+    /**
+     * Stablish the ammount of chunks for quering cells involving high 
+     * cardinality dimensions. Should prime with mondrian.result.limit.
+     */
+    public transient final IntegerProperty HighCardChunkSize = 
+            new IntegerProperty(this, "mondrian.result.highCardChunkSize", 1);
+
     /** @deprecated obsolete */
     public transient final IntegerProperty CachePoolCostLimit =
         new IntegerProperty(
@@ -451,6 +458,16 @@
     // miscellaneous
 
     /**
+     * Number of maximum simultaneous threads for parallel query running
+     *
+     */
+    public transient final IntegerProperty MaximumParallelThreads = 
+        new IntegerProperty(
+            this, "mondrian.rolap.MaximumParallelThreads", 5);
+
+
+    
+    /**
      * Property containing the JDBC URL of the FoodMart database.
      * The default value is to connect to an ODBC data source called
      * "MondrianFoodMart".
Index: src/main/mondrian/olap/CubeAccess.java
===================================================================
--- src/main/mondrian/olap/CubeAccess.java	
+++ src/main/mondrian/olap/CubeAccess.java	
@@ -27,7 +27,7 @@
     /** array of hierarchies with no access */
     private Hierarchy[] noAccessHierarchies;
     /** array of members which have limited access */
-    private Member[]  limitedMembers;
+    private List<Member>  limitedMembers;
     private final List<Hierarchy> hierarchyList = new ArrayList<Hierarchy>();
     private final List<Member> memberList = new ArrayList<Member>();
     private final Cube mdxCube;
@@ -55,7 +55,7 @@
         return noAccessHierarchies;
     }
 
-    public Member[] getLimitedMembers() {
+    public List<Member> getLimitedMembers() {
         return limitedMembers;
     }
 
@@ -132,7 +132,7 @@
      */
     public void normalizeCubeAccess() {
         if (memberList.size() > 0) {
-            limitedMembers = memberList.toArray(new Member[memberList.size()]);
+            limitedMembers = memberList;
             hasRestrictions = true;
         }
         if (hierarchyList.size() > 0) {
@@ -172,8 +172,8 @@
         int h = mdxCube.hashCode();
         h = Util.hash(h, hierarchyList);
         h = Util.hash(h, memberList);
-        h = Util.hashArray(h, noAccessHierarchies);
-        h = Util.hashArray(h, limitedMembers);
+        h = Util.hash(h, noAccessHierarchies);
+        h = Util.hash(h, limitedMembers);
         return h;
     }
 }
Index: src/main/mondrian/olap/MemberBase.java
===================================================================
--- src/main/mondrian/olap/MemberBase.java	
+++ src/main/mondrian/olap/MemberBase.java	
@@ -247,14 +247,14 @@
     }
 
     // implement Member
-    public Member[] getAncestorMembers() {
+    public List<Member> getAncestorMembers() {
         List<Member> list = new ArrayList<Member>();
         Member parentMember = getParentMember();
         while (parentMember != null) {
             list.add(parentMember);
             parentMember = parentMember.getParentMember();
         }
-        return list.toArray(new Member[list.size()]);
+        return list;
     }
 
     /**
Index: src/main/mondrian/olap/Query.java
===================================================================
--- src/main/mondrian/olap/Query.java	
+++ src/main/mondrian/olap/Query.java	
@@ -1397,7 +1397,6 @@
      * returns the calculated members defined in this query.
      */
     private class QuerySchemaReader extends DelegatingSchemaReader {
-
         public QuerySchemaReader(SchemaReader cubeSchemaReader) {
             super(cubeSchemaReader);
         }
@@ -1424,13 +1423,13 @@
             }
         }
 
-        public Member[] getLevelMembers(
+        public List<? extends Member> getLevelMembers(
                 Level level, boolean includeCalculated) {
-            Member[] members = super.getLevelMembers(level, false);
-            if (includeCalculated) {
-                members = Util.addLevelCalculatedMembers(this, level, members);
-            }
-            return members;
+            final List<? extends Member> members = 
+                    super.getLevelMembers(level, false);
+            if(includeCalculated) {
+                return Util.addLevelCalculatedMembers(this, level, members);
+            } else return members;
         }
 
         public Member getCalculatedMember(List<Id.Segment> nameParts) {
@@ -1438,11 +1437,12 @@
             return lookupMemberFromCache(uniqueName);
         }
 
-        public List<Member> getCalculatedMembers(Hierarchy hierarchy) {
+        public List<? extends Member> getCalculatedMembers(
+                final Hierarchy hierarchy) {
             List<Member> result = new ArrayList<Member>();
             // Add calculated members in the cube.
-            final List<Member> calculatedMembers =
-                super.getCalculatedMembers(hierarchy);
+            final List<? extends Member> calculatedMembers =
+                    super.getCalculatedMembers(hierarchy);
             result.addAll(calculatedMembers);
             // Add calculated members defined in the query.
             for (Member member : getDefinedMembers()) {
@@ -1453,9 +1453,9 @@
             return result;
         }
 
-        public List<Member> getCalculatedMembers(Level level) {
-            List<Member> hierarchyMembers =
-                getCalculatedMembers(level.getHierarchy());
+        public List<? extends Member> getCalculatedMembers(Level level) {
+            List<? extends Member> hierarchyMembers =
+                    getCalculatedMembers(level.getHierarchy());
             List<Member> result = new ArrayList<Member>();
             for (Member member : hierarchyMembers) {
                 if (member.getLevel().equals(level)) {
@@ -1465,12 +1465,11 @@
             return result;
         }
 
-        public List<Member> getCalculatedMembers() {
+        public List<? extends Member> getCalculatedMembers() {
             return getDefinedMembers();
         }
 
-        public OlapElement getElementChild(OlapElement parent, Id.Segment s)
-        {
+        public OlapElement getElementChild(OlapElement parent, Id.Segment s) {
             return getElementChild(parent, s, MatchType.EXACT);
         }
 
Index: src/main/mondrian/olap/ResultBase.java
===================================================================
--- src/main/mondrian/olap/ResultBase.java	
+++ src/main/mondrian/olap/ResultBase.java	
@@ -84,33 +84,17 @@
             }
             i++;
         }
-/*
-        for (int i = 0, count = positions.size(); i < count; i++) {
-            if (axis < 0) {
-                if (i > 0) {
-                    pw.print(", ");
-                }
-                printCell(pw, pos);
-            } else {
-                pos[axis] = i;
-                if (axis == 0) {
-                    int row = axis + 1 < pos.length ? pos[axis + 1] : 0;
-                    pw.print("Row #" + row + ": ");
-                }
-                printRows(pw, axis - 1, pos);
-                if (axis == 0) {
-                    pw.println();
-                }
-            }
-        }
-*/
     }
     private void printAxis(PrintWriter pw, Axis axis) {
         List<Position> positions = axis.getPositions();
-        for (Position position: positions) {
+        main: for (Position position: positions) {
             boolean firstTime = true;
             pw.print("{");
             for (Member member: position) {
+                if(member.getDimension().isHighCardinality()) {
+                    pw.println(" -- HighCardinality Dimension-- }");
+                    break main;
+                }
                 if (! firstTime) {
                     pw.print(", ");
                 }
Index: src/main/mondrian/olap/Evaluator.java
===================================================================
--- src/main/mondrian/olap/Evaluator.java	
+++ src/main/mondrian/olap/Evaluator.java	
@@ -55,11 +55,11 @@
      * @return Evaluator with each given member overriding the state of the
      *   current Evaluator for its dimension
      */
-    Evaluator push(Member[] members);
+    Evaluator push(List<Member> members);
 
     /**
      * Creates a new Evaluator with the same context as this evaluator.
-     * Equivalent to {@link #push(Member[]) push(new Member[0])}.
+     * Equivalent to {@link #push(List<Member>) push(new Member[0])}.
      *
      * <p>This method is typically called before evaluating an expression which
      * is known to corrupt the evaluation context.
@@ -75,7 +75,7 @@
     /**
      * Creates a new Evaluator with the same context except for one member.
      * Equivalent to
-     * {@link #push(Member[]) push(new Member[] &#124;member&#125;)}.
+     * {@link #push(List<Member>) push(new List<Member> &#124;member&#125;)}.
      *
      * <p>You can retrieve this Evaluator by calling the new Evaluator's
      * {@link #pop()} method, but it is not necessary to call <code>pop</code>.
@@ -100,10 +100,8 @@
      */
     Member setContext(Member member);
 
-    void setContext(List<Member> memberList);
+    void setContext(List<Member> members);
 
-    void setContext(Member[] members);
-
     Member getContext(Dimension dimension);
 
     /**
@@ -207,7 +205,7 @@
     /**
      * Returns an array of the members which make up the current context.
      */
-    Member[] getMembers();
+    List<Member> getMembers();
 
     /**
      * Returns the number of times that this evaluator has told a lie when
Index: src/main/mondrian/olap/fun/ToggleDrillStateFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/ToggleDrillStateFunDef.java	
+++ src/main/mondrian/olap/fun/ToggleDrillStateFunDef.java	
@@ -36,7 +36,9 @@
     static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
             "ToggleDrillState",
             "ToggleDrillState(<Set1>, <Set2>[, RECURSIVE])",
-            "Toggles the drill state of members. This function is a combination of DrillupMember and DrilldownMember.",
+            "Toggles the drill state of members. "
+                    + "This function is a combination of DrillupMember "
+                    + "and DrilldownMember.",
             new String[]{"fxxx", "fxxxy"},
             ToggleDrillStateFunDef.class,
             ReservedWords);
@@ -47,34 +49,40 @@
 
     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
         if (call.getArgCount() > 2) {
-            throw MondrianResource.instance().ToggleDrillStateRecursiveNotSupported.ex();
+            throw MondrianResource.instance()
+                    .ToggleDrillStateRecursiveNotSupported.ex();
         }
         final ListCalc listCalc0 =
                 compiler.compileList(call.getArg(0));
         final ListCalc listCalc1 =
                 compiler.compileList(call.getArg(1));
         if (((SetType) call.getType()).getArity() == 1) {
-            return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
+            return new AbstractListCalc(call, new Calc[] 
+                    {listCalc0, listCalc1}) {
                 public List evaluateList(Evaluator evaluator) {
-                    final List<Member> list0 = listCalc0.evaluateList(evaluator);
-                    final List<Member> list1 = listCalc1.evaluateList(evaluator);
+                    final List<Member> list0 = 
+                            listCalc0.evaluateList(evaluator);
+                    final List<Member> list1 = 
+                            listCalc1.evaluateList(evaluator);
                     return toggleDrillStateMembers(evaluator, list0, list1);
                 }
             };
         } else {
-            return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
+            return new AbstractListCalc(call, new Calc[] 
+                    {listCalc0, listCalc1}) {
                 public List evaluateList(Evaluator evaluator) {
-                    final List<Member[]> list0 = listCalc0.evaluateList(evaluator);
-                    final List<Member> list1 = listCalc1.evaluateList(evaluator);
+                    final List<List<Member>> list0 = 
+                            listCalc0.evaluateList(evaluator);
+                    final List<Member> list1 = 
+                            listCalc1.evaluateList(evaluator);
                     return toggleDrillStateTuples(evaluator, list0, list1);
                 }
             };
         }
     }
 
-    List<Member> toggleDrillStateMembers(
-        Evaluator evaluator, List<Member> v0, List<Member> list1)
-    {
+    List<Member> toggleDrillStateMembers(final Evaluator evaluator, 
+            final List<Member> v0, List<Member> list1) {
         if (list1.isEmpty()) {
             return v0;
         }
@@ -111,8 +119,8 @@
                     }
                 } while (i < n);
             } else {
-                Member[] children =
-                    evaluator.getSchemaReader().getMemberChildren(m);
+                List<? extends Member> children =
+                        evaluator.getSchemaReader().getMemberChildren(m);
                 for (Member child : children) {
                     result.add(child);
                 }
@@ -121,9 +129,8 @@
         return result;
     }
 
-    List<Member[]> toggleDrillStateTuples(
-        Evaluator evaluator, List<Member[]> v0, List<Member> list1)
-    {
+    List<List<Member>> toggleDrillStateTuples(final Evaluator evaluator, 
+            final List<List<Member>> v0, List<Member> list1) {
         if (list1.isEmpty()) {
             return v0;
         }
@@ -132,15 +139,15 @@
         }
         Set<Member> set = new HashSet<Member>();
         set.addAll(list1);
-        List<Member[]> result = new ArrayList<Member[]>();
+        List<List<Member>> result = new ArrayList<List<Member>>();
         int i = 0, n = v0.size();
         while (i < n) {
-            Member[] o = v0.get(i++);
+            List<Member> o = v0.get(i++);
             result.add(o);
             Member m = null;
             int k = -1;
-            for (int j = 0; j < o.length; j++) {
-                Member member = o[j];
+            for (int j = 0; j < o.size(); j++) {
+                Member member = o.get(j);
                 if (set.contains(member)) {
                     k = j;
                     m = member;
@@ -152,8 +159,8 @@
             }
             boolean isDrilledDown = false;
             if (i < n) {
-                Member[] next = v0.get(i);
-                Member nextMember = next[k];
+                List<Member> next = v0.get(i);
+                Member nextMember = next.get(k);
                 boolean strict = true;
                 if (FunUtil.isAncestorOf(m, nextMember, strict)) {
                     isDrilledDown = true;
@@ -162,8 +169,8 @@
             if (isDrilledDown) {
                 // skip descendants of this member
                 do {
-                    Member[] next = v0.get(i);
-                    Member nextMember = next[k];
+                    List<Member> next = v0.get(i);
+                    Member nextMember = next.get(k);
                     boolean strict = true;
                     if (FunUtil.isAncestorOf(m, nextMember, strict)) {
                         i++;
@@ -172,10 +179,12 @@
                     }
                 } while (i < n);
             } else {
-                Member[] children = evaluator.getSchemaReader().getMemberChildren(m);
+                List<? extends Member> children = 
+                        evaluator.getSchemaReader().getMemberChildren(m);
                 for (Member child : children) {
-                    Member[] members = o.clone();
-                    members[k] = child;
+                    List<Member> members = new ArrayList<Member>();
+                    ((List)members).addAll(o);
+                    members.set(k, child);
                     result.add(members);
                 }
             }
Index: src/main/mondrian/olap/fun/ExtractFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/ExtractFunDef.java	
+++ src/main/mondrian/olap/fun/ExtractFunDef.java	
@@ -184,10 +184,10 @@
             return new AbstractListCalc(call, new Calc[] {listCalc}) {
                 public List evaluateList(Evaluator evaluator) {
                     List<Member> result = new ArrayList<Member>();
-                    List<Member[]> list = listCalc.evaluateList(evaluator);
+                    List<List<Member>> list = listCalc.evaluateList(evaluator);
                     Set<Member> emittedMembers = new HashSet<Member>();
-                    for (Member[] members : list) {
-                        Member outMember = members[extractedOrdinals[0]];
+                    for (List<Member> members : list) {
+                        Member outMember = members.get(extractedOrdinals[0]);
                         if (emittedMembers.contains(outMember)) {
                             continue;
                         }
@@ -200,19 +200,18 @@
         } else {
             return new AbstractListCalc(call, new Calc[] {listCalc}) {
                 public List evaluateList(Evaluator evaluator) {
-                    List<Member[]> result = new ArrayList<Member[]>();
-                    List<Member[]> list = listCalc.evaluateList(evaluator);
+                    List<List<Member>> result = new ArrayList<List<Member>>();
+                    List<List<Member>> list = listCalc.evaluateList(evaluator);
                     Set<List<Member>> emittedTuples = new HashSet<List<Member>>();
-                    for (Member[] members : list) {
-                        Member[] outMembers = new Member[outArity];
-                        for (int i = 0; i < outMembers.length; i++) {
-                            outMembers[i] = members[extractedOrdinals[i]];
+                    for (List<Member> members : list) {
+                        List<Member> outMembers = new ArrayList<Member>();
+                        for (int i = 0; i < outArity; i++) {
+                            outMembers.add(members.get(extractedOrdinals[i]));
                         }
-                        final List<Member> outTuple = Arrays.asList(outMembers);
-                        if (emittedTuples.contains(outTuple)) {
+                        if (emittedTuples.contains(outMembers)) {
                             continue;
                         }
-                        emittedTuples.add(outTuple);
+                        emittedTuples.add(outMembers);
                         result.add(outMembers);
                     }
                     return result;
Index: src/main/mondrian/olap/fun/MemberHelper.java
===================================================================
--- src/main/mondrian/olap/fun/MemberHelper.java	
+++ src/main/mondrian/olap/fun/MemberHelper.java	
@@ -11,6 +11,8 @@
 
 import mondrian.olap.Member;
 
+import java.util.*;
+
 /**
  * This helper class is used by the Distinct(&lt;set&gt;) function to determine
  * whether or not elements of different types within a set are equal.
@@ -18,13 +20,13 @@
 public class MemberHelper {
     private final Object mObject;
     public MemberHelper(Object entry) {
-        if ((entry == null) || 
-            (entry instanceof Member) || 
-            (entry instanceof Member[])) {
-
+        if ((entry == null) || (entry instanceof Member) || 
+                    (entry instanceof List)) {
             mObject = entry;
         } else {
-            throw new IllegalArgumentException("Expected Member or Member[]");
+            throw new IllegalArgumentException(
+                    "Expected Member or List<Member> but received "
+                    + entry.getClass());
         }
     }
 
@@ -41,18 +43,16 @@
             return mh.mObject == null;
         } else if (mh.mObject instanceof Member && mObject instanceof Member) {
             return ((Member)mObject).equals(mh.mObject);
-        } else if (mh.mObject instanceof Member[] && 
-            mObject instanceof Member[]) {
+        } else if (mh.mObject instanceof List && mObject instanceof List) {
+            List<Member> array1 = (List<Member>)mh.mObject;
+            List<Member> array2 = (List<Member>)this.mObject;
 
-            Member[] array1 = (Member[])mh.mObject;
-            Member[] array2 = (Member[])this.mObject;
-
-            if (array1.length != array2.length) {
+            if (array1.size() != array2.size()) {
                 return false;
             }
 
-            for (int idx = 0; idx < array1.length; idx++) {
-                if (!array1[idx].equals(array2[idx])) {
+            for (int idx = 0; idx < array1.size(); idx++) {
+                if (!array1.get(idx).equals(array2.get(idx))) {
                     return false;
                 }
             }
@@ -66,13 +66,13 @@
     public int hashCode() {
         if (mObject instanceof Member) {
             return mObject.hashCode();
-        } else if (mObject instanceof Member[]) {
+        } else if (mObject instanceof List) {
             int hash = 0;
 
-            Member[] array = (Member[]) mObject;
+            List<Member> array = (List<Member>) mObject;
 
-            for (int idx = 0; idx < array.length; idx++) {
-                hash ^= array[idx].hashCode();
+            for (int idx = 0; idx < array.size(); idx++) {
+                hash ^= array.get(idx).hashCode();
             }
 
             return hash;
Index: src/main/mondrian/olap/fun/StrToTupleFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/StrToTupleFunDef.java	
+++ src/main/mondrian/olap/fun/StrToTupleFunDef.java	
@@ -63,7 +63,7 @@
                 hierarchies[i] = tupleType.elementTypes[i].getHierarchy();
             }
             return new AbstractTupleCalc(call, new Calc[] {stringCalc}) {
-                public Member[] evaluateTuple(Evaluator evaluator) {
+                public List<Member> evaluateTuple(Evaluator evaluator) {
                     String string = stringCalc.evaluateString(evaluator);
                     return parseTuple(evaluator, string, hierarchies);
                 }
@@ -80,23 +80,23 @@
      * @param hierarchies Hierarchies of the members
      * @return Tuple represented as array of members
      */
-    private Member[] parseTuple(
-        Evaluator evaluator, String string, Hierarchy[] hierarchies)
-    {
-        final Member[] members = new Member[hierarchies.length];
+    private List<Member> parseTuple(final Evaluator evaluator, 
+            final String string, final Hierarchy[] hierarchies) {
+        final List<Member> members = new ArrayList<Member>();
         int i = StrToSetFunDef.parseTuple(
-            evaluator, string, 0, members, hierarchies);
+                evaluator, string, 0, members, hierarchies);
         // todo: check for garbage at end of string
         return members;
     }
 
     private Member parseMember(
         Evaluator evaluator, String string, Hierarchy hierarchy) {
-        Member[] members = {null};
+        List<Member> members = new ArrayList<Member>();
+        members.add(null);
         int i = StrToSetFunDef.parseMember(
             evaluator, string, 0, members, new Hierarchy[] {hierarchy}, 0);
         // todo: check for garbage at end of string
-        return members[0];
+        return members.get(0);
     }
 
     public Exp createCall(Validator validator, Exp[] args) {
Index: src/main/mondrian/olap/fun/DrilldownMemberFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/DrilldownMemberFunDef.java	
+++ src/main/mondrian/olap/fun/DrilldownMemberFunDef.java	
@@ -31,8 +31,9 @@
     static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
             "DrilldownMember",
             "DrilldownMember(<Set1>, <Set2>[, RECURSIVE])",
-            "Drills down the members in a set that are present in a second specified set.",
-            new String[]{"fxxx", "fxxxy"},
+            "Drills down the members in a set that are present in a "
+                    + "second specified set.",
+            new String[] {"fxxx", "fxxxy"},
             DrilldownMemberFunDef.class,
             reservedWords);
 
@@ -56,14 +57,12 @@
             /**
              * Drills down an element.
              *
-             * Algorithm: If object is present in a_hsSet1 then adds to result children
-             * of the object. If flag a_bRecursive is set then this method is called
-             * recursively for the children.
+             * Algorithm: If object is present in a_hsSet1 then adds to 
+             * result children of the object. If flag a_bRecursive is 
+             * set then this method is called recursively for the children.
              *
              * @param element Element of a set, can be either {@link Member} or
              *   {@link Member}[]
-             *
-             *
              */
             protected void drillDownObj(
                     Evaluator evaluator,
@@ -82,10 +81,10 @@
                     }
                     m = (Member) element;
                 } else {
-                    Util.assertTrue(element instanceof Member[]);
-                    Member[] members = (Member[]) element;
-                    for (int j = 0; j < members.length; j++) {
-                        Member member = members[j];
+                    Util.assertTrue(element instanceof List);
+                    List<Member> members = (List<Member>) element;
+                    for (int j = 0; j < members.size(); j++) {
+                        Member member = members.get(j);
                         if (memberSet.contains(member)) {
                             k = j;
                             m = member;
@@ -97,14 +96,16 @@
                     }
                 }
 
-                Member[] children = evaluator.getSchemaReader().getMemberChildren(m);
-                for (int j = 0; j < children.length; j++) {
+                List<? extends Member> children = 
+                        evaluator.getSchemaReader().getMemberChildren(m);
+                for (int j = 0; j < children.size(); j++) {
                     Object objNew;
                     if (k < 0) {
-                        objNew = children[j];
+                        objNew = children.get(j);
                     }  else {
-                        Member[] members = (Member[]) ((Member[]) element).clone();
-                        members[k] = children[j];
+                        List<Member> members = new ArrayList<Member>();
+                        members.addAll((List)element);
+                        members.set(k, children.get(j));
                         objNew = members;
                     }
 
@@ -115,7 +116,7 @@
                 }
             }
 
-            private List drilldownMember(List v0, List v1, Evaluator evaluator) {
+            private List drilldownMember(List v0, List v1,Evaluator evaluator) {
                 if (null == v0 ||
                     v0.isEmpty() ||
                     null == v1 ||
Index: src/main/mondrian/olap/fun/TupleFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/TupleFunDef.java	
+++ src/main/mondrian/olap/fun/TupleFunDef.java	
@@ -11,6 +11,7 @@
 // jhyde, 3 March, 2002
 */
 package mondrian.olap.fun;
+
 import mondrian.olap.*;
 import mondrian.olap.type.*;
 import mondrian.resource.MondrianResource;
@@ -19,6 +20,7 @@
 import mondrian.mdx.ResolvedFunCall;
 
 import java.io.PrintWriter;
+import java.util.*;
 
 /**
  * <code>TupleFunDef</code> implements the '( ... )' operator which builds
@@ -107,11 +109,11 @@
             this.memberCalcs = memberCalcs;
         }
 
-        public Member[] evaluateTuple(Evaluator evaluator) {
-            final Member[] members = new Member[memberCalcs.length];
-            for (int i = 0; i < members.length; i++) {
-                final Member member = members[i]
-                        = memberCalcs[i].evaluateMember(evaluator);
+        public List<Member> evaluateTuple(Evaluator evaluator) {
+            final List<Member> members = new ArrayList<Member>();
+            for (int i = 0; i < memberCalcs.length; i++) {
+                final Member member = memberCalcs[i].evaluateMember(evaluator);
+                members.add(member);
                 if (member == null || member.isNull()) {
                     return null;
                 }
Index: src/main/mondrian/olap/fun/TopBottomPercentSumFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/TopBottomPercentSumFunDef.java	
+++ src/main/mondrian/olap/fun/TopBottomPercentSumFunDef.java	
@@ -121,10 +121,10 @@
                 sortMembers(evaluator, memberList, calc, top, true);
             } else {
                 isMember = false;
-                List<Member[]> tupleList = (List<Member[]>) list;
+                List<List<Member>> tupleList = (List<List<Member>>) list;
                 mapMemberToValue =
-                    evaluateTuples(evaluator, calc, tupleList);
-                int arity = ((Member[]) first).length;
+                        evaluateTuples(evaluator, calc, tupleList);
+                int arity = ((List<Member>) first).size();
                 sortTuples(evaluator, tupleList, calc, top, true, arity);
             }
             if (percent) {
@@ -140,8 +140,7 @@
                 }
                 Object o = (isMember)
                     ? mapMemberToValue.get(list.get(i))
-                    : mapMemberToValue.get(
-                        new ArrayHolder<Member>((Member []) list.get(i)));
+                    : mapMemberToValue.get((List<Member>) list.get(i));
                 if (o == Util.nullValue) {
                     nullCount++;
                 } else if (o instanceof Number) {
Index: src/main/mondrian/olap/fun/FunDefBase.java
===================================================================
--- src/main/mondrian/olap/fun/FunDefBase.java	
+++ src/main/mondrian/olap/fun/FunDefBase.java	
@@ -382,6 +382,11 @@
     public void unparse(Exp[] args, PrintWriter pw) {
         getSyntax().unparse(getName(), args, pw);
     }
+
+    public String toString() {
+        return this.getName() + ";" + this.getSignature() + ";"
+                + this.getDescription();
+    }
 }
 
 // End FunDefBase.java
Index: src/main/mondrian/olap/fun/SetItemFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/SetItemFunDef.java	
+++ src/main/mondrian/olap/fun/SetItemFunDef.java	
@@ -112,11 +112,12 @@
         Calc[] calcs = calcList.toArray(new Calc[calcList.size()]);
         if (elementType instanceof TupleType) {
             final TupleType tupleType = (TupleType) elementType;
-            final Member[] nullTuple = makeNullTuple(tupleType);
+            final List<Member> nullTuple = makeNullTuple(tupleType);
             if (isString) {
                 return new AbstractTupleCalc(call, calcs) {
-                    public Member[] evaluateTuple(Evaluator evaluator) {
-                        final List<Member[]> list = listCalc.evaluateList(evaluator);
+                    public List<Member> evaluateTuple(Evaluator evaluator) {
+                        final List<List<Member>> list = 
+                                listCalc.evaluateList(evaluator);
                         assert list != null;
                         String[] results = new String[stringCalcs.length];
                         for (int i = 0; i < stringCalcs.length; i++) {
@@ -124,10 +125,10 @@
                                     stringCalcs[i].evaluateString(evaluator);
                         }
                         listLoop:
-                        for (Member[] members : list) {
+                        for (List<Member> members : list) {
                             for (int j = 0; j < results.length; j++) {
                                 String result = results[j];
-                                final Member member = members[j];
+                                final Member member = members.get(j);
                                 if (!matchMember(member, result)) {
                                     continue listLoop;
                                 }
@@ -142,15 +143,14 @@
                 };
             } else {
                 return new AbstractTupleCalc(call, calcs) {
-                    public Member[] evaluateTuple(Evaluator evaluator) {
+                    public List<Member> evaluateTuple(Evaluator evaluator) {
                         final List list = listCalc.evaluateList(evaluator);
                         assert list != null;
                         final int index = indexCalc.evaluateInteger(evaluator);
-                        int listSize = list.size();
-                        if (index >= listSize || index < 0) {
+                        try {
+                            return (List<Member>) list.get(index);
+                        } catch(IndexOutOfBoundsException e) {
                             return nullTuple;
-                        } else {
-                            return (Member[]) list.get(index);
                         }
                     }
                 };
@@ -179,11 +179,10 @@
                         final List list = listCalc.evaluateList(evaluator);
                         assert list != null;
                         final int index = indexCalc.evaluateInteger(evaluator);
-                        int listSize = list.size();
-                        if (index >= listSize || index < 0) {
-                            return nullMember;
-                        } else {
+                        try {
                             return (Member) list.get(index);
+                        } catch(IndexOutOfBoundsException e) {
+                            return nullMember;
                         }
                     }
                 };
Index: src/main/mondrian/olap/fun/HeadTailFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/HeadTailFunDef.java	
+++ src/main/mondrian/olap/fun/HeadTailFunDef.java	
@@ -17,10 +17,10 @@
 import mondrian.calc.IntegerCalc;
 import mondrian.calc.impl.ConstantCalc;
 import mondrian.calc.impl.AbstractListCalc;
+import mondrian.util.UnsupportedList;
 import mondrian.mdx.ResolvedFunCall;
 
-import java.util.List;
-import java.util.Collections;
+import java.util.*;
 
 /**
  * Definition of the <code>Head</code> and <code>Tail</code>
@@ -60,7 +60,8 @@
                 compiler.compileInteger(call.getArg(1)) :
                 ConstantCalc.constantInteger(1);
         if (head) {
-            return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
+            return new AbstractListCalc(call, 
+                    new Calc[] {listCalc, integerCalc}) {
                 public List evaluateList(Evaluator evaluator) {
                     List list = listCalc.evaluateList(evaluator);
                     int count = integerCalc.evaluateInteger(evaluator);
@@ -68,8 +69,8 @@
                 }
             };
         } else {
-            return new AbstractListCalc(call, new Calc[] {listCalc, integerCalc}) {
-
+            return new AbstractListCalc(call, 
+                    new Calc[] {listCalc, integerCalc} ) {
                 public List evaluateList(Evaluator evaluator) {
                     List list = listCalc.evaluateList(evaluator);
                     int count = integerCalc.evaluateInteger(evaluator);
@@ -79,7 +80,7 @@
         }
     }
 
-    static List tail(final int count, List members) {
+    static List tail(final int count, final List members) {
         assert members != null;
         final int memberCount = members.size();
         if (count >= memberCount) {
@@ -88,18 +89,47 @@
         if (count <= 0) {
             return Collections.EMPTY_LIST;
         }
-        return members.subList(memberCount - count, memberCount);
+        return new UnsupportedList() {
+                public boolean isEmpty() {
+                    return false;
+                }
+                public int size() {
+                    return Math.min(count, members.size());
+                }
+
+                public Object get(final int idx) {
+                    final int index = idx + memberCount - count;
+                    return members.get(index);
+                }
+
+                public Iterator iterator() {
+                    return new ItrUnknownSize();
+                }
+            };
     }
 
-    static List head(final int count, List members) {
+    static List head(final int count, final List members) {
         assert members != null;
-        if (count >= members.size()) {
-            return members;
-        }
         if (count <= 0) {
             return Collections.EMPTY_LIST;
         }
-        return members.subList(0, count);
+        return new UnsupportedList() {
+                public boolean isEmpty() {
+                    return false;
+                }
+                public int size() {
+                    return Math.min(count, members.size());
+                }
+
+                public Object get(final int index) {
+                    if(index>=count) throw new IndexOutOfBoundsException();
+                    return members.get(index);
+                }
+
+                public Iterator iterator() {
+                    return new ItrUnknownSize();
+                }
+            };
     }
 }
 
Index: src/main/mondrian/olap/fun/OpeningClosingPeriodFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/OpeningClosingPeriodFunDef.java	
+++ src/main/mondrian/olap/fun/OpeningClosingPeriodFunDef.java	
@@ -12,6 +12,8 @@
 */
 package mondrian.olap.fun;
 
+import java.util.*;
+
 import mondrian.olap.*;
 import mondrian.olap.type.MemberType;
 import mondrian.olap.type.Type;
@@ -160,7 +162,7 @@
             Member member,
             Level targetLevel,
             boolean returnFirstDescendant) {
-        Member[] children;
+        List<? extends Member> children;
 
         final int targetLevelDepth = targetLevel.getDepth();
         assertPrecondition(member.getLevel().getDepth() < targetLevelDepth,
@@ -169,11 +171,12 @@
         for (;;) {
             children = schemaReader.getMemberChildren(member);
 
-            if (children.length == 0) {
+            if (children.size() == 0) {
                 return targetLevel.getHierarchy().getNullMember();
             }
 
-            member = children[returnFirstDescendant ? 0 : (children.length - 1)];
+            member = children.get(
+                    returnFirstDescendant ? 0 : (children.size()-1));
 
             if (member.getLevel().getDepth() == targetLevelDepth) {
                 if (member.isHidden()) {
Index: src/main/mondrian/olap/fun/TupleToStrFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/TupleToStrFunDef.java	
+++ src/main/mondrian/olap/fun/TupleToStrFunDef.java	
@@ -19,6 +19,8 @@
 import mondrian.olap.Evaluator;
 import mondrian.olap.Member;
 
+import java.util.*;
+
 /**
  * Definition of the <code>TupleToStr</code> MDX function.
  *
@@ -59,7 +61,7 @@
                     compiler.compileTuple(call.getArg(0));
             return new AbstractStringCalc(call, new Calc[] {tupleCalc}) {
                 public String evaluateString(Evaluator evaluator) {
-                    final Member[] members =
+                    final List<Member> members =
                             tupleCalc.evaluateTuple(evaluator);
                     if (members == null) {
                         return "";
Index: src/main/mondrian/olap/fun/DrilldownLevelFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/DrilldownLevelFunDef.java	
+++ src/main/mondrian/olap/fun/DrilldownLevelFunDef.java	
@@ -97,7 +97,8 @@
             //
             if (member.getLevel().getDepth() == searchDepth
                     && !FunUtil.isAncestorOf(member, nextMember, true)) {
-                Member[] childMembers = evaluator.getSchemaReader().getMemberChildren(member);
+                final List<? extends Member> childMembers = 
+                        evaluator.getSchemaReader().getMemberChildren(member);
                 for (Member childMember : childMembers) {
                     drilledSet.add(childMember);
                 }
Index: src/main/mondrian/olap/fun/ExceptFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/ExceptFunDef.java	
+++ src/main/mondrian/olap/fun/ExceptFunDef.java	
@@ -20,6 +20,7 @@
 import mondrian.calc.ListCalc;
 import mondrian.calc.impl.AbstractListCalc;
 import mondrian.mdx.ResolvedFunCall;
+import mondrian.util.FilteredIterableList;
 
 import java.util.*;
 
@@ -34,7 +35,8 @@
     static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
             "Except",
             "Except(<Set1>, <Set2>[, ALL])",
-            "Finds the difference between two sets, optionally retaining duplicates.",
+            "Finds the difference between two sets, optionally "
+                    + "retaining duplicates.",
             new String[]{"fxxx", "fxxxy"},
             ExceptFunDef.class);
 
@@ -44,19 +46,21 @@
 
     public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
         // todo: implement ALL
-        final ListCalc listCalc0 =
-                compiler.compileList(call.getArg(0));
-        final ListCalc listCalc1 =
-                compiler.compileList(call.getArg(1));
-        final Type elementType = ((SetType) listCalc0.getType()).getElementType();
+        final ListCalc listCalc0 = compiler.compileList(call.getArg(0));
+        final ListCalc listCalc1 = compiler.compileList(call.getArg(1));
+        final Type elementType = ((SetType) 
+                listCalc0.getType()).getElementType();
         if (elementType instanceof TupleType) {
-            return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) {
+            return new AbstractListCalc(call, new Calc[] 
+                    {listCalc0, listCalc1}) {
                 public List evaluateList(Evaluator evaluator) {
-                    List<Member[]> list0 = listCalc0.evaluateList(evaluator);
+                    List<List<Member>> list0 = 
+                            listCalc0.evaluateList(evaluator);
                     if (list0.isEmpty()) {
                         return list0;
                     }
-                    List<Member[]> list1 = listCalc1.evaluateList(evaluator);
+                    List<List<Member>> list1 = 
+                            listCalc1.evaluateList(evaluator);
                     return exceptTuples(list0, list1);
                 }
             };
@@ -75,39 +79,31 @@
     }
 
     <T> List<T> except(final List<T> list0, final List<T> list1) {
-        if (list0.size() == 0) {
+        if (list0.isEmpty()) {
             return list0;
         }
-        Set<T> set = new HashSet<T>(list1);
-        List<T> result = new ArrayList<T>();
-        for (int i = 0, count = list0.size(); i < count; i++) {
-            T o = list0.get(i);
-            if (!set.contains(o)) {
-                result.add(o);
-            }
-        }
-        return result;
+        final Set<T> set = new HashSet<T>(list1);
+        return new FilteredIterableList<T>(list0, 
+                new FilteredIterableList.Filter<T>() {
+                    public boolean accept(final T o) {
+                        return !set.contains(o);
+                    }});
     }
 
-    List exceptTuples(final List<Member[]> list0, final List list1) {
-        if (list0.size() == 0) {
+    List exceptTuples(final List<List<Member>> list0, final List list1) {
+        if (list0.isEmpty()) {
             return list0;
         }
-        // Because the .equals and .hashCode methods of
-        // Member[] use identity, wrap each tuple in a list.
-        Set<List<Member>> set = new HashSet<List<Member>>();
-        for (int i = 0, count1 = list1.size(); i < count1; i++) {
-            Member[] members = (Member[]) list1.get(i);
-            set.add(Arrays.asList(members));
+        final Set<List<Member>> set = new HashSet<List<Member>>();
+        for(final Object members : list1) {
+            set.add((List<Member>)members);
         }
-        List<Member[]> result = new ArrayList<Member[]>();
-        for (int i = 0, count0 = list0.size(); i < count0; i++) {
-            Member[] members = list0.get(i);
-            if (!set.contains(Arrays.asList(members))) {
-                result.add(members);
-            }
-        }
-        return result;
+
+        return new FilteredIterableList<List<Member>>(list0, 
+                new FilteredIterableList.Filter<List<Member>>() {
+                    public boolean accept(final List<Member> o) {
+                        return !set.contains(o);
+                    }});
     }
 }
 
Index: src/main/mondrian/olap/fun/RankFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/RankFunDef.java	
+++ src/main/mondrian/olap/fun/RankFunDef.java	
@@ -107,7 +107,8 @@
         private final TupleCalc tupleCalc;
         private final Calc listCalc;
 
-        public Rank2TupleCalc(ResolvedFunCall call, TupleCalc tupleCalc, Calc listCalc) {
+        public Rank2TupleCalc(ResolvedFunCall call, TupleCalc tupleCalc, 
+                Calc listCalc) {
             super(call, new Calc[] {tupleCalc, listCalc});
             this.tupleCalc = tupleCalc;
             this.listCalc = listCalc;
@@ -117,7 +118,8 @@
             // Get member or tuple.
             // If the member is null (or the tuple contains a null member)
             // the result is null (even if the list is null).
-            final Member[] members = tupleCalc.evaluateTuple(evaluator);
+            final List<Member> members = 
+                    tupleCalc.evaluateTuple(evaluator);
             if (members == null) {
                 return DoubleNull;
             }
@@ -193,7 +195,7 @@
         }
 
         public double evaluateDouble(Evaluator evaluator) {
-            Member[] members = tupleCalc.evaluateTuple(evaluator);
+            List<Member> members = tupleCalc.evaluateTuple(evaluator);
             if (members == null) {
                 return DoubleNull;
             }
@@ -349,7 +351,7 @@
                     Member member = (Member) o;
                     evaluator2.setContext(member);
                 } else {
-                    evaluator2.setContext((Member[]) o);
+                    evaluator2.setContext((List<Member>) o);
                 }
                 final Object value = sortCalc.evaluate(evaluator2);
                 if (value instanceof RuntimeException) {
@@ -462,13 +464,11 @@
         Map<Object, Integer> map = new HashMap<Object, Integer>();
 
         RankedList(List members) {
-            for (int i = 0; i < members.size(); i++) {
-                Object o = members.get(i);
+            int i = 0;
+            for(final Object o : members) {
                 final Object key;
-                if (o instanceof Member) {
+                if (o instanceof Member || o instanceof List) {
                     key = o;
-                } else if (o instanceof Member[]) {
-                    key = Arrays.asList((Member []) o);
                 } else {
                     throw Util.newInternal("bad member/tuple " + o);
                 }
@@ -478,6 +478,7 @@
                     // it back.
                     map.put(key, value);
                 }
+                i++;
             }
         }
 
Index: src/main/mondrian/olap/fun/TupleItemFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/TupleItemFunDef.java	
+++ src/main/mondrian/olap/fun/TupleItemFunDef.java	
@@ -20,6 +20,8 @@
 import mondrian.calc.impl.AbstractMemberCalc;
 import mondrian.mdx.ResolvedFunCall;
 
+import java.util.*;
+
 /**
  * Definition of the <code>&lt;Tuple&gt;.Item</code> MDX function.
  *
@@ -75,22 +77,23 @@
                     compiler.compileTuple(call.getArg(0));
             final IntegerCalc indexCalc =
                     compiler.compileInteger(call.getArg(1));
-            return new AbstractMemberCalc(call, new Calc[] {tupleCalc, indexCalc}) {
-                final Member[] nullTupleMembers =
+            return new AbstractMemberCalc(call, new Calc[] {
+                                                tupleCalc, indexCalc}) {
+                final List<Member> nullTupleMembers =
                         makeNullTuple((TupleType) tupleCalc.getType());
                 public Member evaluateMember(Evaluator evaluator) {
-                    final Member[] members =
+                    final List<Member> members =
                             tupleCalc.evaluateTuple(evaluator);
                     assert members == null ||
-                            members.length == nullTupleMembers.length;
+                            members.size() == nullTupleMembers.size();
                     final int index = indexCalc.evaluateInteger(evaluator);
                     if (members == null) {
-                        return nullTupleMembers[index];
+                        return nullTupleMembers.get(index);
                     }
-                    if (index >= members.length || index < 0) {
+                    if (index >= members.size()|| index < 0) {
                         return null;
                     }
-                    return members[index];
+                    return members.get(index);
                 }
             };
         }
Index: src/main/mondrian/olap/fun/CrossJoinFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/CrossJoinFunDef.java	
+++ src/main/mondrian/olap/fun/CrossJoinFunDef.java	
@@ -283,7 +283,7 @@
          * @param o2 List or Iterable of Member or Member[]
          * @return Iterable&lt;Member[]&gt; over contents of o1 and o2
          */
-        protected abstract Iterable<Member[]> makeIterable(Object o1, Object o2);
+        protected abstract Iterable<List<Member>> makeIterable(Object o1, Object o2);
 
         /**
          * Derived classes implement depending upon the types of parameter
@@ -293,9 +293,9 @@
          * @param o2 Member or Member[]
          * @return combining o1 and o2 into Member[]
          */
-        protected abstract Member[] makeNext(Object o1, Object o2);
+        protected abstract List<Member> makeNext(Object o1, Object o2);
 
-        protected Iterable<Member[]> makeIterableIterable(
+        protected Iterable<List<Member>> makeIterableIterable(
             final Iterable it1,
             final Iterable it2)
         {
@@ -303,9 +303,9 @@
             // are or how many null members they might have, so all
             // one can do is iterate across them:
             // iterate across it1 and for each member iterate across it2
-            Iterable<Member[]> iterable = new Iterable<Member[]>() {
-                public Iterator<Member[]> iterator() {
-                    return new Iterator<Member[]>() {
+            Iterable<List<Member>> iterable = new Iterable<List<Member>>() {
+                public Iterator<List<Member>> iterator() {
+                    return new Iterator<List<Member>>() {
                         Iterator i1 = it1.iterator();
                         Object o1 = null;
                         Iterator i2 = it2.iterator();
@@ -331,7 +331,7 @@
                             }
                             return true;
                         }
-                        public Member[] next() {
+                        public List<Member> next() {
                             try {
                                 return makeNext(o1, o2);
                             } finally {
@@ -368,13 +368,13 @@
             return iterable;
         }
 
-        protected Iterable<Member[]> makeIterableList(
+        protected Iterable<List<Member>> makeIterableList(
             final Iterable it1,
             final List l2)
         {
-            Iterable<Member[]> iterable = new Iterable<Member[]>() {
-                public Iterator<Member[]> iterator() {
-                    return new Iterator<Member[]>() {
+            Iterable<List<Member>> iterable = new Iterable<List<Member>>() {
+                public Iterator<List<Member>> iterator() {
+                    return new Iterator<List<Member>>() {
                         Iterator i1 = it1.iterator();
                         Object o1 = null;
                         int index2 = 0;
@@ -400,7 +400,7 @@
                             }
                             return true;
                         }
-                        public Member[] next() {
+                        public List<Member> next() {
                             try {
                                 return makeNext(o1, o2);
                             } finally {
@@ -436,13 +436,13 @@
             return iterable;
         }
 
-        protected Iterable<Member[]> makeListIterable(
+        protected Iterable<List<Member>> makeListIterable(
             final List l1,
             final Iterable it2)
         {
-            Iterable<Member[]> iterable = new Iterable<Member[]>() {
-                public Iterator<Member[]> iterator() {
-                    return new Iterator<Member[]>() {
+            Iterable<List<Member>> iterable = new Iterable<List<Member>>() {
+                public Iterator<List<Member>> iterator() {
+                    return new Iterator<List<Member>>() {
                         int index1 = 0;
                         Object o1 = null;
                         Iterator i2 = it2.iterator();
@@ -468,7 +468,7 @@
                             }
                             return true;
                         }
-                        public Member[] next() {
+                        public List<Member> next() {
                             try {
                                 return makeNext(o1, o2);
                             } finally {
@@ -505,13 +505,13 @@
             return iterable;
         }
 
-        protected Iterable<Member[]> makeListList(
+        protected Iterable<List<Member>> makeListList(
             final List l1,
             final List l2)
         {
-            Iterable<Member[]> iterable = new Iterable<Member[]>() {
-                public Iterator<Member[]> iterator() {
-                    return new Iterator<Member[]>() {
+            Iterable<List<Member>> iterable = new Iterable<List<Member>>() {
+                public Iterator<List<Member>> iterator() {
+                    return new Iterator<List<Member>>() {
                         int index1 = 0;
                         Object o1 = null;
                         int index2 = 0;
@@ -537,7 +537,7 @@
                             }
                             return true;
                         }
-                        public Member[] next() {
+                        public List<Member> next() {
                             try {
                                 return makeNext(o1, o2);
                             } finally {
@@ -582,8 +582,8 @@
         BaseMemberMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Member[] makeNext(Object o1, Object o2) {
-            return new Member[] {(Member) o1, (Member) o2};
+        protected List<Member> makeNext(Object o1, Object o2) {
+            return Arrays.asList(new Member[] {(Member) o1, (Member) o2});
         }
     }
 
@@ -593,12 +593,12 @@
         BaseMemberMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Member[] makeNext(Object o1, Object o2) {
+        protected List<Member> makeNext(Object o1, Object o2) {
             Member m1 = (Member) o1;
-            Member[] ma2 = (Member[]) o2;
-            Member[] ma = new Member[ma2.length+1];
-            ma[0] = m1;
-            System.arraycopy(ma2, 0, ma, 1, ma2.length);
+            List<Member> ma2 = (List<Member>) o2;
+            List<Member> ma = new ArrayList<Member>();
+            ma.add(m1);
+            ma.addAll(ma2);
             return ma;
         }
     }
@@ -609,12 +609,11 @@
         BaseMemberArrayMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Member[] makeNext(Object o1, Object o2) {
-            Member[] ma1 = (Member[]) o1;
+        protected List<Member> makeNext(Object o1, Object o2) {
+            List<Member> ma1 = (List<Member>) o1;
             Member m2 = (Member) o2;
-            Member[] ma = new Member[ma1.length+1];
-            System.arraycopy(ma1, 0, ma, 0, ma1.length);
-            ma[ma1.length] = m2;
+            List<Member> ma = new ArrayList<Member>(ma1);
+            ma.add(m2);
             return ma;
         }
     }
@@ -625,12 +624,12 @@
         BaseMemberArrayMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Member[] makeNext(Object o1, Object o2) {
-            Member[] ma1 = (Member[]) o1;
-            Member[] ma2 = (Member[]) o2;
-            Member[] ma = new Member[ma1.length+ma2.length];
-            System.arraycopy(ma1, 0, ma, 0, ma1.length);
-            System.arraycopy(ma2, 0, ma, ma1.length, ma2.length);
+        protected List<Member> makeNext(Object o1, Object o2) {
+            List<Member> ma1 = (List<Member>) o1;
+            List<Member> ma2 = (List<Member>) o2;
+            List<Member> ma = new ArrayList<Member>();
+            ma.addAll(ma1);
+            ma.addAll(ma2);
             return ma;
         }
     }
@@ -643,7 +642,7 @@
         IterMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             Iterable<Member> it1 = (Iterable<Member>) o1;
             Iterable<Member> it2 = (Iterable<Member>) o2;
             return makeIterableIterable(it1, it2);
@@ -656,7 +655,7 @@
         IterMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             Iterable<Member> it1 = (Iterable<Member>) o1;
             List<Member> l2 = (List<Member>) o2;
 
@@ -675,7 +674,7 @@
         ListMemberIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             List<Member> l1 = (List<Member>) o1;
             Iterable<Member> it2 = (Iterable<Member>) o2;
 
@@ -695,7 +694,7 @@
         ListMemberListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             List<Member> l1 = (List<Member>) o1;
             List<Member> l2 = (List<Member>) o2;
 
@@ -729,9 +728,9 @@
         IterMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             Iterable<Member> it1 = (Iterable<Member>) o1;
-            Iterable<Member[]> it2 = (Iterable<Member[]>) o2;
+            Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2;
             return makeIterableIterable(it1, it2);
         }
     }
@@ -742,9 +741,9 @@
         IterMemberListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             Iterable<Member> it1 = (Iterable<Member>) o1;
-            List<Member[]> l2 = (List<Member[]>) o2;
+            List<List<Member>> l2 = (List<List<Member>>) o2;
 
             if (l2 instanceof RandomAccess) {
                 // direct access faster
@@ -762,9 +761,9 @@
         ListMemberIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             List<Member> l1 = (List<Member>) o1;
-            Iterable<Member[]> it2 = (Iterable<Member[]>) o2;
+            Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2;
 
             if (l1 instanceof RandomAccess) {
                 // direct access faster
@@ -782,9 +781,9 @@
         ListMemberListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
             List<Member> l1 = (List<Member>) o1;
-            List<Member[]> l2 = (List<Member[]>) o2;
+            List<List<Member>> l2 = (List<List<Member>>) o2;
 
             if (l1 instanceof RandomAccess) {
                 // l1 direct access faster
@@ -816,8 +815,8 @@
         IterMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            Iterable<Member[]> it1 = (Iterable<Member[]>) o1;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1;
             Iterable<Member> it2 = (Iterable<Member>) o2;
             return makeIterableIterable(it1, it2);
         }
@@ -829,8 +828,8 @@
         IterMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            Iterable<Member[]> it1 = (Iterable<Member[]>) o1;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1;
             List<Member> l2 = (List<Member>) o2;
 
             if (l2 instanceof RandomAccess) {
@@ -849,8 +848,8 @@
         ListMemberArrayIterMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            List<Member[]> l1 = (List<Member[]>) o1;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            List<List<Member>> l1 = (List<List<Member>>) o1;
             Iterable<Member> it2 = (Iterable<Member>) o2;
 
             if (l1 instanceof RandomAccess) {
@@ -869,8 +868,8 @@
         ListMemberArrayListMemberIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            List<Member[]> l1 = (List<Member[]>) o1;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            List<List<Member>> l1 = (List<List<Member>>) o1;
             List<Member> l2 = (List<Member>) o2;
 
             if (l1 instanceof RandomAccess) {
@@ -903,9 +902,9 @@
         IterMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            Iterable<Member[]> it1 = (Iterable<Member[]>) o1;
-            Iterable<Member[]> it2 = (Iterable<Member[]>) o2;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1;
+            Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2;
             return makeIterableIterable(it1, it2);
         }
     }
@@ -916,9 +915,9 @@
         IterMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            Iterable<Member[]> it1 = (Iterable<Member[]>) o1;
-            List<Member[]> l2 = (List<Member[]>) o2;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            Iterable<List<Member>> it1 = (Iterable<List<Member>>) o1;
+            List<List<Member>> l2 = (List<List<Member>>) o2;
 
             if (l2 instanceof RandomAccess) {
                 // direct access faster
@@ -936,9 +935,9 @@
         ListMemberArrayIterMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            List<Member[]> l1 = (List<Member[]>) o1;
-            Iterable<Member[]> it2 = (Iterable<Member[]>) o2;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            List<List<Member>> l1 = (List<List<Member>>) o1;
+            Iterable<List<Member>> it2 = (Iterable<List<Member>>) o2;
 
             if (l1 instanceof RandomAccess) {
                 // direct access faster
@@ -956,9 +955,9 @@
         ListMemberArrayListMemberArrayIterCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs);
         }
-        protected Iterable<Member[]> makeIterable(Object o1, Object o2) {
-            List<Member[]> l1 = (List<Member[]>) o1;
-            List<Member[]> l2 = (List<Member[]>) o2;
+        protected Iterable<List<Member>> makeIterable(Object o1, Object o2) {
+            List<List<Member>> l1 = (List<List<Member>>) o1;
+            List<List<Member>> l2 = (List<List<Member>>) o2;
 
             if (l1 instanceof RandomAccess) {
                 // l1 direct access faster
@@ -1049,7 +1048,7 @@
                     boolean mutable) {
             super(call, calcs, mutable);
         }
-        public List<Member[]> evaluateList(Evaluator evaluator) {
+        public List<List<Member>> evaluateList(Evaluator evaluator) {
             ResolvedFunCall call = (ResolvedFunCall) exp;
             // Use a native evaluator, if more efficient.
             // TODO: Figure this out at compile time.
@@ -1089,15 +1088,15 @@
             return makeList(l1, l2);
         }
 
-        protected abstract List<Member[]> makeList(List l1, List l2);
+        protected abstract List<List<Member>> makeList(List l1, List l2);
     }
 
     public abstract class BaseImmutableList
-                            extends UnsupportedList<Member[]> {
+                            extends UnsupportedList<List<Member>> {
         protected BaseImmutableList() {
         }
         public abstract int size();
-        public abstract Member[] get(int index);
+        public abstract List<Member> get(int index);
 
         public Object[] toArray() {
             int size = size();
@@ -1107,21 +1106,21 @@
             }
             return result;
         }
-        public List<Member[]> toArrayList() {
-            List<Member[]> l = new ArrayList<Member[]>(size());
+        public List<List<Member>> toArrayList() {
+            List<List<Member>> l = new ArrayList<List<Member>>(size());
             Iterator i = iterator();
             while (i.hasNext()) {
-                l.add((Member[]) i.next());
+                l.add((List<Member>) i.next());
             }
             return l;
         }
-        public ListIterator<Member[]> listIterator() {
+        public ListIterator<List<Member>> listIterator() {
             return new ListItr(0);
         }
-        public ListIterator<Member[]> listIterator(int index) {
+        public ListIterator<List<Member>> listIterator(int index) {
             return new ListItr(index);
         }
-        public Iterator<Member[]> iterator() {
+        public Iterator<List<Member>> iterator() {
             return new Itr();
         }
     }
@@ -1132,7 +1131,7 @@
         ImmutableListMemberListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, false);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
+        protected List<List<Member>> makeList(final List l1, final List l2) {
             final int size = l1.size() * l2.size();
             // This is the mythical "local class" declaration.
             // Observer that in the subList method, there is another
@@ -1155,14 +1154,14 @@
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = (index / l2.size());
                     int j = (index % l2.size());
                     Member m1 = (Member) l1.get(i);
                     Member m2 = (Member) l2.get(j);
-                    return new Member[] { m1, m2 };
+                    return Arrays.asList(new Member[] { m1, m2 });
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     class Inner extends Outer {
                         int fromIndex;
                         int toIndex;
@@ -1173,10 +1172,10 @@
                         public int size() {
                             return (this.toIndex - this.fromIndex);
                         }
-                        public Member[] get(int index) {
+                        public List<Member> get(int index) {
                             return Outer.this.get(index + this.fromIndex);
                         }
-                        public List<Member[]> subList(int fromIndex, int toIndex) {
+                        public List<List<Member>> subList(int fromIndex, int toIndex) {
                             return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
                         }
                     }
@@ -1193,25 +1192,25 @@
         ImmutableListMemberListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, false);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
-            final int len2 = ((Member[])l2.get(0)).length;
+        protected List<List<Member>> makeList(final List l1, final List l2) {
+            final int len2 = ((List<Member>)l2.get(0)).size();
             final int size = (l1.size() * l2.size());
             class Outer extends BaseImmutableList {
                 Outer() {}
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = (index / l2.size());
                     int j = (index % l2.size());
-                    Member[] ma = new Member[1 + len2];
+                    List<Member> ma = new ArrayList<Member>();
                     Member m1 = (Member) l1.get(i);
-                    Member[] ma2 = (Member[]) l2.get(j);
-                    ma[0] = m1;
-                    System.arraycopy(ma2, 0, ma, 1, len2);
+                    List<Member> ma2 = (List<Member>) l2.get(j);
+                    ma.add(m1);
+                    ma.addAll(ma2);
                     return ma;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     class Inner extends Outer {
                         int fromIndex;
                         int toIndex;
@@ -1222,10 +1221,10 @@
                         public int size() {
                             return (this.toIndex - this.fromIndex);
                         }
-                        public Member[] get(int index) {
+                        public List<Member> get(int index) {
                             return Outer.this.get(index + this.fromIndex);
                         }
-                        public List<Member[]> subList(int fromIndex, int toIndex) {
+                        public List<List<Member>> subList(int fromIndex, int toIndex) {
                             return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
                         }
                     }
@@ -1241,25 +1240,24 @@
         ImmutableListMemberArrayListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, false);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
-            final int len1 = ((Member[])l1.get(0)).length;
+        protected List<List<Member>> makeList(final List l1, final List l2) {
+            final int len1 = ((List<Member>)l1.get(0)).size();
             final int size = (l1.size() * l2.size());
             class Outer extends BaseImmutableList {
                 Outer() {}
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = (index / l2.size());
                     int j = (index % l2.size());
-                    Member[] ma = new Member[len1 + 1];
-                    Member[] ma1 = (Member[]) l1.get(i);
+                    List<Member> ma1 = (List<Member>) l1.get(i);
+                    List<Member> ma = new ArrayList<Member>(ma1);
                     Member m2 = (Member) l2.get(j);
-                    System.arraycopy(ma1, 0, ma, 0, len1);
-                    ma[len1] = m2;
+                    ma.add(m2);
                     return ma;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     class Inner extends Outer {
                         int fromIndex;
                         int toIndex;
@@ -1270,10 +1268,10 @@
                         public int size() {
                             return (this.toIndex - this.fromIndex);
                         }
-                        public Member[] get(int index) {
+                        public List<Member> get(int index) {
                             return Outer.this.get(index + this.fromIndex);
                         }
-                        public List<Member[]> subList(int fromIndex, int toIndex) {
+                        public List<List<Member>> subList(int fromIndex, int toIndex) {
                             return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
                         }
                     }
@@ -1289,9 +1287,9 @@
         ImmutableListMemberArrayListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, false);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
-            final int len1 = ((Member[])l1.get(0)).length;
-            final int len2 = ((Member[])l2.get(0)).length;
+        protected List<List<Member>> makeList(final List l1, final List l2) {
+            final int len1 = ((List<Member>)l1.get(0)).size();
+            final int len2 = ((List<Member>)l2.get(0)).size();
             final int size = (l1.size() * l2.size());
 
             class Outer extends BaseImmutableList {
@@ -1299,17 +1297,17 @@
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = (index / l2.size());
                     int j = (index % l2.size());
-                    Member[] ma = new Member[len1 + len2];
-                    Member[] ma1 = (Member[]) l1.get(i);
-                    Member[] ma2 = (Member[]) l2.get(j);
-                    System.arraycopy(ma1, 0, ma, 0, len1);
-                    System.arraycopy(ma2, 0, ma, len1, len2);
+                    List<Member> ma = new ArrayList<Member>();
+                    List<Member> ma1 = (List<Member>) l1.get(i);
+                    List<Member> ma2 = (List<Member>) l2.get(j);
+                    ma.addAll(ma1);
+                    ma.addAll(ma2);
                     return ma;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     class Inner extends Outer {
                         int fromIndex;
                         int toIndex;
@@ -1320,10 +1318,10 @@
                         public int size() {
                             return (this.toIndex - this.fromIndex);
                         }
-                        public Member[] get(int index) {
+                        public List<Member> get(int index) {
                             return Outer.this.get(index + this.fromIndex);
                         }
-                        public List<Member[]> subList(int fromIndex, int toIndex) {
+                        public List<List<Member>> subList(int fromIndex, int toIndex) {
                             return new Inner(this.fromIndex+fromIndex, this.fromIndex+toIndex);
                         }
                     }
@@ -1385,16 +1383,16 @@
      * supported).
      */
     public abstract class BaseMutableList
-                            extends UnsupportedList<Member[]> {
-        protected final Member[] members;
-        protected BaseMutableList(Member[] members) {
+                            extends UnsupportedList<List<Member>> {
+        protected final List<Member> members;
+        protected BaseMutableList(List<Member> members) {
             this.members = members;
         }
         public abstract int size();
-        public abstract Member[] get(int index);
-        public abstract Member[] set(int index, Member[] element);
-        public abstract Member[] remove(int index);
-        public abstract List<Member[]> subList(int fromIndex, int toIndex);
+        public abstract List<Member> get(int index);
+        public abstract List<Member> set(int index, List<Member> element);
+        public abstract List<Member> remove(int index);
+        public abstract List<List<Member>> subList(int fromIndex, int toIndex);
 
         public Object[] toArray() {
             int size = size();
@@ -1404,21 +1402,21 @@
             }
             return result;
         }
-        public List<Member[]> toArrayList() {
-            List<Member[]> l = new ArrayList<Member[]>(size());
+        public List<List<Member>> toArrayList() {
+            List<List<Member>> l = new ArrayList<List<Member>>(size());
             Iterator i = iterator();
             while (i.hasNext()) {
-                l.add((Member[]) i.next());
+                l.add((List<Member>) i.next());
             }
             return l;
         }
-        public ListIterator<Member[]> listIterator() {
+        public ListIterator<List<Member>> listIterator() {
             return new LocalListItr(0);
         }
-        public ListIterator<Member[]> listIterator(int index) {
+        public ListIterator<List<Member>> listIterator(int index) {
             return new LocalListItr(index);
         }
-        public Iterator<Member[]> iterator() {
+        public Iterator<List<Member>> iterator() {
             return new LocalItr();
         }
         private class LocalItr extends Itr {
@@ -1447,7 +1445,7 @@
             public LocalListItr(int index) {
                 super(index);
             }
-            public void set(Member[] o) {
+            public void set(List<Member> o) {
                 if (lastRet == -1)
                     throw new IllegalStateException();
                 try {
@@ -1461,79 +1459,75 @@
     }
 
     // LIST Member LIST Member
-    class MutableListMemberListMemberListCalc
-            extends BaseListCalc {
-        MutableListMemberListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
+    class MutableListMemberListMemberListCalc extends BaseListCalc {
+        MutableListMemberListMemberListCalc(final ResolvedFunCall call, 
+                final Calc[] calcs) {
             super(call, calcs, true);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
-            int size1 = l1.size();
-            // len1 == 1
-            int size2 = l2.size();
-            // len2 == 1
-            int arraySize = (2 * (size1 * size2));
+        protected List<List<Member>> makeList(final List l1, final List l2) {
+            if(l1.isEmpty() || l2.isEmpty()) return Collections.EMPTY_LIST;
 
-            Member[] members = new Member[arraySize];
-            for (int i = 0; i < size1; i++) {
-                Member m1 = (Member) l1.get(i);
-                int ii = i*size2;
-                for (int j = 0; j < size2; j++) {
-                    Member m2 = (Member) l2.get(j);
-                    members[2*(ii + j)] = m1;
-                    members[2*(ii + j)+1] = m2;
+            final Iterator it1 = l1.iterator();
+            final Member first = (Member) it1.next();
+            if(first.getDimension().isHighCardinality()) {
+                return new AbstractSequentialList<List<Member>>() {
+                    public int size() {
+                        return l1.size() * l2.size();
+                    }
+                    public ListIterator<List<Member>> listIterator(
+                            final int index) {
+                        return new ListIterator<List<Member>>() {
+                            private int idx = 0;
+                            private Member m1 = first;
+                            private Iterator it2 = l2.iterator();
+                            public boolean hasNext() {
+                                return it2.hasNext() || it1.hasNext();
+                            }
+                            public List<Member> next() {
+                               if(!it2.hasNext()) {
+                                    it2 = l2.iterator();
+                                    m1 = (Member) it1.next();
+                                }
+                                idx++;
+                                return Arrays.asList(new Member[] { 
+                                            (Member) m1, (Member) it2.next() });
+                            }
+                            public int nextIndex() {
+                                return idx;
+                            }
+                            public void add(final List<Member> t) {
+                                throw new UnsupportedOperationException();
+                            }
+                            public void set(final List<Member> t) {
+                                throw new UnsupportedOperationException();
+                            }
+                            public boolean hasPrevious() {
+                                throw new UnsupportedOperationException();
+                            }
+                            public List<Member> previous() {
+                                throw new UnsupportedOperationException();
+                            }
+                            public int previousIndex() {
+                                throw new UnsupportedOperationException();
+                            }
+                            public void remove() {
+                                throw new UnsupportedOperationException();
+                            }
+                        };
+                    }
+                };
+            } else {
+                final List<List<Member>> members=new ArrayList<List<Member>>();
+                for(final Object o1 : l1) {
+                    final Member m1 = (Member) o1;
+                    for(final Object o2 : l2) {
+                        Member m2 = (Member) o2;
+                        members.add(Arrays.asList(new Member [] {m1,m2}));
+                    }
                 }
+                return members;
             }
-            return makeList(members);
         }
-        protected List<Member[]> makeList(Member[] members) {
-            // externally looks like:
-            //  [] <- [a][A]
-            //  [] <- [a][B]
-            //  ...
-            //  [] <- [m][N]
-            //
-            // but internally is:
-            //  [a][A][a][B] ... [m][M][m][N]
-            List<Member[]> list = new BaseMutableList(members) {
-                int size = members.length/2;
-                public int size() {
-                    return size;
-                }
-                public Member[] get(int index) {
-                    int i = index+index;
-                    return new Member[] { members[i], members[i+1] };
-                }
-                public Member[] set(int index, Member[] element) {
-                    int i = index+index;
-                    Member[] oldValue =
-                        new Member[] { members[i], members[i+1] };
-
-                    members[i] = element[0];
-                    members[i+1] = element[1];
-
-                    return oldValue;
-                }
-                public Member[] remove(int index) {
-                    int i = index+index;
-                    Member[] oldValue =
-                        new Member[] { members[i], members[i+1] };
-
-                    System.arraycopy(members, i+2, members, i,
-                            members.length - (i+2));
-
-                    size--;
-                    return oldValue;
-                }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
-                    int from = fromIndex + fromIndex;
-                    int to = toIndex + toIndex;
-                    Member[] sublist = new Member[to - from];
-                    System.arraycopy(members, from, sublist, 0, to - from);
-                    return makeList(sublist);
-                }
-            };
-            return list;
-        }
     }
 
     // LIST Member LIST Member[]
@@ -1542,31 +1536,31 @@
         MutableListMemberListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, true);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
+        protected List<List<Member>> makeList(final List l1, final List l2) {
             int size1 = l1.size();
             // len1 == 1
             int size2 = l2.size();
-            int len2 = ((Member[])l2.get(0)).length;
+            int len2 = ((List<Member>)l2.get(0)).size();
             int totalLen = 1+len2;
             int arraySize = (totalLen * (size1 * size2));
 
-            Member[] members = new Member[arraySize];
+            final List<Member> members = new ArrayList<Member>(arraySize);
             for (int i = 0; i < size1; i++) {
                 Member m1 = (Member) l1.get(i);
                 int ii = i*size2;
                 for (int j = 0; j < size2; j++) {
-                    Member[] ma2 = (Member[]) l2.get(j);
-                    members[totalLen*(ii + j)] = m1;
-                    for (int k = 0; k < len2; k++) {
-                        Member m2 = (Member) ma2[k];
-                        members[totalLen*(ii + j)+k+1] = m2;
+                    final List<Member> ma2 = (List<Member>) (l2.get(j));
+                    members.add(m1);
+                    for(int k=0; k<len2; k++) {
+                        final Member m2 = ma2.get(k);
+                        members.add(m2);
                     }
                 }
             }
-
             return makeList(members, totalLen);
         }
-        protected List<Member[]> makeList(Member[] members, final int totalLen) {
+        protected List<List<Member>> makeList(final List<Member> members, 
+                final int totalLen) {
             // l1: a,b
             // l2: {A,B,C},{D,E,F}
             //
@@ -1578,43 +1572,39 @@
             //
             // but internally is:
             // a,A,B,C,a,D,E,F,b,A,B,C,b,D,E,F
-            List<Member[]> list = new BaseMutableList(members) {
-                int size = members.length/totalLen;
+            //
+            List<List<Member>> list = new BaseMutableList(members) {
+                int size = members.size()/totalLen;
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = totalLen*index;
-                    Member[] ma = new Member[totalLen];
-                    System.arraycopy(members, i, ma, 0, totalLen);
+                    final List<Member> ma = new ArrayList<Member>();
+                    ma.addAll(members.subList(i, i+totalLen));
                     return ma;
                 }
-                public Member[] set(int index, Member[] element) {
+                public List<Member> set(int index, List<Member> element) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(element, 0, members, i, totalLen);
-
+                    List<Member> oldValue = new ArrayList<Member>();
+                    oldValue.addAll(members.subList(i, totalLen+i));
+                    for(int j=0; j<totalLen; j++) {
+                        members.set(i+j, element.get(j));
+                    }
                     return oldValue;
                 }
-                public Member[] remove(int index) {
+                public List<Member> remove(int index) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(members, i+totalLen,
-                            members, i,
-                            members.length-(i+totalLen));
-
+                    List<Member> oldValue = new ArrayList<Member>(
+                            members.subList(i, i+totalLen));
+                    members.subList(i, i+totalLen).clear();
                     size--;
                     return oldValue;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     int from = totalLen*fromIndex;
                     int to = totalLen*toIndex;
-                    Member[] sublist = new Member[to - from];
-                    System.arraycopy(members, from, sublist, 0, to - from);
+                    final List<Member> sublist = members.subList(from, to);
                     return makeList(sublist, totalLen);
                 }
             };
@@ -1624,12 +1614,13 @@
     // LIST Member[] LIST Member
     class MutableListMemberArrayListMemberListCalc
             extends BaseListCalc {
-        MutableListMemberArrayListMemberListCalc(ResolvedFunCall call, Calc[] calcs) {
+        MutableListMemberArrayListMemberListCalc(final ResolvedFunCall call, 
+                final Calc[] calcs) {
             super(call, calcs, true);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
+        protected List<List<Member>> makeList(final List l1, final List l2) {
             int size1 = l1.size();
-            int len1 = ((Member[])l1.get(0)).length;
+            int len1 = ((List<Member>)l1.get(0)).size();
             int size2 = l2.size();
             // len2 == 1
             int totalLen = 1+len1;
@@ -1637,11 +1628,11 @@
 
             Member[] members = new Member[arraySize];
             for (int i = 0; i < size1; i++) {
-                Member[] ma1 = (Member[]) l1.get(i);
+                List<Member> ma1 = (List<Member>) l1.get(i);
                 int ii = i*size2;
                 for (int j = 0; j < size2; j++) {
                     for (int k = 0; k < len1; k++) {
-                        Member m1 = (Member) ma1[k];
+                        Member m1 = ma1.get(k);
                         members[totalLen*(ii + j)+k] = m1;
                     }
                     Member m2 = (Member) l2.get(j);
@@ -1649,9 +1640,10 @@
                 }
             }
 
-            return makeList(members, totalLen);
+            return makeList(Arrays.asList(members), totalLen);
         }
-        protected List<Member[]> makeList(Member[] members, final int totalLen) {
+        protected List<List<Member>> makeList(final List<Member> members, 
+                final int totalLen) {
             // l1: {A,B,C},{D,E,F}
             // l2: a,b
             //
@@ -1663,43 +1655,43 @@
             //
             // but internally is:
             //  A,B,C,a,A,B,C,b,D,E,F,a,D,E,F,b
-            List<Member[]> list = new BaseMutableList(members) {
-                int size = members.length/totalLen;
+            //
+            //  VERIFIED by pierluiggi@sf.net
+            List<List<Member>> list = new BaseMutableList(members) {
+                int size = members.size()/totalLen;
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = totalLen*index;
-                    Member[] ma = new Member[totalLen];
-                    System.arraycopy(members, i, ma, 0, totalLen);
+                    List<Member> ma = new ArrayList<Member>(
+                            members.subList(i, totalLen+i));
                     return ma;
                 }
-                public Member[] set(int index, Member[] element) {
+                public List<Member> set(int index, List<Member> element) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(element, 0, members, i, totalLen);
-
+                    List<Member> oldValue = new ArrayList<Member>();
+                    oldValue.addAll(members.subList(i, i+totalLen));
+                    for(int j=0; j<totalLen; j++) {
+                        members.set(i+j, element.get(j));
+                    }
                     return oldValue;
                 }
-                public Member[] remove(int index) {
+                public List<Member> remove(int index) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(members, i+totalLen,
-                            members, i,
-                            members.length-(i+totalLen));
-
+                    List<Member> oldValue = new ArrayList<Member>(
+                            members.subList(i, i+totalLen));
+                    final int maxJ = (size*totalLen) - totalLen;
+                    for(int j=i; j<maxJ; j++) {
+                        members.set(j, members.get(j+totalLen));
+                    }
                     size--;
                     return oldValue;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     int from = totalLen*fromIndex;
                     int to = totalLen*toIndex;
-                    Member[] sublist = new Member[to - from];
-                    System.arraycopy(members, from, sublist, 0, to - from);
+                    List<Member> sublist = members.subList(from, to);
                     return makeList(sublist, totalLen);
                 }
             };
@@ -1712,33 +1704,34 @@
         MutableListMemberArrayListMemberArrayListCalc(ResolvedFunCall call, Calc[] calcs) {
             super(call, calcs, true);
         }
-        protected List<Member[]> makeList(final List l1, final List l2) {
+        protected List<List<Member>> makeList(final List l1, final List l2) {
             int size1 = l1.size();
-            int len1 = ((Member[])l1.get(0)).length;
+            int len1 = ((List<Member>)l1.get(0)).size();
             int size2 = l2.size();
-            int len2 = ((Member[])l2.get(0)).length;
+            int len2 = ((List<Member>)l2.get(0)).size();
             int totalLen = len1+len2;
             int arraySize = (totalLen * (size1 * size2));
 
-            Member[] members = new Member[arraySize];
+            final List<Member> members = new ArrayList<Member>(arraySize);
             for (int i = 0; i < size1; i++) {
-                Member[] ma1 = (Member[]) l1.get(i);
+                List<Member> ma1 = (List<Member>) l1.get(i);
                 int ii = i*size2;
                 for (int j = 0; j < size2; j++) {
                     for (int k = 0; k < len1; k++) {
-                        Member m1 = (Member) ma1[k];
-                        members[totalLen*(ii + j)+k] = m1;
+                        Member m1 = (Member) ma1.get(k);
+                        members.add(m1);
                     }
-                    Member[] ma2 = (Member[]) l2.get(j);
+                    List<Member> ma2 = (List<Member>) l2.get(j);
                     for (int k = 0; k < len2; k++) {
-                        Member m2 = (Member) ma2[k];
-                        members[totalLen*(ii + j)+len1+k] = m2;
+                        Member m2 = (Member) ma2.get(k);
+                        members.add(m2);
                     }
                 }
             }
             return makeList(members, totalLen);
         }
-        protected List<Member[]> makeList(Member[] members, final int totalLen) {
+        protected List<List<Member>> makeList(final List<Member> members, 
+                final int totalLen) {
 
             // l1: {A,B,C},{D,E,F}
             // l2: {a,b},{c,d},{e,f}
@@ -1754,44 +1747,40 @@
             // but internally is:
             //  A,B,C,a,b,A,B,C,c,d,A,B,C,e,f,D,E,F,a,b,D,E,F,c,d,D,E,F,e,d
             //
-            List<Member[]> list = new BaseMutableList(members) {
-                int size = members.length/totalLen;
+            // VERIFIED pierluiggi@sf.net
+            List<List<Member>> list = new BaseMutableList(members) {
+                int size = members.size()/totalLen;
                 public int size() {
                     return size;
                 }
-                public Member[] get(int index) {
+                public List<Member> get(int index) {
                     int i = totalLen*index;
-                    Member[] ma = new Member[totalLen];
-                    System.arraycopy(members, i, ma, 0, totalLen);
+                    List<Member> ma = new ArrayList<Member>(
+                            members.subList(i, totalLen+i));
                     return ma;
                 }
-                public Member[] set(int index, Member[] element) {
+                public List<Member> set(int index, List<Member> element) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(element, 0, members, i, totalLen);
-
+                    List<Member> oldValue = new ArrayList<Member>();
+                    oldValue.addAll(members.subList(i, totalLen+i));
+                    for(int j=0; j<totalLen; j++) {
+                        members.set(i+j, element.get(j));
+                    }
                     return oldValue;
                 }
 
-                public Member[] remove(int index) {
+                public List<Member> remove(int index) {
                     int i = totalLen*index;
-                    Member[] oldValue = new Member[totalLen];
-                    System.arraycopy(members, i, oldValue, 0, totalLen);
-
-                    System.arraycopy(members, i+totalLen,
-                            members, i,
-                            members.length-(i+totalLen));
-
+                    List<Member> oldValue = new ArrayList<Member>(
+                            members.subList(i, i+totalLen));
+                    members.subList(i, i+totalLen).clear();
                     size--;
                     return oldValue;
                 }
-                public List<Member[]> subList(int fromIndex, int toIndex) {
+                public List<List<Member>> subList(int fromIndex, int toIndex) {
                     int from = totalLen*fromIndex;
                     int to = totalLen*toIndex;
-                    Member[] sublist = new Member[to - from];
-                    System.arraycopy(members, from, sublist, 0, to - from);
+                    List<Member> sublist = members.subList(from, to);
                     return makeList(sublist, totalLen);
                 }
             };
@@ -1806,6 +1795,17 @@
             ResolvedFunCall call) {
 
         int opSize = MondrianProperties.instance().CrossJoinOptimizerSize.get();
+        if(list.isEmpty()) return list;
+
+        try {
+            final Object o = list.get(0);
+            if(o instanceof Member) {
+                // Cannot optimize high cardinality dimensions
+                if(((Member)o).getDimension().isHighCardinality()) return list;
+            }
+        } catch(IndexOutOfBoundsException ioobe) {
+            return Collections.EMPTY_LIST;
+        }
         int size = list.size();
 
         if (size > opSize && evaluator.isNonEmpty()) {
@@ -1870,17 +1870,17 @@
         // large - which means we're allocating a huge array which we might
         // pare down later by applying NON EMPTY constraints - which is a
         // concern.
-        List<Member[]> result = new ArrayList<Member[]>((int) size);
+        List<List<Member>> result = new ArrayList<List<Member>>((int) size);
 
         boolean neitherSideIsTuple = true;
         int arity0 = 1;
         int arity1 = 1;
-        if (list1.get(0) instanceof Member[]) {
-            arity0 = ((Member[]) list1.get(0)).length;
+        if (list1.get(0) instanceof List) {
+            arity0 = ((List<Member>) list1.get(0)).size();
             neitherSideIsTuple = false;
         }
-        if (list2.get(0) instanceof Member[]) {
-            arity1 = ((Member[]) list2.get(0)).length;
+        if (list2.get(0) instanceof List) {
+            arity1 = ((List<Member>) list2.get(0)).size();
             neitherSideIsTuple = false;
         }
 
@@ -1888,7 +1888,7 @@
             // Simpler routine if we know neither side contains tuples.
             for (Member o0 : (List<Member>) list1) {
                 for (Member o1 : (List<Member>) list2) {
-                    result.add(new Member[]{o0, o1});
+                    result.add(Arrays.asList(new Member[]{o0, o1}));
                 }
             }
         } else {
@@ -1901,8 +1901,8 @@
                 if (o0 instanceof Member) {
                     row[x++] = (Member) o0;
                 } else {
-                    assertTrue(o0 instanceof Member[]);
-                    final Member[] members = (Member[]) o0;
+                    assertTrue(o0 instanceof List);
+                    final List<Member> members = (List<Member>) o0;
                     for (Member member : members) {
                         row[x++] = member;
                     }
@@ -1912,13 +1912,13 @@
                     if (o1 instanceof Member) {
                         row[x++] = (Member) o1;
                     } else {
-                        assertTrue(o1 instanceof Member[]);
-                        final Member[] members = (Member[]) o1;
+                        assertTrue(o1 instanceof List);
+                        final List<Member> members = (List<Member>) o1;
                         for (Member member : members) {
                             row[x++] = member;
                         }
                     }
-                    result.add(row.clone());
+                    result.add(Arrays.asList(row.clone()));
                     x = arity0;
                 }
             }
@@ -2196,9 +2196,9 @@
 
         // Determine if there is any data.
         evaluator = evaluator.push();
-        if (list.get(0) instanceof Member[]) {
-            for (Member[] ms : ((List<Member[]>) list)) {
-                evaluator.setContext(ms);
+        if (list.get(0) instanceof List) {
+            for (List<Member> ms : ((List<List<Member>>) list)) {
+                evaluator.setContext((ms));
                 // no measures found, use standard algorithm
                 if (measureSet == null) {
                     Object value = evaluator.evaluateCurrent();
@@ -2390,19 +2390,19 @@
             // Get all of the All Members and those Hierarchies that
             // do not have All Members.
             //
-            Member[] evalMembers = (Member[]) evaluator.getMembers().clone();
+            List<Member> evalMembers=evaluator.getMembers();
 
-            Member[] listMembers = (list.get(0) instanceof Member[])
-                ? (Member[]) list.get(0) 
-                : new Member[] { (Member) list.get(0) }; 
+            List<Member> listMembers = (list.get(0) instanceof List)
+                ? (List<Member>) list.get(0) 
+                : Arrays.asList(new Member[] { (Member) list.get(0) }); 
 
             // Remove listMembers from evalMembers and independentSlicerMembers   
             for (Member lm : listMembers) {
                 Hierarchy h = lm.getHierarchy();
-                for (int i = 0; i < evalMembers.length; i++) {
-                    Member em = evalMembers[i];
+                for (int i = 0; i < evalMembers.size(); i++) {
+                    Member em = evalMembers.get(i);
                     if ((em != null) && h.equals(em.getHierarchy())) {
-                        evalMembers[i] = null;
+                        evalMembers.set(i, null);
                     }
                 }                
             }
@@ -2425,8 +2425,8 @@
             
             Member em;
             boolean isSlicerMember = false;
-            for (int i = 0; i < evalMembers.length; i++) {
-                em = evalMembers[i];
+            for (int i = 0; i < evalMembers.size(); i++) {
+                em = evalMembers.get(i);
                 
                 if (slicerMembers == null) {
                     isSlicerMember = false;
@@ -2467,7 +2467,8 @@
                 // replace with the "all" member.
                 if (isSlicerMember || !em.isAll()) {
                     Hierarchy h = em.getHierarchy();
-                    Member[] rootMembers = schemaReader.getHierarchyRootMembers(h);
+                    Member[] rootMembers = schemaReader
+                            .getHierarchyRootMembers(h).toArray(new Member[0]);
                     if (h.hasAll()) {
                         // The Hierarchy has an All member
                         boolean found = false;
@@ -2483,7 +2484,7 @@
                         }
                     } else {
                         // The Hierarchy does NOT have an All member
-                        nonAllMemberList.add(rootMembers);
+                        ((List)nonAllMemberList).add(rootMembers);
                     }
                 }
             }
@@ -2506,8 +2507,8 @@
         // Member[] or Member elements). If for any combination of
         // Measure and non-All Members evaluation is non-null, then
         // add it to the result List.
-        if (list.get(0) instanceof Member[]) {
-            for (Member[] ms : ((List<Member[]>) list)) {
+        if (list.get(0) instanceof List) {
+            for (List<Member> ms : ((List<List<Member>>) list)) {
                 evaluator.setContext(ms);
                 if (checkData(nonAllMembers, nonAllMembers.length-1, 
                             measureSet, evaluator)) {
Index: src/main/mondrian/olap/fun/OrderFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/OrderFunDef.java	
+++ src/main/mondrian/olap/fun/OrderFunDef.java	
@@ -139,8 +139,18 @@
         }
 
         public List evaluateList(Evaluator evaluator) {
-            List list = listCalc.evaluateList(evaluator);
-            sortMembers(evaluator.push(), list, expCalc, desc, brk);
+            List<Member> list = listCalc.evaluateList(evaluator);
+            try {
+                if(list.get(0) instanceof Member &&
+                        list.get(0).getDimension().isHighCardinality()) {
+                    throw new UnsupportedOperationException(
+                            "Cannot sort high cardinality members");
+                }
+                list = new ArrayList<Member>(list);
+                sortMembers(evaluator.push(), list, expCalc, desc, brk);
+            } catch(IndexOutOfBoundsException ioobe) {
+                // No problem: no elements, no need to sort.
+            }
             return list;
         }
 
@@ -164,7 +174,7 @@
         private final MemberCalc[] memberCalcs;
         private final Calc calc;
         private final Calc[] calcs;
-        private final Member[] members; // workspace
+        private final List<Member> members; // workspace
 
         protected ContextCalc(MemberCalc[] memberCalcs, Calc calc) {
             super(new DummyExp(calc.getType()));
@@ -173,7 +183,7 @@
             this.calcs = new Calc[memberCalcs.length + 1];
             System.arraycopy(memberCalcs, 0, this.calcs, 0, memberCalcs.length);
             this.calcs[this.calcs.length - 1] = calc;
-            this.members = new Member[memberCalcs.length];
+            this.members = new ArrayList<Member>();
         }
 
         public Calc[] getCalcs() {
@@ -184,7 +194,7 @@
             // Evaluate each of the members, and set as context in the
             // sub-evaluator.
             for (int i = 0; i < memberCalcs.length; i++) {
-                members[i] = memberCalcs[i].evaluateMember(evaluator);
+                members.add(memberCalcs[i].evaluateMember(evaluator));
             }
             final Evaluator subEval = evaluator.push(members);
             // Evaluate the expression in the new context.
Index: src/main/mondrian/olap/fun/IsFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/IsFunDef.java	
+++ src/main/mondrian/olap/fun/IsFunDef.java	
@@ -9,6 +9,8 @@
 */
 package mondrian.olap.fun;
 
+import java.util.*;
+
 import mondrian.olap.*;
 import mondrian.calc.Calc;
 import mondrian.calc.ExpCompiler;
@@ -42,10 +44,11 @@
         case Category.Tuple:
             final TupleCalc tupleCalc0 = compiler.compileTuple(call.getArg(0));
             final TupleCalc tupleCalc1 = compiler.compileTuple(call.getArg(1));
-            return new AbstractBooleanCalc(call, new Calc[] {tupleCalc0, tupleCalc1}) {
+            return new AbstractBooleanCalc(call, 
+                    new Calc[] {tupleCalc0, tupleCalc1}) {
                 public boolean evaluateBoolean(Evaluator evaluator) {
-                    Member[] o0 = tupleCalc0.evaluateTuple(evaluator);
-                    Member[] o1 = tupleCalc1.evaluateTuple(evaluator);
+                    List<Member> o0 = tupleCalc0.evaluateTuple(evaluator);
+                    List<Member> o1 = tupleCalc1.evaluateTuple(evaluator);
                     return equalTuple(o0, o1);
                 }
             };
Index: src/main/mondrian/olap/fun/SetToStrFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/SetToStrFunDef.java	
+++ src/main/mondrian/olap/fun/SetToStrFunDef.java	
@@ -49,8 +49,8 @@
         } else {
             return new AbstractStringCalc(call, new Calc[] {listCalc}) {
                 public String evaluateString(Evaluator evaluator) {
-                    final List<Member[]> list =
-                        (List<Member[]>) listCalc.evaluateList(evaluator);
+                    final List<List<Member>> list =
+                        (List<List<Member>>) listCalc.evaluateList(evaluator);
                     return tupleSetToStr(list);
                 }
             };
@@ -71,11 +71,11 @@
         return buf.toString();
     }
 
-    static String tupleSetToStr(List<Member[]> list) {
+    static String tupleSetToStr(List<List<Member>> list) {
         StringBuilder buf = new StringBuilder();
         buf.append("{");
         int k = 0;
-        for (Member[] members : list) {
+        for (List<Member> members : list) {
             if (k++ > 0) {
                 buf.append(", ");
             }
Index: src/main/mondrian/olap/fun/GenerateFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/GenerateFunDef.java	
+++ src/main/mondrian/olap/fun/GenerateFunDef.java	
@@ -112,11 +112,13 @@
 
         public List evaluateList(Evaluator evaluator) {
             List<Object> result = new ArrayList<Object>();
+
             if (tuple) {
-                final List<Member[]> list1 = listCalc1.evaluateList(evaluator);
+                final List<List<Member>> list1 = 
+                        listCalc1.evaluateList(evaluator);
                 final Evaluator evaluator2 = evaluator.push();
                 if (all) {
-                    for (Member[] members : list1) {
+                    for (List<Member> members : list1) {
                         evaluator2.setContext(members);
                         final List<Object> result2 =
                             listCalc2.evaluateList(evaluator2);
@@ -124,7 +126,7 @@
                     }
                 } else {
                     final Set<Object> emitted = new HashSet<Object>();
-                    for (Member[] members : list1) {
+                    for (List<Member> members : list1) {
                         evaluator2.setContext(members);
                         final List<Object> result2 =
                             listCalc2.evaluateList(evaluator2);
@@ -198,9 +200,9 @@
             StringBuilder buf = new StringBuilder();
             int k = 0;
             if (tuple) {
-                final List<Member[]> list1 = listCalc.evaluateList(evaluator);
+                final List<List<Member>> list1=listCalc.evaluateList(evaluator);
                 final Evaluator evaluator2 = evaluator.push();
-                for (Member[] members : list1) {
+                for (List<Member> members : list1) {
                     evaluator2.setContext(members);
                     if (k++ > 0) {
                         String sep = sepCalc.evaluateString(evaluator2);
Index: src/main/mondrian/olap/fun/FunUtil.java
===================================================================
--- src/main/mondrian/olap/fun/FunUtil.java	
+++ src/main/mondrian/olap/fun/FunUtil.java	
@@ -19,6 +19,7 @@
 import mondrian.calc.ResultStyle;
 import mondrian.calc.DoubleCalc;
 import mondrian.mdx.*;
+import mondrian.util.*;
 
 import org.apache.log4j.Logger;
 
@@ -259,12 +260,11 @@
         return members;
     }
 
-    static List<Member> addMembers(
-            SchemaReader schemaReader,
-            List<Member> members,
-            Level level) {
-        Member[] levelMembers = schemaReader.getLevelMembers(level, true);
-        addAll(members, levelMembers);
+    static List<? extends Member> addMembers(final SchemaReader schemaReader,
+                final List<? extends Member> members, final Level level) {
+        final List<? extends Member> levelMembers = 
+                schemaReader.getLevelMembers(level, true);
+        ((List) members).addAll(levelMembers);
         return members;
     }
 
@@ -272,15 +272,15 @@
      * Removes every member from a list which is calculated.
      * The list must not be null, and must consist only of members.
      */
-    static void removeCalculatedMembers(List<Member> memberList)
-    {
-        for (int i = 0; i < memberList.size(); i++) {
-            Member member = (Member) memberList.get(i);
-            if (member.isCalculated()) {
-                memberList.remove(i);
-                --i;
-            }
-        }
+    static List<? extends Member> removeCalculatedMembers(
+            final List<? extends Member> memberList) {
+        final List<Member> l = new FilteredIterableList<Member>(memberList,
+                new FilteredIterableList.Filter<Member>() {
+                    public boolean accept(final Member m) {
+                        return ! m.isCalculated();
+                    }
+                });
+        return l;
     }
 
     /**
@@ -330,8 +330,7 @@
 
         assert exp.getType() instanceof ScalarType;
         Map<Member, Object> mapMemberToValue = new HashMap<Member, Object>();
-        for (int i = 0, count = members.size(); i < count; i++) {
-            Member member = members.get(i);
+        for (Member member : members) {
             while (true) {
                 evaluator.setContext(member);
                 Object result = exp.evaluate(evaluator);
@@ -360,28 +359,25 @@
      *
      * @param evaluator Evaluation context
      * @param exp Expression to evaluate
-     * @param members List of members (or List of Member[] tuples)
+     * @param members List of members (or List of Membe[] tuples)
      *
      * @pre exp != null
      * @pre exp.getType() instanceof ScalarType
      */
-    static Map<Object, Object> evaluateTuples(
-            Evaluator evaluator,
-            Calc exp,
-            List<Member[]> members) {
-        // RME
-        evaluator= evaluator.push();
+    static Map<Object, Object> evaluateTuples(Evaluator evaluator,
+                final Calc exp, final List<List<Member>> members) {
+        evaluator = evaluator.push();
 
         assert exp.getType() instanceof ScalarType;
         Map<Object, Object> mapMemberToValue = new HashMap<Object, Object>();
         for (int i = 0, count = members.size(); i < count; i++) {
-            Member[] tuples = members.get(i);
+            final List<Member> tuples = members.get(i);
             evaluator.setContext(tuples);
             Object result = exp.evaluate(evaluator);
             if (result == null) {
                 result = Util.nullValue;
             }
-            mapMemberToValue.put(new ArrayHolder<Member>(tuples), result);
+            mapMemberToValue.put(tuples, result);
         }
         return mapMemberToValue;
     }
@@ -426,59 +422,63 @@
         if (members.isEmpty()) {
             return;
         }
-        Object first = members.get(0);
-        Comparator comparator;
-        Map<Member, Object> mapMemberToValue;
-        if (first instanceof Member) {
-            final boolean parentsToo = !brk;
-            mapMemberToValue = evaluateMembers(evaluator, exp, members, parentsToo);
-            if (brk) {
-                comparator = new BreakMemberComparator(mapMemberToValue, desc);
-            } else {
-                comparator = new HierarchicalMemberComparator(mapMemberToValue, desc);
-            }
-        } else {
-            Util.assertTrue(first instanceof Member[]);
-            final int arity = ((Member[]) first).length;
-            if (brk) {
-                comparator = new BreakArrayComparator(evaluator, exp, arity);
-                if (desc) {
-                    comparator = new ReverseComparator(comparator);
+        try {
+            Object first = members.get(0);
+            Comparator comparator;
+            Map<Member, Object> mapMemberToValue;
+            if (first instanceof Member) {
+                final boolean parentsToo = !brk;
+                mapMemberToValue = evaluateMembers(evaluator, 
+                        exp, members, parentsToo);
+                if (brk) {
+                    comparator = new BreakMemberComparator(
+                            mapMemberToValue, desc);
+                } else {
+                    comparator = new HierarchicalMemberComparator(
+                            mapMemberToValue, desc);
                 }
             } else {
-                comparator = new HierarchicalArrayComparator(evaluator, exp, arity, desc);
+                Util.assertTrue(first instanceof List);
+                final int arity = ((List) first).size();
+                if (brk) {
+                    comparator=new BreakArrayComparator(evaluator, exp, arity);
+                    if (desc) {
+                        comparator = new ReverseComparator(comparator);
+                    }
+                } else {
+                    comparator = new HierarchicalArrayComparator(
+                            evaluator, exp, arity, desc);
+                }
             }
-        }
-        Collections.sort(members, comparator);
-        if (debug) {
-            final PrintWriter pw = new PrintWriter(System.out);
-            for (int i = 0; i < members.size(); i++) {
-                Object o = members.get(i);
-                pw.print(i);
-                pw.print(": ");
-                if (mapMemberToValue != null) {
-                    pw.print(mapMemberToValue.get(o));
+            Collections.sort(members, comparator);
+            if (debug) {
+                final PrintWriter pw = new PrintWriter(System.out);
+                for (int i = 0; i < members.size(); i++) {
+                    Object o = members.get(i);
+                    pw.print(i);
                     pw.print(": ");
+                    if (mapMemberToValue != null) {
+                        pw.print(mapMemberToValue.get(o));
+                        pw.print(": ");
+                    }
+                    pw.println(o);
                 }
-                pw.println(o);
+                pw.flush();
             }
-            pw.flush();
+        } catch(IndexOutOfBoundsException ioobe) {
         }
     }
 
     /**
-     * Helper function to sortMembers a list of members according to an expression.
+     * 
+     * Helper function to sortMembers a list of members according 
+     * to an expression.
      *
      * <p>NOTE: This function does not preserve the contents of the validator.
      */
-    public static void sortTuples(
-        Evaluator evaluator,
-        List<Member[]> tuples,
-        Calc exp,
-        boolean desc,
-        boolean brk,
-        int arity)
-    {
+    public static void sortTuples(final Evaluator evaluator,
+            final List<List<Member>> tuples, final Calc exp,
+            final boolean desc, final boolean brk, final int arity) {
         if (tuples.isEmpty()) {
             return;
         }
@@ -489,7 +489,8 @@
                 comparator = new ReverseComparator(comparator);
             }
         } else {
-            comparator = new HierarchicalArrayComparator(evaluator, exp, arity, desc);
+            comparator = new HierarchicalArrayComparator(evaluator, 
+                    exp, arity, desc);
         }
         Collections.sort(tuples, comparator);
         if (debug) {
@@ -508,15 +509,17 @@
         if (members.isEmpty()) {
             return;
         }
-        Object first = members.get(0);
+        final Object first = members.get(0);
         Comparator comparator;
         if (first instanceof Member) {
+            if(((Member)first).getDimension().isHighCardinality()) return;
             comparator = new HierarchizeComparator(post);
         } else {
-            Util.assertTrue(first instanceof Member[]);
-            final int arity = ((Member[]) first).length;
+            Util.assertTrue(first instanceof List);
+            final int arity = ((List) first).size();
             comparator = new HierarchizeArrayComparator(arity, post);
         }
+        members.toArray();
         Collections.sort(members, comparator);
     }
 
@@ -635,8 +638,7 @@
         for (int i = 0; i < memberCount; i++) {
             Object o = (isMember)
                     ? mapMemberToValue.get(members.get(i))
-                    : mapMemberToValue.get(
-                        new ArrayHolder<Member>((Member []) members.get(i)));
+                    : mapMemberToValue.get((List<Member>) members.get(i));
             if (o instanceof Number) {
                 total += ((Number) o).doubleValue();
             }
@@ -645,7 +647,7 @@
             Object mo = members.get(i);
             Object o = (isMember) ?
                 mapMemberToValue.get(mo) :
-                mapMemberToValue.get(new ArrayHolder<Member>((Member []) mo));
+                mapMemberToValue.get((List<Member>) mo);
             if (o instanceof Number) {
                 double d = ((Number) o).doubleValue();
                 if (isMember) {
@@ -653,8 +655,7 @@
                         mo,
                         d / total * (double) 100);
                 } else {
-                    mapMemberToValue.put(
-                        new ArrayHolder<Member>((Member []) mo),
+                    mapMemberToValue.put((List<Member>) mo,
                         d / total * (double) 100);
                 }
             }
@@ -1121,7 +1122,7 @@
                 if (object instanceof Member) {
                     evaluator.setContext((Member) object);
                 } else {
-                    evaluator.setContext((Member[]) object);
+                    evaluator.setContext((List<Member>) object);
                 }
                 Object o = evaluator.evaluateCurrent();
                 if (o != Util.nullValue && o != null) {
@@ -1132,67 +1133,6 @@
         }
     }
 
-/*
-    public static int countOld(
-            Evaluator evaluator,
-            List members,
-            boolean includeEmpty) {
-        if (members == null) {
-System.out.println("FunUtil.count List: null 0");
-            return 0;
-        }
-        if (includeEmpty) {
-System.out.println("FunUtil.count List: "+members.size());
-            return members.size();
-        } else {
-            int retval = 0;
-            for (int i = 0; i < members.size(); i++) {
-                final Object member = members.get(i);
-                if (member instanceof Member) {
-                    evaluator.setContext((Member) member);
-                } else {
-                    evaluator.setContext((Member[]) member);
-                }
-                Object o = evaluator.evaluateCurrent();
-                if (o != Util.nullValue && o != null) {
-                    retval++;
-                }
-            }
-System.out.println("FunUtil.count List: "+retval);
-            return retval;
-        }
-    }
-    public static int countIterable(
-            Evaluator evaluator,
-            Iterable iterable,
-            boolean includeEmpty) {
-        if (iterable == null) {
-System.out.println("FunUtil.countIterable Iterable: null 0");
-            return 0;
-        }
-        int retval = 0;
-        Iterator it = iterable.iterator();
-        while (it.hasNext()) {
-            final Object member = it.next();
-            if (member instanceof Member) {
-                evaluator.setContext((Member) member);
-            } else if (member instanceof Member[]) {
-                evaluator.setContext((Member[]) member);
-            }
-            if (includeEmpty) {
-                retval++;
-            } else {
-                Object o = evaluator.evaluateCurrent();
-                if (o != Util.nullValue && o != null) {
-                    retval++;
-                }
-            }
-        }
-System.out.println("FunUtil.countIterable Iterable: "+retval);
-        return retval;
-    }
-*/
-
     /**
      * Evaluates <code>exp</code> (if defined) over <code>members</code> to
      * generate a {@link List} of {@link SetWrapper} objects, which contains
@@ -1213,8 +1153,8 @@
         SetWrapper retval = new SetWrapper();
         for (Iterator it = members.iterator(); it.hasNext();) {
             Object obj = it.next();
-            if (obj instanceof Member[]) {
-                evaluator.setContext((Member[])obj);
+            if (obj instanceof List) {
+                evaluator.setContext((List<Member>)obj);
             } else {
                 evaluator.setContext((Member)obj);
             }
@@ -1261,11 +1201,11 @@
         for (int i = 0; i < calcs.length; i++) {
             retvals[i] = new SetWrapper();
         }
-        for (int j = 0; j < members.size(); j++) {
+        for(final Object member : members) {
             if (isTuples) {
-                evaluator.setContext((Member[]) members.get(j));
+                evaluator.setContext((List<Member>) member);
             } else {
-                evaluator.setContext((Member) members.get(j));
+                evaluator.setContext((Member) member);
             }
             for (int i = 0; i < calcs.length; i++) {
                 DoubleCalc calc = calcs[i];
@@ -1373,16 +1313,19 @@
         if (member1.getLevel() == member2.getLevel()) {
             return member2;
         }
-        Member uncle = cousin2(schemaReader, member1.getParentMember(), member2);
+        Member uncle = cousin2(schemaReader, 
+                member1.getParentMember(), member2);
         if (uncle == null) {
             return null;
         }
-        int ordinal = Util.getMemberOrdinalInParent(schemaReader, member1);
-        Member[] cousins = schemaReader.getMemberChildren(uncle);
-        if (cousins.length <= ordinal) {
+        final int ordinal = 
+                Util.getMemberOrdinalInParent(schemaReader, member1);
+        final List<? extends Member> cousins 
+                = schemaReader.getMemberChildren(uncle);
+        if (cousins.size() <= ordinal) {
             return null;
         }
-        return cousins[ordinal];
+        return cousins.get(ordinal);
     }
 
     /**
@@ -1426,14 +1369,14 @@
             return member.getHierarchy().getNullMember();
         }
 
-        Member[] ancestors = member.getAncestorMembers();
+        List<Member> ancestors = member.getAncestorMembers();
         final SchemaReader schemaReader = evaluator.getSchemaReader();
 
         Member result = member.getHierarchy().getNullMember();
 
         searchLoop:
-        for (int i = 0; i < ancestors.length; i++) {
-            final Member ancestorMember = ancestors[i];
+        for (int i = 0; i < ancestors.size(); i++) {
+            final Member ancestorMember = ancestors.get(i);
 
             if (targetLevel != null) {
                 if (ancestorMember.getLevel() == targetLevel) {
@@ -1698,9 +1641,9 @@
     /**
      * Returns whether one of the members in a tuple is null.
      */
-    static boolean tupleContainsNullMember(Member[] tuple) {
-        for (int i = 0; i < tuple.length; i++) {
-            Member member = tuple[i];
+    static boolean tupleContainsNullMember(List<Member> tuple) {
+        for (int i = 0; i < tuple.size(); i++) {
+            Member member = tuple.get(i);
             if (member.isNull()) {
                 return true;
             }
@@ -1708,17 +1651,16 @@
         return false;
     }
 
-    public static Member[] makeNullTuple(final TupleType tupleType) {
-        Member[] members = new Member[tupleType.elementTypes.length];
+    public static List<Member> makeNullTuple(final TupleType tupleType) {
+        List<Member> members = new ArrayList<Member>();
         for (int i = 0; i < tupleType.elementTypes.length; i++) {
             MemberType type = (MemberType) tupleType.elementTypes[i];
-            members[i] = makeNullMember(type);
+            members.add(makeNullMember(type));
         }
         return members;
     }
 
-    static Member makeNullMember(
-            MemberType memberType) {
+    static Member makeNullMember(final MemberType memberType) {
         Hierarchy hierarchy = memberType.getHierarchy();
         if (hierarchy == null) {
             return NullMember;
@@ -1791,13 +1733,13 @@
         return funDef;
     }
 
-    static void appendTuple(StringBuilder buf, Member[] members) {
+    static void appendTuple(StringBuilder buf, List<Member> members) {
         buf.append("(");
-        for (int j = 0; j < members.length; j++) {
+        for (int j = 0; j < members.size(); j++) {
             if (j > 0) {
                 buf.append(", ");
             }
-            Member member = members[j];
+            Member member = members.get(j);
             buf.append(member.getUniqueName());
         }
         buf.append(")");
@@ -1812,24 +1754,24 @@
      * </blockquote>
      * returns <code>true</code>.
      */
-    static boolean equalTuple(Member[] members0, Member[] members1) {
-        final int count = members0.length;
-        if (count != members1.length) {
+    static boolean equalTuple(List<Member> members0, List<Member> members1) {
+        final int count = members0.size();
+        if (count != members1.size()) {
             return false;
         }
         outer:
         for (int i = 0; i < count; i++) {
             // First check the member at the corresponding ordinal. It is more
             // likely to be there.
-            final Member member0 = members0[i];
-            if (member0.equals(members1[i])) {
+            final Member member0 = members0.get(i);
+            if (member0.equals(members1.get(i))) {
                 continue;
             }
             // Look for this member in other positions.
             // We can assume that the members in members0 are distinct (because
             // they belong to different dimensions), so this test is valid.
             for (int j = 0; j < count; j++) {
-                if (i != j && member0.equals(members1[j])) {
+                if (i != j && member0.equals(members1.get(j))) {
                     continue outer;
                 }
             }
@@ -1996,10 +1938,10 @@
             this.arity = arity;
         }
 
-        private static String toString(Member[] a) {
+        private static String toString(List<Member> a) {
             StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < a.length; i++) {
-                Member member = a[i];
+            for (int i = 0; i < a.size(); i++) {
+                Member member = a.get(i);
                 if (i > 0) {
                     sb.append(",");
                 }
@@ -2009,8 +1951,8 @@
         }
 
         public int compare(Object o1, Object o2) {
-            final Member[] a1 = (Member[]) o1;
-            final Member[] a2 = (Member[]) o2;
+            final List<Member> a1 = (List<Member>) o1;
+            final List<Member> a2 = (List<Member>) o2;
             final int c = compare(a1, a2);
             if (LOGGER.isDebugEnabled()) {
                 LOGGER.debug(
@@ -2020,7 +1962,7 @@
             return c;
         }
 
-        protected abstract int compare(Member[] a1, Member[] a2);
+        protected abstract int compare(List<Member> a1, List<Member> a2);
     }
 
     /**
@@ -2050,12 +1992,12 @@
             this.desc = desc;
         }
 
-        protected int compare(Member[] a1, Member[] a2) {
+        protected int compare(List<Member> a1, List<Member> a2) {
             int c = 0;
             evaluator = evaluator.push();
             for (int i = 0; i < arity; i++) {
-                Member m1 = a1[i],
-                        m2 = a2[i];
+                Member m1 = a1.get(i),
+                       m2 = a2.get(i);
                 c = compareHierarchicallyButSiblingsByValue(m1, m2);
                 if (c != 0) {
                     break;
@@ -2121,7 +2063,7 @@
             super(evaluator, calc, arity);
         }
 
-        protected int compare(Member[] a1, Member[] a2) {
+        protected int compare(List<Member> a1, List<Member> a2) {
             evaluator.setContext(a1);
             Object v1 = calc.evaluate(evaluator);
             evaluator.setContext(a2);
@@ -2142,10 +2084,10 @@
             this.post = post;
         }
 
-        protected int compare(Member[] a1, Member[] a2) {
+        protected int compare(List<Member> a1, List<Member> a2) {
             for (int i = 0; i < arity; i++) {
-                Member m1 = a1[i],
-                        m2 = a2[i];
+                Member m1 = a1.get(i),
+                       m2 = a2.get(i);
                 int c = FunUtil.compareHierarchically(m1, m2, post);
                 if (c != 0) {
                     return c;
@@ -2284,7 +2226,7 @@
             throw new UnsupportedOperationException();
         }
 
-        public Member[] getAncestorMembers() {
+        public List<Member> getAncestorMembers() {
             throw new UnsupportedOperationException();
         }
 
Index: src/main/mondrian/olap/fun/BuiltinFunTable.java
===================================================================
--- src/main/mondrian/olap/fun/BuiltinFunTable.java	
+++ src/main/mondrian/olap/fun/BuiltinFunTable.java	
@@ -22,6 +22,7 @@
 import mondrian.olap.type.DimensionType;
 import mondrian.olap.type.LevelType;
 import mondrian.olap.type.Type;
+import mondrian.util.ConcatenableList;
 import org.eigenbase.xom.XOMUtil;
 
 import java.io.PrintWriter;
@@ -395,11 +396,11 @@
             }
 
             Member firstChild(Evaluator evaluator, Member member) {
-                Member[] children = evaluator.getSchemaReader()
+                List<? extends Member> children = evaluator.getSchemaReader()
                         .getMemberChildren(member);
-                return (children.length == 0)
+                return (children.size()== 0)
                         ? member.getHierarchy().getNullMember()
-                        : children[0];
+                        : children.get(0);
             }
         });
 
@@ -421,16 +422,18 @@
 
             Member firstSibling(Member member, Evaluator evaluator) {
                 Member parent = member.getParentMember();
-                Member[] children;
+                List<? extends Member> children;
                 if (parent == null) {
                     if (member.isNull()) {
                         return member;
                     }
-                    children = evaluator.getSchemaReader().getHierarchyRootMembers(member.getHierarchy());
+                    children = evaluator.getSchemaReader()
+                            .getHierarchyRootMembers(member.getHierarchy());
                 } else {
-                    children = evaluator.getSchemaReader().getMemberChildren(parent);
+                    children = evaluator.getSchemaReader()
+                            .getMemberChildren(parent);
                 }
-                return children[0];
+                return children.get(0);
             }
         });
 
@@ -441,7 +444,7 @@
                 "LastChild",
                 "Returns the last child of a member.",
                 "pmm") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 final MemberCalc memberCalc =
                         compiler.compileMember(call.getArg(0));
                 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) {
@@ -453,11 +456,11 @@
             }
 
             Member lastChild(Evaluator evaluator, Member member) {
-                Member[] children =
+                List<? extends Member> children =
                         evaluator.getSchemaReader().getMemberChildren(member);
-                return (children.length == 0)
+                return (children.size() == 0)
                         ? member.getHierarchy().getNullMember()
-                        : children[children.length - 1];
+                        : children.get(children.size() - 1);
             }
         });
 
@@ -479,7 +482,7 @@
 
             Member firstSibling(Member member, Evaluator evaluator) {
                 Member parent = member.getParentMember();
-                Member[] children;
+                List<? extends Member> children;
                 final SchemaReader schemaReader = evaluator.getSchemaReader();
                 if (parent == null) {
                     if (member.isNull()) {
@@ -490,34 +493,33 @@
                 } else {
                     children = schemaReader.getMemberChildren(parent);
                 }
-                return children[children.length - 1];
+                return children.get(children.size() - 1);
             }
         });
 
         define(LeadLagFunDef.LeadResolver);
 
         // Members(<String Expression>)
-        define(new FunDefBase(
-                "Members",
-                "Returns the member whose name is specified by a string expression.",
-                "fmS") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+        define(new FunDefBase("Members",
+                "Returns the member whose name is specified by a string "
+                        + "expression.", "fmS") {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 throw new UnsupportedOperationException();
             }
         });
 
         // <Member>.NextMember
-        define(new FunDefBase(
-                "NextMember",
-                "Returns the next member in the level that contains a specified member.",
-                "pmm") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+        define(new FunDefBase("NextMember",
+                "Returns the next member in the level that contains a "
+                        + "specified member.", "pmm") {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 final MemberCalc memberCalc =
                         compiler.compileMember(call.getArg(0));
                 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) {
                     public Member evaluateMember(Evaluator evaluator) {
                         Member member = memberCalc.evaluateMember(evaluator);
-                        return evaluator.getSchemaReader().getLeadMember(member, +1);
+                        return evaluator.getSchemaReader()
+                                .getLeadMember(member, +1);
                     }
                 };
             }
@@ -534,7 +536,7 @@
                 "Parent",
                 "Returns the parent of a member.",
                 "pmm") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 final MemberCalc memberCalc =
                         compiler.compileMember(call.getArg(0));
                 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) {
@@ -546,7 +548,8 @@
             }
 
             Member memberParent(Evaluator evaluator, Member member) {
-                Member parent = evaluator.getSchemaReader().getMemberParent(member);
+                Member parent = evaluator.getSchemaReader()
+                        .getMemberParent(member);
                 if (parent == null) {
                     parent = member.getHierarchy().getNullMember();
                 }
@@ -556,17 +559,17 @@
         });
 
         // <Member>.PrevMember
-        define(new FunDefBase(
-                "PrevMember",
-                "Returns the previous member in the level that contains a specified member.",
-                "pmm") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+        define(new FunDefBase("PrevMember",
+                "Returns the previous member in the level that contains "
+                        + "a specified member.", "pmm") {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 final MemberCalc memberCalc =
                         compiler.compileMember(call.getArg(0));
                 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) {
                     public Member evaluateMember(Evaluator evaluator) {
                         Member member = memberCalc.evaluateMember(evaluator);
-                        return evaluator.getSchemaReader().getLeadMember(member, -1);
+                        return evaluator.getSchemaReader()
+                                .getLeadMember(member, -1);
                     }
                 };
             }
@@ -608,11 +611,10 @@
         define(AggregateFunDef.resolver);
 
         // Obsolete??
-        define(new MultiResolver(
-                "$AggregateChildren",
+        define(new MultiResolver("$AggregateChildren",
                 "$AggregateChildren(<Hierarchy>)",
-                "Equivalent to 'Aggregate(<Hierarchy>.CurrentMember.Children); for internal use.",
-                new String[] {"Inh"}) {
+                "Equivalent to 'Aggregate(<Hierarchy>.CurrentMember.Children); "
+                        + "for internal use.", new String[] {"Inh"}) {
             protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
                 return new FunDefBase(dummyFunDef) {
                     public void unparse(Exp[] args, PrintWriter pw) {
@@ -622,15 +624,17 @@
                         pw.print(")");
                     }
 
-                    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+                    public Calc compileCall(ResolvedFunCall call, 
+                            ExpCompiler compiler) {
                         final HierarchyCalc hierarchyCalc =
                                 compiler.compileHierarchy(call.getArg(0));
                         final Calc valueCalc = new ValueCalc(call);
                         return new GenericCalc(call) {
                             public Object evaluate(Evaluator evaluator) {
-                                Hierarchy hierarchy =
-                                        hierarchyCalc.evaluateHierarchy(evaluator);
-                                return aggregateChildren(evaluator, hierarchy, valueCalc);
+                                Hierarchy hierarchy = hierarchyCalc
+                                        .evaluateHierarchy(evaluator);
+                                return aggregateChildren(
+                                        evaluator, hierarchy, valueCalc);
                             }
 
                             public Calc[] getCalcs() {
@@ -880,7 +884,7 @@
                 "Ascendants",
                 "Returns the set of the ascendants of a specified member.",
                 "fxm") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+            public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) {
                 final MemberCalc memberCalc =
                         compiler.compileMember(call.getArg(0));
                 return new AbstractListCalc(call, new Calc[] {memberCalc}) {
@@ -895,11 +899,11 @@
                 if (member.isNull()) {
                     return Collections.emptyList();
                 }
-                Member[] members = member.getAncestorMembers();
+                List<? extends Member> members = member.getAncestorMembers();
                 final List<Member> result =
-                    new ArrayList<Member>(members.length + 1);
+                    new ArrayList<Member>(members.size()+ 1);
                 result.add(member);
-                XOMUtil.addAll(result, members);
+                XOMUtil.addAll(result, members.toArray(new Member[0]));
                 return result;
             }
         });
@@ -924,8 +928,8 @@
                         // Return the list of children. The list is immutable,
                         // hence 'false' above.
                         Member member = memberCalc.evaluateMember(evaluator);
-                        Member[] children = getNonEmptyMemberChildren(evaluator, member);
-                        return Arrays.asList(children);
+                        List<? extends Member> children = getNonEmptyMemberChildren(evaluator, member);
+                        return children;
                     }
                 };
             }
@@ -1094,10 +1098,11 @@
                 "Members",
                 "Returns the set of members in a level.",
                 "pxl") {
-            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
+            public Calc compileCall(final ResolvedFunCall call, 
+                    final ExpCompiler compiler) {
                 final LevelCalc levelCalc =
                         compiler.compileLevel(call.getArg(0));
-                return new AbstractListCalc(call, new Calc[] {levelCalc}) {
+                return new AbstractListCalc(call,new Calc[] {levelCalc},false) {
                     public List evaluateList(Evaluator evaluator) {
                         Level level = levelCalc.evaluateLevel(evaluator);
                         return levelMembers(level, evaluator, false);
@@ -1138,8 +1143,9 @@
                         compiler.compileList(call.getArg(0));
                 return new AbstractListCalc(call, new Calc[] {listCalc}) {
                     public List evaluateList(Evaluator evaluator) {
-                        final List<Member> list = listCalc.evaluateList(evaluator);
-                        removeCalculatedMembers(list);
+                        List<? extends Member> list = 
+                                listCalc.evaluateList(evaluator);
+                        list = removeCalculatedMembers(list);
                         return list;
                     }
                 };
@@ -1171,11 +1177,11 @@
                 }
                 Member parent = member.getParentMember();
                 final SchemaReader schemaReader = evaluator.getSchemaReader();
-                Member[] siblings = (parent == null)
-                    ? schemaReader.getHierarchyRootMembers(member.getHierarchy())
+                List<? extends Member> siblings = (parent == null) ? 
+                    schemaReader.getHierarchyRootMembers(member.getHierarchy())
                     : schemaReader.getMemberChildren(parent);
 
-                return Arrays.asList(siblings);
+                return siblings;
             }
         });
 
@@ -2090,7 +2096,7 @@
         return instance;
     }
 
-    protected Member[] getNonEmptyMemberChildren(Evaluator evaluator, Member member) {
+    protected List<? extends Member> getNonEmptyMemberChildren(Evaluator evaluator, Member member) {
         SchemaReader sr = evaluator.getSchemaReader();
         if (evaluator.isNonEmpty()) {
             return sr.getMemberChildren(member, evaluator);
@@ -2107,14 +2113,13 @@
      * @param level Level
      * @param includeCalcMembers Whether to include calculated members
      */
-    protected static Member[] getNonEmptyLevelMembers(
-        Evaluator evaluator,
-        Level level,
-        boolean includeCalcMembers)
-    {
+    protected static List<? extends Member> getNonEmptyLevelMembers(
+            final Evaluator evaluator, final Level level,
+            final boolean includeCalcMembers) {
         SchemaReader sr = evaluator.getSchemaReader();
         if (evaluator.isNonEmpty()) {
-            final Member[] members = sr.getLevelMembers(level, evaluator);
+            final List<? extends Member> members = 
+                    sr.getLevelMembers(level, evaluator);
             if (includeCalcMembers) {
                 return Util.addLevelCalculatedMembers(sr, level, members);
             }
@@ -2123,49 +2128,41 @@
         return sr.getLevelMembers(level, includeCalcMembers);
     }
 
-    static List<Member> levelMembers(
-            Level level,
-            Evaluator evaluator,
-            final boolean includeCalcMembers) {
-        Member[] members =
+    static List<? extends Member> levelMembers(final Level level,
+            final Evaluator evaluator, final boolean includeCalcMembers) {
+        List<? extends Member> members =
             getNonEmptyLevelMembers(evaluator, level, includeCalcMembers);
-        List<Member> memberList =
-            new ArrayList<Member>(Arrays.asList(members));
         if (!includeCalcMembers) {
-            FunUtil.removeCalculatedMembers(memberList);
+            members = FunUtil.removeCalculatedMembers(members);
         }
-        FunUtil.hierarchize(memberList, false);
-        return memberList;
+        FunUtil.hierarchize(members, false);
+        return members;
     }
 
-    static List<Member> hierarchyMembers(
-            Hierarchy hierarchy,
-            Evaluator evaluator,
-            final boolean includeCalcMembers) {
-        final List<Member> memberList;
+    static List<? extends Member> hierarchyMembers(final Hierarchy hierarchy,
+            final Evaluator evaluator, final boolean includeCalcMembers) {
+        List<? extends Member> memberList;
         if (evaluator.isNonEmpty()) {
             // Allow the SQL generator to generate optimized SQL since we know
             // we're only interested in non-empty members of this level.
             memberList = new ArrayList<Member>();
             for (Level level : hierarchy.getLevels()) {
-                Member[] members =
-                    getNonEmptyLevelMembers(
+                List<? extends Member> members = getNonEmptyLevelMembers(
                         evaluator, level, includeCalcMembers);
-                memberList.addAll(Arrays.asList(members));
+                ((List) memberList).addAll(members);
             }
         } else {
-            memberList = FunUtil.addMembers(
-                evaluator.getSchemaReader(),
-                new ArrayList<Member>(), hierarchy);
+            memberList = FunUtil.addMembers(evaluator.getSchemaReader(), 
+                    new ConcatenableList<Member>(), hierarchy);
             if (!includeCalcMembers && memberList != null) {
-                FunUtil.removeCalculatedMembers(memberList);
+                memberList = FunUtil.removeCalculatedMembers(memberList);
             }
         }
         FunUtil.hierarchize(memberList, false);
         return memberList;
     }
 
-    static List<Member> dimensionMembers(
+    static List<? extends Member> dimensionMembers(
             Dimension dimension,
             Evaluator evaluator,
             final boolean includeCalcMembers) {
Index: src/main/mondrian/olap/fun/TopBottomCountFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/TopBottomCountFunDef.java	
+++ src/main/mondrian/olap/fun/TopBottomCountFunDef.java	
@@ -96,14 +96,21 @@
                     } else {
                         sortTuples(
                             evaluator.push(),
-                            (List<mondrian.olap.Member[]>) list,
+                            (List<List<mondrian.olap.Member>>) list,
                             orderCalc, top, true, arity);
                     }
                 }
+/*
                 if (n < list.size()) {
                     list = list.subList(0, n);
                 }
                 return list;
+*/
+                try {
+                    return list.subList(0, n);
+                } catch(IndexOutOfBoundsException e) {
+                    return list;
+                }
             }
 
             public boolean dependsOn(Dimension dimension) {
Index: src/main/mondrian/olap/fun/AbstractAggregateFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/AbstractAggregateFunDef.java	
+++ src/main/mondrian/olap/fun/AbstractAggregateFunDef.java	
@@ -62,9 +62,14 @@
     protected List evaluateCurrentList(ListCalc listCalc, Evaluator evaluator) {
         List memberList = listCalc.evaluateList(evaluator);
 
-        int currLen = memberList.size();
+        final int currLen;
+        if(memberList.isEmpty()) currLen = 0;
+        else if(memberList.get(0) instanceof Member) {
+            currLen = ((Member) memberList.get(0)).getDimension()
+                .isHighCardinality() ?  Integer.MAX_VALUE : memberList.size();
+        } else currLen = memberList.size();
+
         crossProd(evaluator, currLen);
-
         return memberList;
     }
     protected Iterable evaluateCurrentIterable(IterCalc iterCalc,
Index: src/main/mondrian/olap/fun/extra/CalculatedChildFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/extra/CalculatedChildFunDef.java	
+++ src/main/mondrian/olap/fun/extra/CalculatedChildFunDef.java	
@@ -58,7 +58,7 @@
         if (childLevel == null) {
             return parent.getHierarchy().getNullMember();
         }
-        List<Member> calcMemberList =
+        List<? extends Member> calcMemberList =
             schemaReader.getCalculatedMembers(childLevel);
 
         for (Member child : calcMemberList) {
Index: src/main/mondrian/olap/fun/ValidMeasureFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/ValidMeasureFunDef.java	
+++ src/main/mondrian/olap/fun/ValidMeasureFunDef.java	
@@ -68,10 +68,10 @@
         }
 
         public Object evaluate(Evaluator evaluator) {
-            final Member[] members;
+            final List<Member> members;
             if (calc instanceof MemberCalc) {
-                members = new Member[1];
-                members[0] = ((MemberCalc) calc).evaluateMember(evaluator);
+                members = new ArrayList<Member>();
+                members.add(((MemberCalc) calc).evaluateMember(evaluator));
             } else {
                 members = ((TupleCalc)calc).evaluateTuple(evaluator);
             }
@@ -79,8 +79,8 @@
             RolapCube virtualCube = (RolapCube) evaluator.getCube();
             // find the measure in the tuple
             int measurePosition = -1;
-            for (int i = 0; i < members.length; i++) {
-                if (members[i].getDimension().isMeasures()) {
+            for (int i = 0; i < members.size(); i++) {
+                if (members.get(i).getDimension().isMeasures()) {
                     measurePosition = i;
                     break;
                 }
@@ -88,17 +88,16 @@
             // problem: if measure is in two base cubes
             baseCube =
                 getBaseCubeofMeasure(
-                    evaluator, members[measurePosition], baseCube);
+                    evaluator, members.get(measurePosition), baseCube);
             List<Dimension> vMinusBDimensions =
                 getDimensionsToForceToAllLevel(virtualCube, baseCube, members);
             // declare members array and fill in with all needed members
-            final Member[] validMeasureMembers =
-                new Member[vMinusBDimensions.size() + members.length];
-            System.arraycopy(members, 0, validMeasureMembers, 0, members.length);
+            final List<Member> validMeasureMembers =
+                    new ArrayList<Member>(members);
             // start adding to validMeasureMembers at right place
             for (int i = 0; i < vMinusBDimensions.size(); i++) {
-                validMeasureMembers[members.length + i] =
-                    vMinusBDimensions.get(i).getHierarchy().getDefaultMember();
+                validMeasureMembers.add(vMinusBDimensions.get(i)
+                        .getHierarchy().getDefaultMember());
             }
             evaluator.setContext(validMeasureMembers);
             return evaluator.evaluateCurrent();
@@ -114,9 +113,9 @@
             for (Cube cube1 : cubes) {
                 RolapCube cube = (RolapCube) cube1;
                 if (!cube.isVirtual()) {
-                    for (int j = 0; j < cube.getMeasuresMembers().length; j++) {
-                        if (cube.getMeasuresMembers()[j].getName().equals(
-                            member.getName())) {
+                    for (int j = 0; j < cube.getMeasuresMembers().size(); j++) {
+                        if (cube.getMeasuresMembers().get(j).getName().equals(
+                                    member.getName())) {
                             baseCube = cube;
                         }
                     }
@@ -129,10 +128,8 @@
         }
 
         private List<Dimension> getDimensionsToForceToAllLevel(
-            RolapCube virtualCube,
-            RolapCube baseCube,
-            Member[] memberArray)
-        {
+                final RolapCube virtualCube, final RolapCube baseCube,
+                final List<Member> memberArray) {
             List<Dimension> vMinusBDimensions = new ArrayList<Dimension>();
             boolean foundDim;
             for (int i = 0; i < virtualCube.getDimensions().length; i++) {
@@ -148,17 +145,15 @@
                 // we didn't find the dim in the base cube so we need to
                 // add the all member to the tuple
                 if (!foundDim &&!isDimInMembersArray(
-                    memberArray, virtualCube.getDimensions()[i])) {
+                        memberArray, virtualCube.getDimensions()[i])) {
                     vMinusBDimensions.add(virtualCube.getDimensions()[i]);
                 }
             }
             return vMinusBDimensions;
         }
 
-        private boolean isDimInMembersArray(
-            Member[] members,
-            Dimension dimension)
-        {
+        private boolean isDimInMembersArray(final List<Member> members,
+                    final Dimension dimension) {
             for (Member member : members) {
                 if (member.getName().equalsIgnoreCase(dimension.getName())) {
                     return true;
Index: src/main/mondrian/olap/fun/AddCalculatedMembersFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/AddCalculatedMembersFunDef.java	
+++ src/main/mondrian/olap/fun/AddCalculatedMembersFunDef.java	
@@ -87,7 +87,7 @@
         final SchemaReader schemaReader =
                 evaluator.getQuery().getSchemaReader(true);
         for (Level level : levelMap.keySet()) {
-            List<Member> calcMemberList =
+            List<? extends Member> calcMemberList =
                 schemaReader.getCalculatedMembers(level);
             workingList.addAll(calcMemberList);
         }
Index: src/main/mondrian/olap/fun/FilterFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/FilterFunDef.java	
+++ src/main/mondrian/olap/fun/FilterFunDef.java	
@@ -16,6 +16,7 @@
 import mondrian.olap.type.SetType;
 import mondrian.olap.type.MemberType;
 import mondrian.olap.*;
+import mondrian.util.*;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -147,7 +148,6 @@
 
             final Evaluator evaluator2 = evaluator.push();
             List members = lcalc.evaluateList(evaluator);
-
             Iterator it = members.iterator();
             while (it.hasNext()) {
                 Member member = (Member) it.next();
@@ -166,15 +166,23 @@
         protected Iterable makeIterable(Evaluator evaluator) {
             Calc[] calcs = getCalcs();
             ListCalc lcalc = (ListCalc) calcs[0];
-            BooleanCalc bcalc = (BooleanCalc) calcs[1];
+            final BooleanCalc bcalc = (BooleanCalc) calcs[1];
 
             final Evaluator evaluator2 = evaluator.push();
             List<Member> members = lcalc.evaluateList(evaluator);
 
-            // Not mutable, must create new list
+/*
+ * It dosn't pass tests ... (why?)
+            return new FilteredIterableList(members,
+                    new FilteredIterableList.Filter<Member>() {
+                        public boolean accept(final Member m) {
+                            evaluator2.setContext(m);
+                            return bcalc.evaluateBoolean(evaluator2);
+                        }
+                    });
+*/
             List<Member> result = new ArrayList<Member>();
-            for (int i = 0, count = members.size(); i < count; i++) {
-                Member member = members.get(i);
+            for(final Member member : members) {
                 evaluator2.setContext(member);
                 if (bcalc.evaluateBoolean(evaluator2)) {
                     result.add(member);
@@ -253,7 +261,7 @@
 
             Iterator it = members.iterator();
             while (it.hasNext()) {
-                Member[] member = (Member[]) it.next();
+                List<Member> member = (List<Member>) it.next();
                 evaluator2.setContext(member);
                 if (! bcalc.evaluateBoolean(evaluator2)) {
                     it.remove();
@@ -272,12 +280,12 @@
             BooleanCalc bcalc = (BooleanCalc) calcs[1];
 
             final Evaluator evaluator2 = evaluator.push();
-            List<Member[]> members = lcalc.evaluateList(evaluator);
+            List<List<Member>> members = lcalc.evaluateList(evaluator);
 
             // Not mutable, must create new list
-            List<Member[]> result = new ArrayList<Member[]>();
+            List<List<Member>> result = new ArrayList<List<Member>>();
             for (int i = 0, count = members.size(); i < count; i++) {
-                Member[] member = members.get(i);
+                List<Member> member = members.get(i);
                 evaluator2.setContext(member);
                 if (bcalc.evaluateBoolean(evaluator2)) {
                     result.add(member);
@@ -299,12 +307,13 @@
 
             // This does dynamics, just in time,
             // as needed filtering
-            final Iterable<Member[]> iter = icalc.evaluateIterable(evaluator);
-            return new Iterable<Member[]>() {
-                public Iterator<Member[]> iterator() {
-                    return new Iterator<Member[]>() {
-                        Iterator<Member[]> it = iter.iterator();
-                        Member[] m = null;
+            final Iterable<List<Member>> iter = 
+                    icalc.evaluateIterable(evaluator);
+            return new Iterable<List<Member>>() {
+                public Iterator<List<Member>> iterator() {
+                    return new Iterator<List<Member>>() {
+                        Iterator<List<Member>> it = iter.iterator();
+                        List<Member> m = null;
                         public boolean hasNext() {
                             if (m != null) {
                                 return true;
@@ -323,7 +332,7 @@
                             }
                             return true;
                         }
-                        public Member[] next() {
+                        public List<Member> next() {
                             try {
                                 return this.m;
                             } finally {
@@ -475,7 +484,7 @@
 
             Iterator it = members.iterator();
             while (it.hasNext()) {
-                Member[] member = (Member[]) it.next();
+                List<Member> member = (List<Member>) it.next();
                 evaluator2.setContext(member);
                 if (! bcalc.evaluateBoolean(evaluator2)) {
                     it.remove();
@@ -494,12 +503,12 @@
             BooleanCalc bcalc = (BooleanCalc) calcs[1];
 
             final Evaluator evaluator2 = evaluator.push();
-            List<Member[]> members = lcalc.evaluateList(evaluator);
+            List<List<Member>> members = lcalc.evaluateList(evaluator);
 
             // Not mutable, must create new list
-            List<Member[]> result = new ArrayList<Member[]>();
+            List<List<Member>> result = new ArrayList<List<Member>>();
             for (int i = 0, count = members.size(); i < count; i++) {
-                Member[] member = members.get(i);
+                List<Member> member = members.get(i);
                 evaluator2.setContext(member);
                 if (bcalc.evaluateBoolean(evaluator2)) {
                     result.add(member);
Index: src/main/mondrian/olap/fun/StrToSetFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/StrToSetFunDef.java	
+++ src/main/mondrian/olap/fun/StrToSetFunDef.java	
@@ -67,13 +67,10 @@
         }
     }
 
-    private static List<Member[]> parseTupleList(
-        Evaluator evaluator,
-        String string,
-        Hierarchy[] hierarchies)
-    {
-        List<Member[]> tupleList = new ArrayList<Member[]>();
-        Member[] members = new Member[hierarchies.length];
+    private static List<List<Member>> parseTupleList(final Evaluator evaluator,
+            final String string, final Hierarchy[] hierarchies) {
+        final List<List<Member>> tupleList = new ArrayList<List<Member>>();
+        final List<Member> members = new ArrayList<Member>(hierarchies.length);
         int i = 0;
         char c;
         while ((c = string.charAt(i++)) == ' ') {
@@ -83,7 +80,7 @@
         }
         while (true) {
             i = parseTuple(evaluator, string, i, members, hierarchies);
-            tupleList.add(members.clone());
+            tupleList.add(new ArrayList<Member>(members));
             while ((c = string.charAt(i++)) == ' ') {
             }
             if (c == ',') {
@@ -113,7 +110,7 @@
         Evaluator evaluator,
         String string,
         int i,
-        Member[] members,
+        List<Member> members,
         Hierarchy[] hierarchies)
     {
         char c;
@@ -147,14 +144,12 @@
         return i;
     }
 
-    private static List<Member> parseMemberList(
-        Evaluator evaluator,
-        String string,
-        Hierarchy hierarchy)
-    {
+    private static List<Member> parseMemberList(final Evaluator evaluator,
+            final String string, final Hierarchy hierarchy) {
         Hierarchy[] hierarchies = new Hierarchy[] {hierarchy};
         List<Member> memberList = new ArrayList<Member>();
-        Member[] members = {null};
+        List<Member> members = new ArrayList<Member>();
+        members.add(null);
         int i = 0;
         char c;
         while ((c = string.charAt(i++)) == ' ') {
@@ -164,7 +159,7 @@
         }
         while (true) {
             i = parseMember(evaluator, string, i, members, hierarchies, 0);
-            memberList.add(members[0]);
+            memberList.add(members.get(0));
             while ((c = string.charAt(i++)) == ' ') {
             }
             if (c == ',') {
@@ -184,14 +179,9 @@
     private static final int AFTER_SEG = 2;
     private static final int IN_SEG = 3;
 
-    static int parseMember(
-        Evaluator evaluator,
-        String string,
-        int i,
-        Member[] members,
-        Hierarchy[] hierarchies,
-        int j)
-    {
+    static int parseMember(final Evaluator evaluator, final String string,
+            int i, final List<Member> members, 
+            final Hierarchy[] hierarchies, final int j) {
         int k = string.length();
         List<Id.Segment> nameList = new ArrayList<Id.Segment>();
         int state = BEFORE_SEG;
@@ -296,7 +286,9 @@
                     evaluator.getSchemaReader(),
                     evaluator.getCube(),
                     nameList, true, Category.Member);
-        members[j] = member;
+        if(members.size()<=j) members.add(member);
+        else members.set(j, member);
+
         if (member.getHierarchy() != hierarchies[j]) {
             // TODO: better error
             throw Util.newInternal("member is of wrong hierarchy");
Index: src/main/mondrian/olap/fun/LastPeriodsFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/LastPeriodsFunDef.java	
+++ src/main/mondrian/olap/fun/LastPeriodsFunDef.java	
@@ -126,18 +126,17 @@
                 .getLeadMember(member, -(indexValue-1));
             endMember = member;
             if (startMember.isNull()) {
-                Member[] members = evaluator.getSchemaReader()
-                    .getLevelMembers(member.getLevel(), false);
-                startMember = members[0];
+                startMember = evaluator.getSchemaReader()
+                    .getLevelMembers(member.getLevel(), false).get(0);
             }
         } else {
             startMember = member;
             endMember = evaluator.getSchemaReader()
                 .getLeadMember(member, -(indexValue+1));
             if (endMember.isNull()) {
-                Member[] members = evaluator.getSchemaReader()
-                    .getLevelMembers(member.getLevel(), false);
-                endMember = members[members.length - 1];
+                final List<? extends Member> l = evaluator.getSchemaReader()
+                        .getLevelMembers(member.getLevel(), false);
+                endMember = l.get(l.size()-1);
             }
         }
 
Index: src/main/mondrian/olap/fun/SetFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/SetFunDef.java	
+++ src/main/mondrian/olap/fun/SetFunDef.java	
@@ -20,6 +20,7 @@
 import mondrian.olap.type.*;
 import mondrian.resource.MondrianResource;
 import mondrian.mdx.ResolvedFunCall;
+import mondrian.util.*;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -90,7 +91,7 @@
      * to avoid generating lots of intermediate lists.
      */
     public static class ListSetCalc extends AbstractListCalc {
-        private List result = new ArrayList();
+        private List result = new ConcatenableList();
         private final VoidCalc[] voidCalcs;
 
         public ListSetCalc(
@@ -115,11 +116,8 @@
             return voidCalcs;
         }
 
-        private VoidCalc createCalc(
-            Exp arg,
-            ExpCompiler compiler,
-            List<ResultStyle> resultStyles)
-        {
+        private VoidCalc createCalc(final Exp arg, final ExpCompiler compiler,
+                final List<ResultStyle> resultStyles) {
             final Type type = arg.getType();
             if (type instanceof SetType) {
                 // TODO use resultStyles
@@ -128,15 +126,14 @@
                 if (elementType instanceof MemberType) {
                     return new AbstractVoidCalc(arg, new Calc[] {listCalc}) {
                         public void evaluateVoid(Evaluator evaluator) {
-                            List<Member> list =
-                                listCalc.evaluateList(evaluator);
-                            // Add only members which are not null.
-                            for (Member member : list) {
-                                if (member == null || member.isNull()) {
-                                    continue;
-                                }
-                                result.add(member);
-                            }
+                            final List<Member> list = new FilteredIterableList<
+                                    Member>(listCalc.evaluateList(evaluator),
+                                    new FilteredIterableList.Filter<Member>() {
+                                        public boolean accept(Member m) {
+                                            return m!=null && !m.isNull();
+                                        }
+                                    });
+                            result.addAll(list);
                         }
 
                         protected String getName() {
@@ -146,12 +143,12 @@
                 } else {
                     return new AbstractVoidCalc(arg, new Calc[] {listCalc}) {
                         public void evaluateVoid(Evaluator evaluator) {
-                            List<Member[]> list =
+                            List<List<Member>> list =
                                 listCalc.evaluateList(evaluator);
                             // Add only tuples which are not null. Tuples with
                             // any null members are considered null.
                             list:
-                            for (Member[] members : list) {
+                            for (List<Member> members : list) {
                                 for (Member member : members) {
                                     if (member == null || member.isNull()) {
                                         continue list;
@@ -186,24 +183,34 @@
                 return new AbstractVoidCalc(arg, new Calc[] {tupleCalc}) {
                     public void evaluateVoid(Evaluator evaluator) {
                         // Don't add null or partially null tuple to result.
-                        Member[] members = tupleCalc.evaluateTuple(evaluator);
+                        List<Member> members=tupleCalc.evaluateTuple(evaluator);
                         if (members == null) {
                             return;
                         }
                         assert !tupleContainsNullMember(members);
-
                         result.add(members);
                     }
                 };
             }
         }
 
-        public List evaluateList(Evaluator evaluator) {
-            result.clear();
+        public List evaluateList(final Evaluator evaluator) {
+            this.result = new ConcatenableList(); 
             for (VoidCalc voidCalc : voidCalcs) {
                 voidCalc.evaluateVoid(evaluator);
             }
-            return new ArrayList(result);
+            try {
+                if(result.get(0) instanceof Member) {
+                    if(!((Member)result.get(0)).getDimension()
+                            .isHighCardinality()) {
+                        result.toArray();
+                    }
+                }
+            } catch(IndexOutOfBoundsException iooe) {
+            } catch(NullPointerException npe) {
+            }
+
+            return result;
         }
     }
     public static class IterSetCalc extends AbstractIterCalc {
@@ -260,10 +267,11 @@
                     case MUTABLE_LIST:
                         return new AbstractIterCalc(arg, new Calc[] {calc}) {
                             private final ListCalc listCalc = (ListCalc) calc;
-                            public Iterable evaluateIterable(Evaluator evaluator) {
+                            public Iterable evaluateIterable(
+                                    final Evaluator evaluator) {
                                 List result = new ArrayList();
                                 List<Member> list =
-                                    listCalc.evaluateList(evaluator);
+                                        listCalc.evaluateList(evaluator);
                                 // Add only members which are not null.
                                 for (Member member : list) {
                                     if (member == null || member.isNull()) {
@@ -359,15 +367,16 @@
 
                 return new AbstractIterCalc(arg, new Calc[] {tupleCalc}) {
                     public Iterable evaluateIterable(Evaluator evaluator) {
-                        final Member[] members = tupleCalc.evaluateTuple(evaluator);
-                        return new Iterable<Member[]>() {
-                            public Iterator<Member[]> iterator() {
-                                return new Iterator<Member[]>() {
-                                    private Member[] m = members;
+                        final List<Member> members = 
+                                tupleCalc.evaluateTuple(evaluator);
+                        return new Iterable<List<Member>>() {
+                            public Iterator<List<Member>> iterator() {
+                                return new Iterator<List<Member>>() {
+                                    private List<Member> m = members;
                                     public boolean hasNext() {
                                         return (m != null);
                                     }
-                                    public Member[] next() {
+                                    public List<Member> next() {
                                         try {
                                             return m;
                                         } finally {
@@ -375,7 +384,8 @@
                                         }
                                     }
                                     public void remove() {
-                                        throw new UnsupportedOperationException("remove");
+                                        throw new UnsupportedOperationException(
+                                                    "remove");
                                     }
                                 };
                             }
Index: src/main/mondrian/olap/fun/DescendantsFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/DescendantsFunDef.java	
+++ src/main/mondrian/olap/fun/DescendantsFunDef.java	
@@ -126,29 +126,30 @@
             final boolean self,
             final boolean after,
             final Evaluator context) {
-        Member[] children = {member};
+        List<? extends Member> children = new ArrayList<Member>();
+        ((List) children).add(member);
         for (int depth = 0;; ++depth) {
             if (depth == depthLimitFinal) {
                 if (self) {
-                    addAll(result, children);
+                    result.addAll(children);
                 }
                 if (!after) {
                     break; // no more results after this level
                 }
             } else if (depth < depthLimitFinal) {
                 if (before) {
-                    addAll(result, children);
+                    result.addAll(children);
                 }
             } else {
                 if (after) {
-                    addAll(result, children);
+                    result.addAll(children);
                 } else {
                     break; // no more results after this level
                 }
             }
 
             children = schemaReader.getMemberChildren(children, context);
-            if (children.length == 0) {
+            if (children.size() == 0) {
                 break;
             }
         }
@@ -170,10 +171,11 @@
             }
             return;
         }
-        Member[] children = {member};
+        List<? extends Member> children = new ArrayList<Member>();
+        ((List) children).add(member);
         for (int depth = 0; depthLimit == -1 || depth <= depthLimit; ++depth) {
             children = schemaReader.getMemberChildren(children);
-            if (children.length == 0) {
+            if (children.size() == 0) {
                 throw Util.newInternal("drillable member must have children");
             }
             List<Member> nextChildren = new ArrayList<Member>();
@@ -191,7 +193,7 @@
             if (nextChildren.isEmpty()) {
                 return;
             }
-            children = nextChildren.toArray(new Member[nextChildren.size()]);
+            children = nextChildren;
         }
     }
 
@@ -236,7 +238,7 @@
         // (a city). This is why we repeat the before/self/after logic for
         // each member.
         final int levelDepth = level.getDepth();
-        Member[] members = {ancestor};
+        List<? extends Member> members = Arrays.asList(new Member[]{ancestor});
         // Each pass, "fertileMembers" has the same contents as "members",
         // except that we omit members whose children we are not interested
         // in. We allocate it once, and clear it each pass, to save a little
@@ -247,9 +249,9 @@
                 List<Member> nextMembers = new ArrayList<Member>();
                 for (Member member : members) {
                     final int currentDepth = member.getLevel().getDepth();
-                    Member[] childMembers =
+                    List<? extends Member> childMembers =
                         schemaReader.getMemberChildren(member, context);
-                    if (childMembers.length == 0) {
+                    if (childMembers.size()== 0) {
                         // this member is a leaf -- add it
                         if (currentDepth == levelDepth) {
                             result.add(member);
@@ -259,13 +261,13 @@
                         // this member is not a leaf -- add its children
                         // to the list to be considered next iteration
                         if (currentDepth <= levelDepth) {
-                            nextMembers.addAll(Arrays.asList(childMembers));
+                            ((List) nextMembers).addAll(childMembers);
                         }
                     }
                 }
-                members = nextMembers.toArray(new Member[nextMembers.size()]);
+                members = nextMembers;
             }
-            while (members.length > 0);
+            while (members.size() > 0);
         } else {
             List<Member> fertileMembers = new ArrayList<Member>();
             do {
@@ -278,25 +280,23 @@
                         }
                         if (after) {
                             // we are interested in member's children
-                            fertileMembers.add(member);
+                            ((List)fertileMembers).add(member);
                         }
                     } else if (currentDepth < levelDepth) {
                         if (before) {
                             result.add(member);
                         }
-                        fertileMembers.add(member);
+                        ((List)fertileMembers).add(member);
                     } else {
                         if (after) {
                             result.add(member);
-                            fertileMembers.add(member);
+                            ((List)fertileMembers).add(member);
                         }
                     }
                 }
-                members = new Member[fertileMembers.size()];
-                members = fertileMembers.toArray(members);
-                members = schemaReader.getMemberChildren(members, context);
+                members=schemaReader.getMemberChildren(fertileMembers,context);
             }
-            while (members.length > 0);
+            while (members.size() > 0);
         }
     }
 
Index: src/main/mondrian/olap/fun/HierarchizeFunDef.java
===================================================================
--- src/main/mondrian/olap/fun/HierarchizeFunDef.java	
+++ src/main/mondrian/olap/fun/HierarchizeFunDef.java	
@@ -15,7 +15,7 @@
 import mondrian.olap.Evaluator;
 import mondrian.olap.FunDef;
 
-import java.util.List;
+import java.util.*;
 
 /**
  * Definition of the <code>Hierarchize</code> MDX function.
Index: src/main/mondrian/olap/Util.java
===================================================================
--- src/main/mondrian/olap/Util.java	
+++ src/main/mondrian/olap/Util.java	
@@ -585,15 +585,13 @@
                 Util.assertPrecondition(child instanceof Member);
                 Member bestChild = (Member) child;
                 for (int j = i + 1; j < names.size(); j++) {
-                    Member[] children =
+                    List<? extends Member> children =
                         schemaReader.getMemberChildren(bestChild);
-                    List<Member> childrenList = Arrays.asList(children);
-                    FunUtil.hierarchize(childrenList, false);
+                    FunUtil.hierarchize(children, false);
                     if (matchType == MatchType.AFTER) {
-                        bestChild = childrenList.get(0);
+                        bestChild = children.get(0);
                     } else {
-                        bestChild =
-                            childrenList.get(children.length - 1);
+                        bestChild = children.get(children.size() - 1);
                     }
                     if (bestChild == null) {
                         child = null;
@@ -720,11 +718,8 @@
      * @param allowProp Whether to allow property references
      * @return OLAP object or property reference
      */
-    public static Exp lookup(
-        Query q,
-        List<Id.Segment> nameParts,
-        boolean allowProp)
-    {
+    public static Exp lookup(final Query q, final List<Id.Segment> nameParts,
+            final boolean allowProp) {
         // First, look for a calculated member defined in the query.
         final String fullName = quoteMdxIdentifier(nameParts);
         // Look for any kind of object (member, level, hierarchy,
@@ -764,7 +759,7 @@
                 int nameLen = nameParts.size() - 1;
                 olapElement = null;
                 while (nameLen > 0 && olapElement == null) {
-                    List<Id.Segment> partialName = nameParts.subList(0, nameLen);
+                    List<Id.Segment> partialName = nameParts.subList(0,nameLen);
                     olapElement = schemaReader.lookupCompound(
                         q.getCube(), partialName, false, Category.Unknown);
                     nameLen--;
@@ -853,45 +848,40 @@
         MatchType matchType)
     {
         // Lookup member at first level.
-        Member[] rootMembers = reader.getHierarchyRootMembers(hierarchy);
+        List<? extends Member> rootMembers = 
+                reader.getHierarchyRootMembers(hierarchy);
 
         // if doing an inexact search on a non-all hieararchy, create
         // a member corresponding to the name we're searching for so
         // we can use it in a hierarchical search
         Member searchMember = null;
         if (matchType != MatchType.EXACT && !hierarchy.hasAll() &&
-            rootMembers.length > 0)
-        {
-            searchMember =
-                hierarchy.createMember(
-                    null,
-                    rootMembers[0].getLevel(),
-                    memberName.name,
-                    null);
+                    rootMembers.size() > 0) {
+            searchMember = hierarchy.createMember(null, 
+                    rootMembers.get(0).getLevel(), memberName.name, null);
         }
 
         int bestMatch = -1;
-        for (int i = 0; i < rootMembers.length; i++) {
+        for (int i = 0; i < rootMembers.size(); i++) {
             int rc;
             // when searching on the ALL hierarchy, match must be exact
             if (matchType == MatchType.EXACT || hierarchy.hasAll()) {
-                rc = rootMembers[i].getName()
+                rc = rootMembers.get(i).getName()
                         .compareToIgnoreCase(memberName.name);
             } else {
                 rc = FunUtil.compareSiblingMembers(
-                    rootMembers[i],
-                    searchMember);
+                        rootMembers.get(i), searchMember);
             }
             if (rc == 0) {
-                return rootMembers[i];
+                return rootMembers.get(i);
             }
             if (!hierarchy.hasAll()) {
                 if (matchType == MatchType.BEFORE) {
                     if (rc < 0 &&
                         (bestMatch == -1 ||
                         FunUtil.compareSiblingMembers(
-                            rootMembers[i],
-                            rootMembers[bestMatch]) > 0))
+                            rootMembers.get(i),
+                            rootMembers.get(bestMatch)) > 0))
                     {
                         bestMatch = i;
                     }
@@ -899,8 +889,8 @@
                     if (rc > 0 &&
                         (bestMatch == -1 ||
                         FunUtil.compareSiblingMembers(
-                            rootMembers[i],
-                            rootMembers[bestMatch]) < 0))
+                            rootMembers.get(i),
+                            rootMembers.get(bestMatch)) < 0))
                     {
                         bestMatch = i;
                     }
@@ -908,17 +898,14 @@
             }
         }
         if (matchType != MatchType.EXACT && bestMatch != -1) {
-            return rootMembers[bestMatch];
+            return rootMembers.get(bestMatch);
         }
         // If the first level is 'all', lookup member at second level. For
         // example, they could say '[USA]' instead of '[(All
         // Customers)].[USA]'.
-        return (rootMembers.length == 1 && rootMembers[0].isAll())
+        return (rootMembers.size() == 1 && rootMembers.get(0).isAll())
             ? reader.lookupMemberChildByName(
-                rootMembers[0],
-                memberName,
-                matchType)
-            : null;
+                rootMembers.get(0), memberName, matchType) : null;
     }
 
     /**
@@ -943,12 +930,11 @@
     public static int getMemberOrdinalInParent(SchemaReader reader,
                                                Member member) {
         Member parent = member.getParentMember();
-        Member[] siblings =  (parent == null)
-            ? reader.getHierarchyRootMembers(member.getHierarchy())
-            : reader.getMemberChildren(parent);
-
-        for (int i = 0; i < siblings.length; i++) {
-            if (siblings[i] == member) {
+        List<? extends Member> siblings = (parent == null)
+                ? reader.getHierarchyRootMembers(member.getHierarchy())
+                : reader.getMemberChildren(parent);
+        for (int i = 0; i < siblings.size(); i++) {
+            if (siblings.get(i) == member) {
                 return i;
             }
         }
@@ -968,8 +954,8 @@
     {
         Member m = parent;
         while (m.getLevel() != level) {
-            Member[] children = reader.getMemberChildren(m);
-            m = children[0];
+            List<? extends Member> children = reader.getMemberChildren(m);
+            m = children.get(0);
         }
         return m;
     }
@@ -1079,11 +1065,10 @@
         throw new UnsupportedOperationException(reason);
     }
 
-    public static Member[] addLevelCalculatedMembers(
-            SchemaReader reader,
-            Level level,
-            Member[] members) {
-        List<Member> calcMembers =
+    public static List<? extends Member> addLevelCalculatedMembers(
+            final SchemaReader reader, final Level level,
+            final List<? extends Member> members) {
+        List<? extends Member> calcMembers =
             reader.getCalculatedMembers(level.getHierarchy());
         List<Member> calcMembersInThisLevel = new ArrayList<Member>();
         for (Member calcMember : calcMembers) {
@@ -1092,12 +1077,10 @@
             }
         }
         if (!calcMembersInThisLevel.isEmpty()) {
-            List<Member> newMemberList =
-                new ArrayList<Member>(Arrays.asList(members));
+            List<Member> newMemberList = new ArrayList<Member>(members);
             newMemberList.addAll(calcMembersInThisLevel);
-            members = newMemberList.toArray(new Member[newMemberList.size()]);
-        }
-        return members;
+            return newMemberList;
+        } else return members;
     }
 
     /**
Index: src/main/mondrian/olap/ExpCacheDescriptor.java
===================================================================
--- src/main/mondrian/olap/ExpCacheDescriptor.java	
+++ src/main/mondrian/olap/ExpCacheDescriptor.java	
@@ -56,9 +56,9 @@
 
     private void computeDepends(Calc calc, Evaluator evaluator) {
         final List<Integer> ordinalList = new ArrayList<Integer>();
-        final Member[] members = evaluator.getMembers();
-        for (int i = 0; i < members.length; i++) {
-            Dimension dimension = members[i].getDimension();
+        final List<Member> members = evaluator.getMembers();
+        for (int i = 0; i < members.size(); i++) {
+            Dimension dimension = members.get(i).getDimension();
             if (calc.dependsOn(dimension)) {
                 ordinalList.add(i);
             }
Index: src/main/mondrian/olap/SchemaReader.java
===================================================================
--- src/main/mondrian/olap/SchemaReader.java	
+++ src/main/mondrian/olap/SchemaReader.java	
@@ -40,7 +40,7 @@
      *
      * @see #getCalculatedMembers(Hierarchy)
      */
-    Member[] getHierarchyRootMembers(Hierarchy hierarchy);
+    List<? extends Member> getHierarchyRootMembers(Hierarchy hierarchy);
 
     /**
      * Returns number of children parent of a member,
@@ -67,7 +67,7 @@
      * @pre member != null
      * @post return != null
      */
-    Member[] getMemberChildren(Member member);
+    List<? extends Member> getMemberChildren(Member member);
 
     /**
      * Returns direct children of <code>member</code>, optimized
@@ -82,15 +82,16 @@
      * Wether or not optimization is possible depends
      * on the SchemaReader implementation.
      */
-    Member[] getMemberChildren(Member member, Evaluator context);
+    List<? extends Member> getMemberChildren(Member member, Evaluator context);
 
     /**
      * Returns direct children of each element of <code>members</code>.
      * @pre members != null
      * @post return != null
      */
-    Member[] getMemberChildren(Member[] members);
-    Member[] getMemberChildren(Member[] members, Evaluator context);
+    List<? extends Member> getMemberChildren(List<? extends Member> members);
+    List<? extends Member> getMemberChildren(List<? extends Member> members, 
+            Evaluator context);
 
     /**
      * Returns the parent of <code>member</code>.
@@ -251,7 +252,8 @@
     /**
      * Returns the members of a level, optionally including calculated members.
      */
-    Member[] getLevelMembers(Level level, boolean includeCalculated);
+    List<? extends Member> getLevelMembers(
+            final Level level, final boolean includeCalculated);
 
     /**
      * Returns the members of a level, optionally filtering out members which
@@ -261,7 +263,7 @@
      * @param context Context for filtering
      * @return Members of this level
      */
-    Member[] getLevelMembers(Level level, Evaluator context);
+    List<? extends Member> getLevelMembers(Level level, Evaluator context);
 
     /**
      * Returns the accessible levels of a hierarchy.
@@ -295,17 +297,17 @@
     /**
      * Returns a list of calculated members in a given hierarchy.
      */
-    List<Member> getCalculatedMembers(Hierarchy hierarchy);
+    List<? extends Member> getCalculatedMembers(Hierarchy hierarchy);
 
     /**
      * Returns a list of calculated members in a given level.
      */
-    List<Member> getCalculatedMembers(Level level);
+    List<? extends Member> getCalculatedMembers(Level level);
 
     /**
      * Returns the list of calculated members.
      */
-    List<Member> getCalculatedMembers();
+    List<? extends Member> getCalculatedMembers();
 
     /**
      * Finds a child of a member with a given name.
Index: src/main/mondrian/olap/Dimension.java
===================================================================
--- src/main/mondrian/olap/Dimension.java	
+++ src/main/mondrian/olap/Dimension.java	
@@ -47,6 +47,12 @@
      * Returns the schema this dimension belongs to.
      */
     Schema getSchema();
+
+    /**
+     * Returns if dimension should be considered as a "high cardinality" or
+     * "low cardinality" according to cube definition.
+     */
+    boolean isHighCardinality();
 }
 
 // End Dimension.java
Index: src/main/mondrian/olap/QueryAxis.java
===================================================================
--- src/main/mondrian/olap/QueryAxis.java	
+++ src/main/mondrian/olap/QueryAxis.java	
@@ -274,7 +274,6 @@
         Hide,
         Show;
     }
-
 }
 
 // End QueryAxis.java
Index: src/main/mondrian/rolap/RolapNativeSet.java
===================================================================
--- src/main/mondrian/rolap/RolapNativeSet.java	
+++ src/main/mondrian/rolap/RolapNativeSet.java	
@@ -172,15 +172,15 @@
                     }
                 };
             } else {
-                return new Iterable<Member[]>() {
-                    public Iterator<Member[]> iterator() {
-                        return new Iterator<Member[]>() {
+                return new Iterable<List<Member>>() {
+                    public Iterator<List<Member>> iterator() {
+                        return new Iterator<List<Member>>() {
                             int index = 0;
                             public boolean hasNext() {
                                 return (index < list.size());
                             }
-                            public Member[] next() {
-                                return (Member[]) list.get(index++);
+                            public List<Member> next() {
+                                return (List<Member>) list.get(index++);
                             }
                             public void remove() {
                                 throw new UnsupportedOperationException("remove");
@@ -191,7 +191,7 @@
             }
         }
         protected List executeList() {
-            SqlTupleReader tr = new SqlTupleReader(constraint);
+            HighCardSqlTupleReader tr = new HighCardSqlTupleReader(constraint);
             tr.setMaxRows(maxRows);
             for (CrossJoinArg arg : args) {
                 addLevel(tr, arg);
@@ -248,7 +248,8 @@
          * returns a copy of the result because its modified
          */
         private <T> List<T> copy(List<T> list) {
-            return new ArrayList<T>(list);
+//            return new ArrayList<T>(list);
+            return list;
         }
 
         private void addLevel(TupleReader tr, CrossJoinArg arg) {
@@ -290,7 +291,7 @@
     protected interface CrossJoinArg {
         RolapLevel getLevel();
 
-        RolapMember[] getMembers();
+        List<RolapMember> getMembers();
 
         void addConstraint(
             SqlQuery sqlQuery,
@@ -324,11 +325,13 @@
             return level;
         }
 
-        public RolapMember[] getMembers() {
+        public List<RolapMember> getMembers() {
             if (member == null) {
                 return null;
             }
-            return new RolapMember[] { member };
+            final List<RolapMember> list = new ArrayList<RolapMember>();
+            list.add(member);
+            return list;
         }
 
         public boolean isPreferInterpreter(boolean joinArg) {
@@ -381,7 +384,7 @@
      * @since Nov 14, 2005
      */
     protected static class MemberListCrossJoinArg implements CrossJoinArg {
-        private RolapMember[] members;
+        private List<RolapMember> members;
         private RolapLevel level = null;
         private boolean restrictMemberTypes;
         private boolean hasCalcMembers;
@@ -389,7 +392,7 @@
         private boolean hasAllMember;
         
         private MemberListCrossJoinArg(
-            RolapLevel level, RolapMember[] members, boolean restrictMemberTypes,
+            RolapLevel level, List<RolapMember> members, boolean restrictMemberTypes,
             boolean hasCalcMembers, boolean hasNonCalcMembers, boolean hasAllMember) {
             this.level = level;
             this.members = members;
@@ -412,13 +415,13 @@
                 return null;
             }
             
-            RolapMember[] memberList = new RolapMember[args.length];
+            List<RolapMember> memberList = new ArrayList<RolapMember>();
             for (int i = 0; i < args.length; i++) {
                 if (!(args[i] instanceof MemberExpr)) {
                     return null;
                 }
-                memberList[i] = 
-                    (RolapMember)(((MemberExpr)args[i]).getMember());
+                memberList.add((RolapMember)
+                        (((MemberExpr)args[i]).getMember()));
             }
             
             return create(memberList, restrictMemberTypes);
@@ -431,13 +434,13 @@
          * @param restrictMemberTypes whether calculated members are allowed
          * @return MemberListCrossJoinArg if member list is well formed, 
          * NULL if not.
-         */
+         *
         static CrossJoinArg create(List args, boolean restrictMemberTypes) {
             if (args.isEmpty()) {
                 return null;
             }
             
-            RolapMember[] memberList = new RolapMember[args.size()];
+            List<RolapMember> memberList = new RolapMember[args.size()];
             for (int i = 0; i < args.size(); i++) {
                 if (!(args.get(i) instanceof RolapMember)) {
                     return null;
@@ -447,6 +450,7 @@
             
             return create(memberList, restrictMemberTypes);
         }
+        */
 
         /**
          * Creates an instance of {@link RolapNativeSet.CrossJoinArg},
@@ -464,7 +468,9 @@
          * members are presented (and then it's flagged appropriately
          * for special handling downstream).
          */
-        static CrossJoinArg create(RolapMember[] args, boolean restrictMemberTypes) {
+        static CrossJoinArg create(final List<RolapMember> args, 
+                final boolean restrictMemberTypes) {
+            if(args.isEmpty()) return null;
 
             RolapLevel level = null;
             RolapLevel nullLevel = null;
@@ -474,16 +480,16 @@
             
             // First check that the member list will not result in a predicate
             // longer than the underlying DB could support.
-            if (args.length >
-                MondrianProperties.instance().MaxConstraints.get()) {
+            if (args.size() > MondrianProperties.instance()
+                    .MaxConstraints.get()) {
                 return null;
             }
             
             int nNullMembers = 0;
-            for (int i = 0; i < args.length; i++) {
+            for (int i = 0; i < args.size(); i++) {
+                if(!(args.get(i) instanceof RolapMember)) return null;        
+                RolapMember m = args.get(i);
                 
-                RolapMember m = args[i];
-                
                 if (m.isNull()) {
                     // we're going to filter out null members anyway;
                     // don't choke on the fact that their level
@@ -532,18 +538,16 @@
             if (!isSimpleLevel(level)) {
                 return null;
             }
-            RolapMember[] members = new RolapMember[args.length - nNullMembers];
+            List<RolapMember> members = new ArrayList<RolapMember>();
             
-            int j = 0;
-            for (int i = 0; i < args.length; ++i) {
-                RolapMember m = args[i];
+            for (int i = 0; i < args.size(); ++i) {
+                RolapMember m = args.get(i);
 
                 if (m.isNull()) {
                     // filter out null members
                     continue;
                 }
-                members[j] = m;
-                ++j;
+                members.add(m);
             }
             
             return new MemberListCrossJoinArg(
@@ -555,7 +559,7 @@
             return level;
         }
 
-        public RolapMember[] getMembers() {
+        public List<RolapMember> getMembers() {
             return members;
         }
 
@@ -598,8 +602,8 @@
             if (this.restrictMemberTypes != that.restrictMemberTypes) {
                 return false;
             }
-            for (int i = 0; i < members.length; i++) {
-                if (this.members[i] != that.members[i]) {
+            for (int i = 0; i < members.size(); i++) {
+                if (this.members.get(i) != that.members.get(i)) {
                     return false;
                 }
             }
@@ -612,7 +616,7 @@
             Map<String, RolapStar.Table> relationNamesToStarTableMap) {
             SqlConstraintUtils.addMemberConstraint(
                 sqlQuery, levelToColumnMap, relationNamesToStarTableMap, null,
-                Arrays.asList(members), restrictMemberTypes, true);
+                members, restrictMemberTypes, true);
         }
     }
 
@@ -882,7 +886,7 @@
      * was translated into an sql condition (filter/topcount). The measure
      * is not used to constrain the result but only to access the star.
      *
-     * @see RolapAggregationManager#makeRequest(Member[])
+     * @see RolapAggregationManager#makeRequest(List<Member>)
      */
     protected RolapEvaluator overrideContext(
         RolapEvaluator evaluator,
Index: src/main/mondrian/rolap/RolapNativeSql.java
===================================================================
--- src/main/mondrian/rolap/RolapNativeSql.java	
+++ src/main/mondrian/rolap/RolapNativeSql.java	
@@ -38,7 +38,7 @@
      * the constraints from RolapAggregationManager. Also
      * make sure all measures live in the same star.
      *
-     * @see RolapAggregationManager#makeRequest(Member[])
+     * @see RolapAggregationManager#makeRequest(List<Member>)
      */
     private boolean saveStoredMeasure(RolapStoredMeasure m) {
         if (storedMeasure != null) {
Index: src/main/mondrian/rolap/RolapMember.java
===================================================================
--- src/main/mondrian/rolap/RolapMember.java	
+++ src/main/mondrian/rolap/RolapMember.java	
@@ -51,24 +51,23 @@
      * @param hierarchy  Hierarchy
      * @return Array of arrays of members
      */
-    public static Member[][] getAllMembers(SchemaReader schemaReader,
-            Hierarchy hierarchy) {
-
+    public static List<List<? extends Member>> getAllMembers(
+            final SchemaReader schemaReader, final Hierarchy hierarchy) {
         long start = System.currentTimeMillis();
-
         try {
-            List<Member[]> list = new ArrayList<Member[]>(500);
-
+            List<List<? extends Member>> list = 
+                    new ArrayList<List<? extends Member>>();
             // Getting the members by Level is the fastest way that I could
             // find for getting all of a hierarchy's members.
             Level[] levels = hierarchy.getLevels();
             for (Level level : levels) {
-                Member[] members = schemaReader.getLevelMembers(level, true);
-                if (members != null) {
+                List<? extends Member> members = schemaReader.getLevelMembers(
+                        level, true);
+                if(members != null) {
                     list.add(members);
                 }
             }
-            return list.toArray(new Member[list.size()][]);
+            return list;
         } finally {
             if (LOGGER.isDebugEnabled()) {
                 long end = System.currentTimeMillis();
@@ -126,15 +125,18 @@
      * @param schemaReader
      * @param seedMember
      */
-    public static void setOrdinals(SchemaReader schemaReader, Member seedMember) {
+    public static void setOrdinals(final SchemaReader schemaReader, 
+            final Member seedMember) {
         long start = System.currentTimeMillis();
 
         try {
             Hierarchy hierarchy = seedMember.getHierarchy();
             //int ordinal = 1;
             int ordinal = hierarchy.hasAll() ? 1 : 0;
-            Member[][] membersArray = getAllMembers(schemaReader, hierarchy);
-            Member[] leafMembers = membersArray[membersArray.length-1];
+            List<List<? extends Member>> membersArray = 
+                    getAllMembers(schemaReader, hierarchy);
+            List<? extends Member> leafMembers = 
+                    membersArray.get(membersArray.size()-1);
 
             // Set all ordinals,
             for (Member child : leafMembers) {
@@ -146,8 +148,8 @@
             // is 'uneven', not all leaf members are at the same level, then
             // the above setting of ordinals will have missed some.
             boolean needsFullTopDown = false;
-            for (int i = 0; i < membersArray.length-1; i++) {
-                Member[] members = membersArray[i];
+            for (int i = 0; i < membersArray.size()-1; i++) {
+                List<? extends Member> members = membersArray.get(i);
                 for (Member member : members) {
                     if (member.getOrdinal() == -1) {
                         needsFullTopDown = true;
@@ -158,8 +160,8 @@
             // If we must to a full Top-down, then first reset all ordinal
             // values to -1, and then call the Top-down
             if (needsFullTopDown) {
-                for (int i = 0; i < membersArray.length-1; i++) {
-                    Member[] members = membersArray[i];
+                for (int i = 0; i < membersArray.size()-1; i++) {
+                    List<? extends Member> members = membersArray.get(i);
                     for (Member member : members) {
                         if (member instanceof RolapMember) {
                             ((RolapMember) member).resetOrdinal();
@@ -211,7 +213,8 @@
      * @param schemaReader
      * @param member
      */
-    public static void setOrdinalsTopDown(SchemaReader schemaReader, Member member) {
+    public static void setOrdinalsTopDown(final SchemaReader schemaReader, 
+            final Member member) {
         long start = System.currentTimeMillis();
 
         try {
@@ -221,9 +224,8 @@
                 // top of the world
                 int ordinal = 0;
 
-                Member[] siblings =
+                List<? extends Member> siblings =
                     schemaReader.getHierarchyRootMembers(member.getHierarchy());
-
                 for (Member sibling : siblings) {
                     ordinal = setAllChildren(ordinal, schemaReader, sibling);
                 }
@@ -234,20 +236,18 @@
         } finally {
             if (LOGGER.isDebugEnabled()) {
                 long end = System.currentTimeMillis();
-                LOGGER.debug("RolapMember.setOrdinalsTopDown: time=" +(end-start));
+                LOGGER.debug("RolapMember.setOrdinalsTopDown: time=" 
+                        + (end-start));
             }
         }
     }
     private static int setAllChildren(
             int ordinal, SchemaReader schemaReader, Member member) {
-
         ordinal = setOrdinal(member, ordinal);
-
-        Member[] children = schemaReader.getMemberChildren(member);
+        List<? extends Member> children=schemaReader.getMemberChildren(member);
         for (Member child : children) {
             ordinal = setAllChildren(ordinal, schemaReader, child);
         }
-
         return ordinal;
     }
 
Index: src/main/mondrian/rolap/ResultLoader.java
===================================================================
--- src/main/mondrian/rolap/ResultLoader.java	
+++ src/main/mondrian/rolap/ResultLoader.java	
@@ -0,0 +1,217 @@
+/*
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2004-2005 TONBELLER AG
+// Copyright (C) 2005-2007 Julian Hyde and others
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.rolap;
+
+import mondrian.olap.*;
+import mondrian.olap.fun.FunUtil;
+import mondrian.resource.MondrianResource;
+import mondrian.rolap.sql.MemberChildrenConstraint;
+import mondrian.rolap.sql.SqlQuery;
+import mondrian.rolap.sql.TupleConstraint;
+import mondrian.util.*;
+
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ * Loader to be iterated to load all results from database.
+ */
+public class ResultLoader {
+    private final List<Target> targets;
+    private final int enumTargetCount;
+    private final ResultSet resultSet;
+    private final boolean execQuery;
+    private final String message;
+    private final List<List<RolapMember>> partialResult, newPartialResult;
+    private final SqlStatement stmt;
+
+    private final int[] srcMemberIdxes;
+
+    int currPartialResultIdx = 0;
+
+    public ResultLoader(final int enumTargetCount, final List<Target> targets,
+            final SqlStatement stmt, final ResultSet resultSet, 
+            final boolean execQuery,
+            final List<List<RolapMember>> partialResult,
+            final List<List<RolapMember>> newPartialResult) 
+            throws SQLException {
+        this.targets = targets;
+        this.enumTargetCount = enumTargetCount;
+        this.stmt = stmt;
+        this.resultSet = resultSet;
+        this.execQuery = execQuery;
+        this.partialResult = partialResult;
+        this.newPartialResult = newPartialResult;
+        this.srcMemberIdxes = enumTargetCount>0 ? new int[enumTargetCount] 
+                                                : null;
+        this.message = "Populating member cache with members for " + targets;
+    }
+
+
+    public boolean loadResult() throws SQLException {
+        boolean moreRows = true;
+/*
+        if (limit > 0 && limit < ++fetchCount) {
+            throw MondrianResource.instance().MemberFetchLimitExceeded
+                    .ex((long) limit);
+        }
+*/
+        if (enumTargetCount == 0) {
+            int column = 0;
+            for (Target target : targets) {
+                target.removeCurrMember();
+                column = target.addRow(resultSet, column);
+            }
+        } else {
+            int firstEnumTarget = 0;
+            for(;firstEnumTarget<targets.size(); firstEnumTarget++) {
+                if(targets.get(firstEnumTarget).getSrcMembers()!=null) {
+                    break;
+                }
+            }
+            List<RolapMember> partialRow;
+            if (execQuery) {
+                partialRow = null;
+            } else {
+                partialRow = partialResult.get(currPartialResultIdx);
+            }
+            resetCurrMembers(partialRow);
+            addTargets(
+                0, firstEnumTarget, enumTargetCount, srcMemberIdxes,
+                resultSet, message);
+            if (newPartialResult != null) {
+                savePartialResult(newPartialResult);
+            }
+        }
+
+        if (execQuery) {
+            moreRows = resultSet.next();
+            if (moreRows) {
+                ++stmt.rowCount;
+            }
+        } else {
+            currPartialResultIdx++;
+            moreRows = currPartialResultIdx < partialResult.size();
+        }
+        return moreRows;
+    }
+
+
+    /**
+     * Closes internal statement.
+     */
+    public void close() {
+        if(this.stmt!=null) this.stmt.close();
+    }
+
+
+    /**
+     * Handles error
+     */
+    public void handle(Exception e) {
+        if(stmt!=null) stmt.handle(e);
+        else throw Util.newError(e, message);
+    }
+
+    //
+    // Private stuff -------------------------------
+    //
+
+    /**
+     * Sets the current member for those targets that retrieve their column
+     * values from native sql.
+     *
+     * @param partialRow if set, previously cached result set
+     */
+    private void resetCurrMembers(List<RolapMember> partialRow) {
+        int nativeTarget = 0;
+        for (Target target : targets) {
+            if (target.getSrcMembers() == null) {
+                if (partialRow != null) {
+                    target.setCurrMember(partialRow.get(nativeTarget++));
+                } else {
+                    target.removeCurrMember();
+                }
+            }
+        }
+    }
+
+    /**
+     * Recursively forms the cross product of a row retrieved through sql
+     * with each of the targets that contains an enumerated set of members.
+     *
+     * @param currEnumTargetIdx current enum target that recursion
+     * is being applied on
+     * @param currTargetIdx index within the list of a targets that
+     * currEnumTargetIdx corresponds to
+     * @param nEnumTargets number of targets that have enumerated members
+     * @param srcMemberIdxes for each enumerated target, the current member
+     * to be retrieved to form the current cross product row
+     * @param resultSet result set corresponding to rows retrieved through
+     * native sql
+     * @param message Message to issue on failure
+     */
+    private void addTargets(
+        int currEnumTargetIdx, int currTargetIdx, int nEnumTargets,
+        int[] srcMemberIdxes, ResultSet resultSet, String message) {
+
+        Target currTarget = targets.get(currTargetIdx);
+        for (int i = 0; i < currTarget.getSrcMembers().size(); i++) {
+            srcMemberIdxes[currEnumTargetIdx] = i;
+            if (currEnumTargetIdx < nEnumTargets - 1) {
+                int nextTargetIdx = currTargetIdx + 1;
+                for (; nextTargetIdx < targets.size(); nextTargetIdx++) {
+                    if (targets.get(nextTargetIdx).getSrcMembers() != null) {
+                        break;
+                    }
+                }
+                addTargets(
+                    currEnumTargetIdx + 1, nextTargetIdx, nEnumTargets,
+                    srcMemberIdxes, resultSet, message);
+            } else {
+                int column = 0;
+                int enumTargetIdx = 0;
+                for (Target target : targets) {
+                    if (target.getSrcMembers() == null) {
+                        try {
+                            column = target.addRow(resultSet, column);
+                        } catch (Throwable e) {
+                            throw Util.newError(e, message);
+                        }
+                    } else {
+                        RolapMember member = target.getSrcMembers().get(
+                                    srcMemberIdxes[enumTargetIdx++]);
+                        target.add(member);
+                    }
+                }
+            }
+        }
+    } 
+
+    /**
+     * Retrieves the current members fetched from the targets executed
+     * through sql and form tuples, adding them to partialResult
+     *
+     * @param partialResult list containing the columns and rows corresponding
+     * to data fetched through sql
+     */
+    private void savePartialResult(List<List<RolapMember>> partialResult) {
+        List<RolapMember> row = new ArrayList<RolapMember>();
+        for (Target target : targets) {
+            if (target.getSrcMembers() == null) {
+                row.add(target.getCurrMember());
+            }
+        }
+        partialResult.add(row);
+    }
+
+}
Index: src/main/mondrian/rolap/RolapResult.java
===================================================================
--- src/main/mondrian/rolap/RolapResult.java	
+++ src/main/mondrian/rolap/RolapResult.java	
@@ -18,8 +18,7 @@
 import mondrian.olap.fun.MondrianEvaluationException;
 import mondrian.resource.MondrianResource;
 import mondrian.rolap.agg.AggregationManager;
-import mondrian.util.Format;
-import mondrian.util.ObjectPool;
+import mondrian.util.*;
 
 import mondrian.olap.fun.FunUtil;
 import mondrian.olap.type.ScalarType;
@@ -44,8 +43,7 @@
  * @since 10 August, 2001
  * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapResult.java#114 $
  */
-public
-class RolapResult extends ResultBase {
+public class RolapResult extends ResultBase {
 
     private static final Logger LOGGER = Logger.getLogger(ResultBase.class);
 
@@ -192,13 +190,16 @@
 
 
             // list of ALL Members that are not default Members
-            final List<Member> nonDefaultAllMembers = new ArrayList<Member>();
+            final List<? extends Member> nonDefaultAllMembers = 
+                    new ArrayList<Member>();
 
             // List of Members of Hierarchies that do not have an ALL Member
-            List<Member[]> nonAllMembers = new ArrayList<Member[]>();
+            List<List<? extends Member>> nonAllMembers = 
+                    new ArrayList<List<? extends Member>>();
 
             // List of Measures
-            final List<Member> measureMembers = new ArrayList<Member>();
+            final List<? extends Member> measureMembers = 
+                    new ArrayList<Member>();
 
             // load all root Members for Hierarchies that have no ALL
             // Member and load ALL Members that are not the default Member.
@@ -213,7 +214,8 @@
             query.putEvalCache("ALL_MEMBER_LIST", nonDefaultAllMembers);
 
 
-            final List<Member[]> emptyNonAllMembers = Collections.emptyList();
+            final List<List<? extends Member>> emptyNonAllMembers = 
+                    Collections.emptyList();
 
             /////////////////////////////////////////////////////////////////
             //
@@ -226,6 +228,7 @@
 
             if (! axisMembers.isEmpty()) {
                 for (Member m : axisMembers) {
+                    if(m==null) break;
                     evaluator.setSlicerContext(m);
                     if (m.isMeasure()) {
                         // A Measure was explicitly declared in the
@@ -369,7 +372,6 @@
                     final Calc calc = query.axisCalcs[i];
                     Axis axisResult = evalExecute(nonAllMembers,
                                 nonAllMembers.size()-1, e, axis, calc);
-
                     if (! nonAllMembers.isEmpty()) {
                         List<Position> pl = axisResult.getPositions();
                         for (Position p : pl) {
@@ -379,7 +381,8 @@
                                         new CalculatedMeasureVisitor();
                                     m.getExpression().accept(visitor);
                                     Dimension dimension = visitor.dimension;
-                                    redo = removeDimension(dimension, nonAllMembers);
+                                    redo = removeDimension(dimension, 
+                                                           nonAllMembers);
                                 }
                             }
                             // Only need to process the first Position
@@ -396,8 +399,12 @@
             //
             // Get value for each Cell
             //
-            executeBody(query);
+            
+            //executeBody(this.query); Lazy, for high cardinality
+            executeBody(this.query, new int[axes.length]);
             //
+            //
+            //
             /////////////////////////////////////////////////////////////////
 
             // If you are very close to running out of memory due to
@@ -445,12 +452,13 @@
             }
         }
     }
-    protected boolean removeDimension(Dimension dimension, List<Member[]> nonAllMembers) {
+    protected boolean removeDimension(final Dimension dimension, 
+            final List<List<? extends Member>> nonAllMembers) {
         boolean changed = false;
-        for (ListIterator<Member[]> it = nonAllMembers.listIterator();
-                it.hasNext();) {
-            Member[] ms = it.next();
-            Dimension d = ms[0].getHierarchy().getDimension();
+        for (ListIterator<List<? extends Member>> it 
+                = nonAllMembers.listIterator(); it.hasNext();) {
+            List<? extends Member> ms = it.next();
+            Dimension d = ms.get(0).getHierarchy().getDimension();
             if (d.equals(dimension)) {
                 it.remove();
             }
@@ -458,7 +466,8 @@
         return changed;
     }
 
-    private static class CalculatedMeasureVisitor extends mondrian.mdx.MdxVisitorImpl {
+    private static class CalculatedMeasureVisitor 
+    extends mondrian.mdx.MdxVisitorImpl {
         Dimension dimension;
         CalculatedMeasureVisitor() {
         }
@@ -499,15 +508,15 @@
         }
     }
 
-    protected boolean replaceNonAllMembers(List<Member[]> nonAllMembers,
-                                            AxisMember axisMembers) {
-
+    protected boolean replaceNonAllMembers(
+            final List<List<? extends Member>> nonAllMembers,
+            final AxisMember axisMembers) {
         boolean changed = false;
         List<Member> mList = new ArrayList<Member>();
-        for (ListIterator<Member[]> it = nonAllMembers.listIterator();
-                it.hasNext();) {
-            Member[] ms = it.next();
-            Hierarchy h = ms[0].getHierarchy();
+        for (ListIterator<List<? extends Member>> it 
+                = nonAllMembers.listIterator(); it.hasNext();) {
+            List<? extends Member> ms = it.next();
+            Hierarchy h = ms.get(0).getHierarchy();
             mList.clear();
             for (Member m : axisMembers) {
                 if (m.getHierarchy().equals(h)) {
@@ -516,24 +525,22 @@
             }
             if (! mList.isEmpty()) {
                 changed = true;
-                Member[] ml = mList.toArray(new Member[mList.size()]);
-                it.set(ml);
+                it.set(mList);
             }
         }
         return changed;
 
     }
 
-    protected void loadMembers(List<Member[]> nonAllMembers,
-                    RolapEvaluator evaluator, QueryAxis axis, Calc calc,
-                    AxisMember axisMembers) {
+    protected void loadMembers(final List<List<? extends Member>> nonAllMembers,
+            final RolapEvaluator evaluator, final QueryAxis axis, 
+            final Calc calc, final AxisMember axisMembers) {
         int attempt = 0;
         evaluator.setCellReader(batchingReader);
         while (true) {
             axisMembers.clearAxisCount();
-            evalLoad(
-                nonAllMembers, nonAllMembers.size() - 1,
-                evaluator, axis, calc, axisMembers);
+            evalLoad(nonAllMembers, nonAllMembers.size() - 1,
+                    evaluator, axis, calc, axisMembers);
 
             if (!batchingReader.loadAggregations(query)) {
                 break;
@@ -552,20 +559,23 @@
         }
     }
 
-    void evalLoad(List<Member[]> nonAllMembers, int cnt,
-            Evaluator evaluator, QueryAxis axis, Calc calc,
-            AxisMember axisMembers) {
+    void evalLoad(final List<List<? extends Member>> nonAllMembers, int cnt,
+            final Evaluator evaluator, final QueryAxis axis, final Calc calc,
+            final AxisMember axisMembers) {
         if (cnt < 0) {
             executeAxis(evaluator.push(), axis, calc, false, axisMembers);
         } else {
             for (Member m : nonAllMembers.get(cnt)) {
                 evaluator.setContext(m);
-                evalLoad(nonAllMembers, cnt-1, evaluator, axis, calc, axisMembers);
+                evalLoad(nonAllMembers, cnt-1, evaluator, axis, calc, 
+                        axisMembers);
             }
         }
     }
-    Axis evalExecute(List<Member[]> nonAllMembers, int cnt,
-            RolapEvaluator evaluator, QueryAxis axis, Calc calc) {
+
+    Axis evalExecute(final List<List<? extends Member>> nonAllMembers, 
+            final int cnt, final RolapEvaluator evaluator, 
+            final QueryAxis axis, final Calc calc) {
         Axis axisResult = null;
         if (cnt < 0) {
             evaluator.setCellReader(aggregatingReader);
@@ -576,7 +586,7 @@
         } else {
             for (Member m : nonAllMembers.get(cnt)) {
                 evaluator.setContext(m);
-                Axis a = evalExecute(nonAllMembers, cnt-1, evaluator, axis, calc);
+                Axis a = evalExecute(nonAllMembers,cnt-1,evaluator,axis,calc);
                 boolean ordered = false;
                 if (axis != null) {
                     ordered = axis.isOrdered();
@@ -599,12 +609,11 @@
      * @param measureMembers  List all Measures
      */
     protected void loadSpecialMembers(
-        List<Member> nonDefaultAllMembers,
-        List<Member[]> nonAllMembers,
-        List<Member> measureMembers)
-    {
+            final List<? extends Member> nonDefaultAllMembers,
+            final List<List<? extends Member>> nonAllMembers,
+            final List<? extends Member> measureMembers) {
         SchemaReader schemaReader = evaluator.getSchemaReader();
-        Member[] evalMembers = evaluator.getMembers();
+        List<? extends Member> evalMembers = evaluator.getMembers();
         for (Member em : evalMembers) {
             if (em.isCalculated()) {
                 continue;
@@ -615,16 +624,17 @@
                 continue;
             }
             if (!em.isAll()) {
-                Member[] rootMembers = schemaReader.getHierarchyRootMembers(h);
+                List<? extends Member> rootMembers = 
+                        schemaReader.getHierarchyRootMembers(h);
                 if (em.isMeasure()) {
                     for (Member mm : rootMembers) {
-                        measureMembers.add(mm);
+                        ((List) measureMembers).add(mm);
                     }
                 } else {
                     if (h.hasAll()) {
                         for (Member m : rootMembers) {
                             if (m.isAll()) {
-                                nonDefaultAllMembers.add(m);
+                                ((List) nonDefaultAllMembers).add(m);
                                 break;
                             }
                         }
@@ -655,12 +665,20 @@
      * @param pos Cell position.
      * @return the Cell associated with the Cell position.
      */
-    public Cell getCell(int[] pos) {
+    public Cell getCell(int[] pos) {    
         if (pos.length != point.size()) {
             throw Util.newError(
                     "coordinates should have dimension " + point.size());
         }
 
+        for(int i=0; i<pos.length; i++) {
+            if(positionsHighCardinality.get(i)) {
+                executeBody(this.query, pos);
+                break;
+            }
+        }
+
+
         CellInfo ci = cellInfos.lookup(pos);
         if (ci.value == null) {
             ci.value = Util.nullValue;
@@ -669,13 +687,9 @@
         return new RolapCell(this, pos.clone(), ci);
     }
 
-    private Axis executeAxis(
-        Evaluator evaluator,
-        QueryAxis axis,
-        Calc axisCalc,
-        boolean construct,
-        AxisMember axisMembers)
-    {
+    private Axis executeAxis(final Evaluator evaluator,
+            final QueryAxis axis, final Calc axisCalc,
+            final boolean construct, final AxisMember axisMembers) {
         Axis axisResult = null;
         if (axis == null) {
             // Create an axis containing one position with no members (not
@@ -683,7 +697,6 @@
             if (construct) {
                 axisResult = new RolapAxis.SingleEmptyPosition();
             }
-
         } else {
             evaluator.setNonEmpty(axis.isNonEmpty());
             evaluator.setEvalAxes(true);
@@ -693,16 +706,17 @@
             }            
             evaluator.setNonEmpty(false);
             if (value != null) {
-                // List or Iterable of Member or Member[]
+                // List or Iterable of Member or List<Member>
                 if (value instanceof List) {
                     List<Object> list = (List) value;
                     if (construct) {
-                        if (list.size() == 0) {
+                        if (list.isEmpty()) {
                             // should be???
                             axisResult = new RolapAxis.NoPosition();
-                        } else if (list.get(0) instanceof Member[]) {
+                        } else if (list.get(0) instanceof List) {
                             axisResult =
-                                new RolapAxis.MemberArrayList((List<Member[]>)value);
+                                new RolapAxis.MemberArrayList(
+                                        (List<List<Member>>)value);
                         } else {
                             axisResult =
                                 new RolapAxis.MemberList((List<Member>)value);
@@ -717,9 +731,9 @@
                     if (construct) {
                         if (! it.hasNext()) {
                             axisResult = new RolapAxis.NoPosition();
-                        } else if (it.next() instanceof Member[]) {
+                        } else if (it.next() instanceof List) {
                             axisResult = new RolapAxis.MemberArrayIterable(
-                                            (Iterable<Member[]>)value);
+                                            (Iterable<List<Member>>)value);
                         } else {
                             axisResult = new RolapAxis.MemberIterable(
                                             (Iterable<Member>)value);
@@ -734,50 +748,45 @@
         return axisResult;
     }
 
-    private void executeBody(Query query) {
-        try {
-            // Compute the cells several times. The first time, use a dummy
-            // evaluator which collects requests.
-            int count = 0;
-            while (true) {
+    private void executeBody(final Query query, final int pos[]) {
+        // Compute the cells several times. The first time, use a dummy
+        // evaluator which collects requests.
+        int count = 0;
+        while (true) {
+            evaluator.setCellReader(batchingReader);
+            executeStripe(query.axes.length - 1,
+                            (RolapEvaluator) evaluator.push(), pos);
 
-                evaluator.setCellReader(batchingReader);
-                executeStripe(query.axes.length - 1,
-                                (RolapEvaluator) evaluator.push());
-
-                // Retrieve the aggregations collected.
-                //
-                if (!batchingReader.loadAggregations(query)) {
-                    // We got all of the cells we needed, so the result must be
-                    // correct.
-                    return;
-                } else {
-                    // Clear invalid expression result so that the next evaluation
-                    // will pick up the newly loaded aggregates.
-                    evaluator.clearExpResultCache(false);
-                }
-                
-                if (count++ > maxEvalDepth) {
-                    if (evaluator instanceof RolapDependencyTestingEvaluator) {
-                        // The dependency testing evaluator can trigger new
-                        // requests every cycle. So let is run as normal for
-                        // the first N times, then run it disabled.
-                        ((RolapDependencyTestingEvaluator.DteRoot)
-                            evaluator.root).disabled = true;
-                        if (count > maxEvalDepth * 2) {
-                            throw Util.newInternal("Query required more than "
-                                + count + " iterations");
-                        }
-                    } else {
+            // Retrieve the aggregations collected.
+            //
+            
+            if (!batchingReader.loadAggregations(query)) {
+                // We got all of the cells we needed, so the result must be
+                // correct.
+                break;
+            } else {
+                // Clear invalid expression result so that the next evaluation
+                // will pick up the newly loaded aggregates.
+                evaluator.clearExpResultCache(false);
+            }
+            
+            if (count++ > maxEvalDepth) {
+                if (evaluator instanceof RolapDependencyTestingEvaluator) {
+                    // The dependency testing evaluator can trigger new
+                    // requests every cycle. So let is run as normal for
+                    // the first N times, then run it disabled.
+                    ((RolapDependencyTestingEvaluator.DteRoot)
+                        evaluator.root).disabled = true;
+                    if (count > maxEvalDepth * 2) {
                         throw Util.newInternal("Query required more than "
                             + count + " iterations");
                     }
+                } else {
+                    throw Util.newInternal("Query required more than "
+                        + count + " iterations");
                 }
-
-                cellInfos.clear();
             }
-        } finally {
-
+            cellInfos.clear();
         }
     }
 
@@ -822,11 +831,12 @@
         return calc.evaluate(ev);
     }
 
-    private void executeStripe(int axisOrdinal, RolapEvaluator revaluator) {
+    private void executeStripe(final int axisOrdinal, 
+            final RolapEvaluator revaluator, final int pos[]) {
         if (axisOrdinal < 0) {
             Axis axis = slicerAxis;
-            List<Position> positions = axis.getPositions();
-            for (Position position: positions) {
+            final List<Position> positions = axis.getPositions();
+            for(final Position position : positions) {
                 getQuery().checkCancelOrTimeout();
                 revaluator.setContext(position);
                 Object o;
@@ -860,14 +870,14 @@
                     // FormatValueFormatter.
                     final RolapCube cube = getCube();
                     Dimension measuresDim =
-                        cube.getMeasuresHierarchy().getDimension();
+                            cube.getMeasuresHierarchy().getDimension();
                     RolapMeasure m =
-                        (RolapMeasure) revaluator.getContext(measuresDim);
+                            (RolapMeasure) revaluator.getContext(measuresDim);
                     CellFormatter cf = m.getFormatter();
                     if (cf != null) {
                         valueFormatter = cellFormatters.get(cf);
                         if (valueFormatter == null) {
-                            valueFormatter = new CellFormatterValueFormatter(cf);
+                            valueFormatter=new CellFormatterValueFormatter(cf);
                             cellFormatters.put(cf, valueFormatter);
                         }
                     } else {
@@ -882,11 +892,9 @@
 
                     ci.formatString = cachedFormatString;
                     ci.valueFormatter = valueFormatter;
-
                 } catch (ResultLimitExceededException e) {
                     // Do NOT ignore a ResultLimitExceededException!!!
                     throw e;
-
                 } catch (MondrianEvaluationException e) {
                     // ignore but warn
                     LOGGER.warn("Mondrian: exception in executeStripe.", e);
@@ -899,25 +907,86 @@
                 }
 
                 if (o == RolapUtil.valueNotReadyException) {
-                    continue;
+                    return;
                 }
-
                 ci.value = o;
             }
         } else {
             Axis axis = axes[axisOrdinal];
             List<Position> positions = axis.getPositions();
-            int i = 0;
-            for (Position position: positions) {
-                point.setAxis(axisOrdinal, i);
-                revaluator.setContext(position);
-                getQuery().checkCancelOrTimeout();
-                executeStripe(axisOrdinal - 1, revaluator);
-                i++;
+
+            if(positionsHighCardinality.get(axisOrdinal)==null) {
+                try {
+                    positionsHighCardinality.put(axisOrdinal,
+                        positions.get(0).get(0).getDimension()
+                        .isHighCardinality());
+                } catch(IndexOutOfBoundsException ioobe) {
+                    // No elements... no problem
+                }
             }
+
+            if(positionsHighCardinality.get(axisOrdinal)!=null
+                    && positionsHighCardinality.get(axisOrdinal)) {
+                final int LIMIT = MondrianProperties.instance()
+                        .HighCardChunkSize.get();
+                if(positionsIterators.get(axisOrdinal)==null) {
+                    final Iterator<Position> it = positions.iterator();
+                    positionsIterators.put(axisOrdinal, it);
+                    positionsIndexes.put(axisOrdinal, 0);
+                    final List<Position> subPositions = 
+                            new ArrayList<Position>();
+                    for(int i=0; i<LIMIT && it.hasNext(); i++) {
+                        subPositions.add(it.next());
+                    }
+                    positionsCurrent.put(axisOrdinal, subPositions);
+                } 
+                final Iterator<Position> it = 
+                        positionsIterators.get(axisOrdinal);
+                final int positionIndex = positionsIndexes.get(axisOrdinal);
+                List<Position> subPositions=positionsCurrent.get(axisOrdinal);
+
+                if(subPositions==null) return;
+
+                int pi;
+                if(pos[axisOrdinal]>positionIndex+subPositions.size()-1
+                        && subPositions.size()==LIMIT) {
+                    pi = positionIndex + subPositions.size();
+                    positionsIndexes.put(axisOrdinal, positionIndex
+                                + subPositions.size());
+                    subPositions.subList(0, subPositions.size()).clear();
+                    for(int i=0; i<LIMIT && it.hasNext(); i++) {
+                        subPositions.add(it.next());
+                    }
+                    positionsCurrent.put(axisOrdinal, subPositions);
+                } else {
+                    pi = positionIndex;
+                }
+
+                for(final Position position : subPositions) {
+                    point.setAxis(axisOrdinal, pi);
+                    revaluator.setContext(position);
+                    getQuery().checkCancelOrTimeout();
+                    executeStripe(axisOrdinal - 1, revaluator, pos);
+                    pi++;
+                }
+            } else {
+                int positionIndex = 0;
+                for(final Position position : positions) {
+                    point.setAxis(axisOrdinal, positionIndex);
+                    revaluator.setContext(position);
+                    getQuery().checkCancelOrTimeout();
+                    executeStripe(axisOrdinal - 1, revaluator, pos);
+                    positionIndex++;
+                }
+            }
         }
     }
+private final Map<Integer, Boolean> positionsHighCardinality = new HashMap<Integer, Boolean>();
+private final Map<Integer, Iterator<Position>> positionsIterators = new HashMap<Integer, Iterator<Position>>();
+private final Map<Integer, Integer> positionsIndexes = new HashMap<Integer, Integer>();
+private final Map<Integer, List<Position>> positionsCurrent = new HashMap<Integer, List<Position>>();
 
+
     /**
      * Converts a cell ordinal to a set of cell coordinates. Converse of
      * {@link #getCellOrdinal}. For example, if this result is 10 x 10 x 10,
@@ -979,15 +1048,16 @@
      * @param pos Coordinates of cell
      * @return Members which form the context of the given cell
      */
-    Member[] getCellMembers(int[] pos) {
-        Member[] members = evaluator.getMembers().clone();
+    List<Member> getCellMembers(int[] pos) {
+        List<Member> members = new ArrayList<Member>(
+                evaluator.getMembers());
         final Cube cube = getCube();
         for (int i = 0; i < pos.length; i++) {
             Position position = axes[i].getPositions().get(pos[i]);
             for (Member member: position) {
                 RolapMember m = (RolapMember) member;
                 int ordinal = m.getDimension().getOrdinal(cube);
-                members[ordinal] = m;
+                members.set(ordinal, m);
             }
 
         }
@@ -1037,7 +1107,7 @@
 
         AxisMember() {
             this.countOnly = false;
-            this.members = new ArrayList<Member>();
+            this.members = new ConcatenableList<Member>();
             this.totalCellCount = 1;
             this.axisCount = 0;
             // Now that the axes are evaluated, make sure that the number of
@@ -1083,26 +1153,29 @@
         }
         void merge(Object value) {
             List<Object> list = (List) value;
-            if (list.size() != 0) {
-                if (list.get(0) instanceof Member[]) {
-                    for (Member[] o : (List<Member[]>) value) {
+            try {
+                if (list.get(0) instanceof List) {
+                    for (List<Member> o : (List<List<Member>>) value) {
                         merge(o);
                     }
                 } else {
                     for (Member o : (List<Member>) value) {
+                        if(o==null) continue;
+                        if(o.getDimension().isHighCardinality()) break;
                         merge(o);
                     }
                 }
+            } catch(IndexOutOfBoundsException e) {
             }
         }
         void merge(Iterator it) {
             if (it.hasNext()) {
                 Object o = it.next();
-                if (o instanceof Member[]) {
-                    merge((Member[]) o);
+                if (o instanceof List) {
+                    merge((List<Member>) o);
                     while (it.hasNext()) {
                         o = it.next();
-                        merge((Member[]) o);
+                        merge((List<Member>) o);
                     }
                 } else {
                     merge((Member) o);
@@ -1118,7 +1191,7 @@
             return (parent == null) ? m : getTopParent(parent);
         }
 
-        private void merge(final Member[] members) {
+        private void merge(final List<Member> members) {
             for (Member member : members) {
                 merge(member);
             }
@@ -1132,7 +1205,7 @@
                         members.add(member);
                     }
                 } else {
-                    if (member.isNull()) {
+                    if (member==null || member.isNull()) {
                         return;
                     } else if (member.isMeasure()) {
                         return;
@@ -1469,6 +1542,7 @@
          * @return formatted value of the Cell
          */
         String getFormatValue() {
+//return value.toString();
             return valueFormatter.format(value, formatString);
         }
     }
@@ -1766,27 +1840,21 @@
             return new RolapAxis.MemberList(list);
         } else {
             // array of Members per position
-            List<Member[]> list = new ArrayList<Member[]>();
-            for (Position p1: pl1) {
-                Member[] members = new Member[arrayLen];
-                int i = 0;
-                for (Member m1: p1) {
-                    members[i++] = m1;
-                }
+            List<List<Member>> list = new ArrayList<List<Member>>();
+            for (final Position p1: pl1) {
+                final List<Member> members = new ArrayList<Member>();
+                for(Member p : p1) members.add(p);
                 list.add(members);
             }
-            List<Member[]> extras = new ArrayList<Member[]>();
-            for (Position p2: pl2) {
-                int i = 0;
-                Member[] members = new Member[arrayLen];
-                for (Member m2: p2) {
-                    members[i++] = m2;
-                }
-                Iterator<Member[]> it1 = list.iterator();
+            List<List<Member>> extras = new ArrayList<List<Member>>();
+            for (final Position p2: pl2) {
+                final List<Member> members = new ArrayList<Member>();
+                for(Member p : p2) members.add(p);
+                Iterator<List<Member>> it1 = list.iterator();
                 boolean found = false;
                 while (it1.hasNext()) {
-                    Member[] m1 = it1.next();
-                    if (java.util.Arrays.equals(members, m1)) {
+                    List<Member> m1 = it1.next();
+                    if (members.equals(m1)) {
                         found = true;
                         break;
                     }
@@ -1799,10 +1867,11 @@
 
             // if there are unique members on both axes and no order function,
             //  sort the list to ensure default order   
-            if (list.size() > 0 && extras.size() > 0 && ordered == false) {
-                Member[] membs = list.get(0);
-                int membsSize = membs.length;
-                ValueCalc valCalc = new ValueCalc(new DummyExp(new ScalarType()));
+            if (!list.isEmpty() && extras.size() > 0 && ordered == false) {
+                List<Member> membs = list.get(0);
+                int membsSize = membs.size();
+                ValueCalc valCalc = new ValueCalc(
+                        new DummyExp(new ScalarType()));
                 FunUtil.sortTuples(evaluator, list, valCalc,
                         false, false, membsSize);
             }
Index: src/main/mondrian/rolap/RolapCube.java
===================================================================
--- src/main/mondrian/rolap/RolapCube.java	
+++ src/main/mondrian/rolap/RolapCube.java	
@@ -121,7 +121,8 @@
                 schema,
                 Dimension.MEASURES_NAME,
                 0,
-                DimensionType.StandardDimension);
+                DimensionType.StandardDimension,
+                false);
 
         this.dimensions[0] = measuresDimension;
 
@@ -176,7 +177,7 @@
         RolapLevel measuresLevel =
             this.measuresHierarchy.newLevel("MeasuresLevel", 0);
 
-        RolapMember measures[] = new RolapMember[xmlCube.measures.length];
+        List<RolapMeasure> measures = new ArrayList<RolapMeasure>();
         Member defaultMeasure = null;
         for (int i = 0; i < xmlCube.measures.length; i++) {
             MondrianDef.Measure xmlMeasure = xmlCube.measures[i];
@@ -207,7 +208,7 @@
                     this, null, measuresLevel, xmlMeasure.name,
                     xmlMeasure.formatString, measureExp,
                 aggregator, xmlMeasure.datatype);
-            measures[i] = measure;
+            measures.add(measure);
             if(Util.equalName(measure.getName(),xmlCube.defaultMeasure)){
                 defaultMeasure = measure;
             }
@@ -281,24 +282,26 @@
 
         // Recreate CalculatedMembers, as the original members point to
         // incorrect dimensional ordinals for the virtual cube.
-        List<RolapVirtualCubeMeasure> origMeasureList =
-            new ArrayList<RolapVirtualCubeMeasure>();
+        List<RolapMeasure> origMeasureList = new ArrayList<RolapMeasure>();
         List<MondrianDef.CalculatedMember> origCalcMeasureList =
             new ArrayList<MondrianDef.CalculatedMember>();
         CubeComparator cubeComparator = new CubeComparator();
-        Map<RolapCube, List<MondrianDef.CalculatedMember>> calculatedMembersMap =
-            new TreeMap<RolapCube, List<MondrianDef.CalculatedMember>>(
-                cubeComparator);
+        Map<RolapCube, List<MondrianDef.CalculatedMember>> 
+                calculatedMembersMap = new TreeMap<
+                        RolapCube, List<MondrianDef.CalculatedMember>>(
+                                cubeComparator);
         Member defaultMeasure = null;
 
-        for (MondrianDef.VirtualCubeMeasure xmlMeasure : xmlVirtualCube.measures) {
+        for (MondrianDef.VirtualCubeMeasure xmlMeasure 
+                : xmlVirtualCube.measures) {
             // Lookup a measure in an existing cube.
             RolapCube cube = schema.lookupCube(xmlMeasure.cubeName);
-            Member[] cubeMeasures = cube.getMeasures();
+            List<? extends Member> cubeMeasures = cube.getMeasures();
             boolean found = false;
             for (Member cubeMeasure : cubeMeasures) {
                 if (cubeMeasure.getUniqueName().equals(xmlMeasure.name)) {
-                    if (cubeMeasure.getName().equalsIgnoreCase(xmlVirtualCube.defaultMeasure)){
+                    if (cubeMeasure.getName().equalsIgnoreCase(
+                            xmlVirtualCube.defaultMeasure))  {
                         defaultMeasure = cubeMeasure;
                     }
                     found = true;
@@ -363,7 +366,8 @@
         // referenced by this virtual cube.  Resolve those members relative
         // to their base cubes first, then resolve them relative to this
         // cube so the correct dimension ordinals are used
-        List<RolapVirtualCubeMeasure> modifiedMeasureList = new ArrayList<RolapVirtualCubeMeasure>(origMeasureList);
+        List<RolapMeasure> modifiedMeasureList = 
+                new ArrayList<RolapMeasure>(origMeasureList);
         for (Object o : calculatedMembersMap.keySet()) {
             RolapCube baseCube = (RolapCube) o;
             List<MondrianDef.CalculatedMember> calculatedMemberList =
@@ -395,16 +399,13 @@
         // Resolve all calculated members relative to this virtual cube,
         // whose measureHierarchy member reader now contains all base
         // measures referenced in those calculated members
-        RolapMember[] measures =
-            modifiedMeasureList.toArray(
-                new RolapMember[modifiedMeasureList.size()]);
+        List<RolapMeasure> measures = modifiedMeasureList;
         this.measuresHierarchy.setMemberReader(
             new CacheMemberReader(
                 new MeasureMemberSource(this.measuresHierarchy, measures)));
         createCalcMembersAndNamedSets(
             calculatedMemberList.toArray(
-                new MondrianDef.CalculatedMember[
-                    calculatedMemberList.size()]),
+                new MondrianDef.CalculatedMember[0]),
                 new MondrianDef.NamedSet[0],
                 new ArrayList<Member>(),
                 new ArrayList<Formula>(),
@@ -413,9 +414,7 @@
 
         // reset the measureHierarchy member reader back to the list of
         // measures that are only defined on this virtual cube
-        measures =
-            origMeasureList.toArray(
-                new RolapMember[origMeasureList.size()]);
+        measures = origMeasureList;
         this.measuresHierarchy.setMemberReader(
             new CacheMemberReader(
                 new MeasureMemberSource(this.measuresHierarchy, measures)));
@@ -629,13 +628,13 @@
      */
     private void checkOrdinals(
             String cubeName,
-            RolapMember measures[],
+            List<RolapMeasure> measures,
             MondrianDef.CalculatedMember[] xmlCalcMembers)
     {
         Map<Integer, String> ordinals = new HashMap<Integer, String>();
 
         // step 1: check the stored measures
-        for (RolapMember measure : measures) {
+        for (RolapMeasure measure : measures) {
             Integer ordinal = measure.getOrdinal();
             if (!ordinals.containsKey(ordinal)) {
                 ordinals.put(ordinal, measure.getUniqueName());
@@ -1068,7 +1067,7 @@
             return;
         }
         List<Member> list = new ArrayList<Member>();
-        Member[] measures = getMeasures();
+        List<? extends Member> measures = getMeasures();
         for (Member measure : measures) {
             if (measure instanceof RolapBaseCubeMeasure) {
                 list.add(measure);
@@ -2104,11 +2103,12 @@
 
 
 
-    public Member[] getMembersForQuery(String query, List<Member> calcMembers) {
+    public List<Member> getMembersForQuery(
+            String query, List<Member> calcMembers) {
         throw new UnsupportedOperationException();
     }
 
-    Member[] getMeasures() {
+    List<? extends Member> getMeasures() {
         Level measuresLevel = dimensions[0].getHierarchies()[0].getLevels()[0];
         return getSchemaReader().getLevelMembers(measuresLevel, true);
     }
@@ -2295,12 +2295,12 @@
     /**
      * Returns the the measures hierarchy.
      */
-    public Hierarchy getMeasuresHierarchy(){
+    public Hierarchy getMeasuresHierarchy() {
         return measuresHierarchy;
     }
 
     // RME
-    public RolapMember[] getMeasuresMembers(){
+    public List<? extends Member> getMeasuresMembers(){
         return measuresHierarchy.getMemberReader().getMembers();
     }
 
@@ -2345,13 +2345,13 @@
             assert role != null : "precondition: role != null";
         }
 
-        public Member[] getLevelMembers(
+        public List<? extends Member> getLevelMembers(
                 Level level, boolean includeCalculated) {
-            Member[] members = super.getLevelMembers(level, false);
+            List<? extends Member> members = 
+                    super.getLevelMembers(level, false);
             if (includeCalculated) {
-                members = Util.addLevelCalculatedMembers(this, level, members);
-            }
-            return members;
+                return Util.addLevelCalculatedMembers(this, level, members);
+            } else return members;
         }
 
 
@@ -2480,12 +2480,12 @@
         /**
          * List of measures found
          */
-        private List<RolapVirtualCubeMeasure> measuresFound;
+        private List<RolapMeasure> measuresFound;
 
         /**
          * List of calculated members found
          */
-        private List<RolapCalculatedMember> calcMembersSeen;
+        private List<RolapMember> calcMembersSeen;
 
         public MeasureFinder(
             RolapCube virtualCube,
@@ -2495,8 +2495,8 @@
             this.virtualCube = virtualCube;
             this.baseCube = baseCube;
             this.measuresLevel = measuresLevel;
-            this.measuresFound = new ArrayList<RolapVirtualCubeMeasure>();
-            this.calcMembersSeen = new ArrayList<RolapCalculatedMember>();
+            this.measuresFound = new ArrayList<RolapMeasure>();
+            this.calcMembersSeen = new ArrayList<RolapMember>();
         }
 
         public Object visit(MemberExpr memberExpr)
@@ -2517,9 +2517,7 @@
                 // now that we've located all measures referenced in the
                 // calculated member's formula, resolve the calculated
                 // member relative to the virtual cube
-                RolapMember[] measures = (RolapMember[])
-                    measuresFound.toArray(
-                        new RolapMember[measuresFound.size()]);
+                List<RolapMeasure> measures = measuresFound;
                 virtualCube.measuresHierarchy.setMemberReader(
                     new CacheMemberReader(
                         new MeasureMemberSource(
@@ -2553,7 +2551,7 @@
             return null;
         }
 
-        public List<RolapVirtualCubeMeasure> getMeasuresFound()
+        public List<RolapMeasure> getMeasuresFound()
         {
             return measuresFound;
         }
Index: src/main/mondrian/rolap/DelegatingMemberReader.java
===================================================================
--- src/main/mondrian/rolap/DelegatingMemberReader.java	
+++ src/main/mondrian/rolap/DelegatingMemberReader.java	
@@ -14,6 +14,7 @@
 import java.util.List;
 
 import mondrian.olap.Id;
+import mondrian.olap.Member;
 import mondrian.rolap.TupleReader.MemberBuilder;
 import mondrian.rolap.sql.TupleConstraint;
 import mondrian.rolap.sql.MemberChildrenConstraint;
@@ -37,7 +38,7 @@
         return memberReader.getLeadMember(member, n);
     }
 
-    public List<RolapMember> getMembersInLevel(
+    public List<? extends Member> getMembersInLevel(
         RolapLevel level,
         int startOrdinal,
         int endOrdinal)
@@ -49,7 +50,7 @@
         RolapLevel level,
         RolapMember startMember,
         RolapMember endMember,
-        List<RolapMember> list)
+        List<? extends Member> list)
     {
         memberReader.getMemberRange(level, startMember, endMember, list);
     }
@@ -70,19 +71,21 @@
         return memberReader.setCache(cache);
     }
 
-    public RolapMember[] getMembers() {
+    public List<? extends Member> getMembers() {
         return memberReader.getMembers();
     }
 
-    public List<RolapMember> getRootMembers() {
+    public List<? extends Member> getRootMembers() {
         return memberReader.getRootMembers();
     }
 
-    public void getMemberChildren(RolapMember parentMember, List<RolapMember> children) {
+    public void getMemberChildren(final Member parentMember, 
+            final List<? extends Member> children) {
         memberReader.getMemberChildren(parentMember, children);
     }
 
-    public void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children) {
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children) {
         memberReader.getMemberChildren(parentMembers, children);
     }
 
@@ -90,21 +93,28 @@
         return memberReader.getMemberCount();
     }
 
-    public RolapMember lookupMember(List<Id.Segment> uniqueNameParts,
+    public Member lookupMember(List<Id.Segment> uniqueNameParts,
                                     boolean failIfNotFound) {
         return memberReader.lookupMember(uniqueNameParts, failIfNotFound);
     }
 
-    public void getMemberChildren(RolapMember member, List<RolapMember> children, MemberChildrenConstraint constraint) {
+    public void getMemberChildren(final Member member, 
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         memberReader.getMemberChildren(member, children, constraint);
     }
 
-    public void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children, MemberChildrenConstraint constraint) {
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         memberReader.getMemberChildren(parentMembers, children, constraint);
     }
 
-    public List<RolapMember> getMembersInLevel(RolapLevel level, int startOrdinal, int endOrdinal, TupleConstraint constraint) {
-        return memberReader.getMembersInLevel(level, startOrdinal, endOrdinal, constraint);
+    public List<? extends Member> getMembersInLevel(final RolapLevel level, 
+            final int startOrdinal, final int endOrdinal, 
+            final TupleConstraint constraint) {
+        return memberReader.getMembersInLevel(level, startOrdinal, 
+                endOrdinal, constraint);
     }
 
     public MemberBuilder getMemberBuilder() {
Index: src/main/mondrian/rolap/RestrictedMemberReader.java
===================================================================
--- src/main/mondrian/rolap/RestrictedMemberReader.java	
+++ src/main/mondrian/rolap/RestrictedMemberReader.java	
@@ -80,34 +80,29 @@
         return member;
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children)
-    {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children) {
         MemberChildrenConstraint constraint =
-            sqlConstraintFactory.getMemberChildrenConstraint(null);
+                sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMember, children, constraint);
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         List<RolapMember> fullChildren = new ArrayList<RolapMember>();
         memberReader.getMemberChildren(parentMember, fullChildren, constraint);
         processMemberChildren(fullChildren, children, constraint);
     }
 
     private void processMemberChildren(
-        List<RolapMember> fullChildren,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+            final List<? extends Member> fullChildren,
+            final List<? extends Member> children,
+            final MemberChildrenConstraint constraint) {
         // todo: optimize if parentMember is beyond last level
         List<RolapMember> grandChildren = null;
         for (int i = 0; i < fullChildren.size(); i++) {
-            RolapMember member = fullChildren.get(i);
+            RolapMember member = (RolapMember) fullChildren.get(i);
             // If a child is hidden (due to raggedness) include its children.
             // This must be done before applying access-control.
             if (ragged) {
@@ -122,8 +117,9 @@
                     } else {
                         grandChildren.clear();
                     }
-                    memberReader.getMemberChildren(member, grandChildren, constraint);
-                    fullChildren.addAll(i, grandChildren);
+                    memberReader.getMemberChildren(member, 
+                            grandChildren, constraint);
+                    ((List) fullChildren).addAll(i, grandChildren);
                     // Step back to before the first child we just inserted,
                     // and go through the loop again.
                     --i;
@@ -138,7 +134,7 @@
                     continue;
                 }
             }
-            children.add(member);
+            ((List) children).add(member);
         }
     }
 
@@ -147,13 +143,11 @@
      * @param members Input list
      * @param filteredMembers Output list
      */
-    private void filterMembers(
-        List<RolapMember> members,
-        List<RolapMember> filteredMembers)
-    {
-        for (RolapMember member : members) {
-            if (canSee(member)) {
-                filteredMembers.add(member);
+    private void filterMembers(final List<? extends Member> members,
+            final List<? extends Member> filteredMembers) {
+        for (Member member : members) {
+            if (canSee((RolapMember) member)) {
+                ((List) filteredMembers).add((RolapMember) member);
             }
         }
     }
@@ -169,12 +163,17 @@
         return true;
     }
 
-    public void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children) {
-        MemberChildrenConstraint constraint = sqlConstraintFactory.getMemberChildrenConstraint(null);
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children) {
+        MemberChildrenConstraint constraint = 
+                sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMembers, children, constraint);
     }
 
-    public synchronized void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children, MemberChildrenConstraint constraint) {
+    public synchronized void getMemberChildren(
+            final List<? extends Member> parentMembers, 
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
 //        for (Iterator i = parentMembers.iterator(); i.hasNext();) {
 //            RolapMember parentMember = (RolapMember) i.next();
 //            getMemberChildren(parentMember, children, constraint);
@@ -184,14 +183,15 @@
         processMemberChildren(fullChildren, children, constraint);
     }
 
-    public List<RolapMember> getMembersInLevel(RolapLevel level,
+    public List<? extends Member> getMembersInLevel(RolapLevel level,
                                   int startOrdinal,
                                   int endOrdinal) {
-        TupleConstraint constraint = sqlConstraintFactory.getLevelMembersConstraint(null);
+        TupleConstraint constraint = 
+                sqlConstraintFactory.getLevelMembersConstraint(null);
         return getMembersInLevel(level, startOrdinal, endOrdinal, constraint);
     }
 
-    public List<RolapMember> getMembersInLevel(RolapLevel level,
+    public List<? extends Member> getMembersInLevel(RolapLevel level,
                                 int startOrdinal,
                                 int endOrdinal,
                                 TupleConstraint constraint) {
@@ -204,9 +204,10 @@
                 return Collections.emptyList();
             }
         }
-        final List<RolapMember> membersInLevel = super.getMembersInLevel(level,
-                startOrdinal, endOrdinal, constraint);
-        List<RolapMember> filteredMembers = new ArrayList<RolapMember>();
+        final List<? extends Member> membersInLevel = 
+                super.getMembersInLevel(level, startOrdinal, endOrdinal, 
+                        constraint);
+        final List<RolapMember> filteredMembers = new ArrayList<RolapMember>();
         filterMembers(membersInLevel, filteredMembers);
         return filteredMembers;
     }
Index: src/main/mondrian/rolap/cache/SoftSmartCache.java
===================================================================
--- src/main/mondrian/rolap/cache/SoftSmartCache.java	
+++ src/main/mondrian/rolap/cache/SoftSmartCache.java	
@@ -82,6 +82,7 @@
         if (value == null) {
             cache.remove(key);
         }
+
         return value;
     }
 
Index: src/main/mondrian/rolap/DefaultMemberChildrenConstraint.java
===================================================================
--- src/main/mondrian/rolap/DefaultMemberChildrenConstraint.java	
+++ src/main/mondrian/rolap/DefaultMemberChildrenConstraint.java	
@@ -11,6 +11,7 @@
 import java.util.List;
 import java.util.Map;
 
+import mondrian.olap.Member;
 import mondrian.rolap.sql.MemberChildrenConstraint;
 import mondrian.rolap.sql.SqlQuery;
 import mondrian.rolap.aggmatcher.AggStar;
@@ -34,25 +35,20 @@
     protected DefaultMemberChildrenConstraint() {
     }
 
-    public void addMemberConstraint(
-        SqlQuery sqlQuery,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap,
-        AggStar aggStar,
-        RolapMember parent)
-    {
+    public void addMemberConstraint(final SqlQuery sqlQuery,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final Map<String, RolapStar.Table> relationNamesToStarTableMap,
+            final AggStar aggStar, final RolapMember parent) {
         SqlConstraintUtils.addMemberConstraint(
             sqlQuery, levelToColumnMap, relationNamesToStarTableMap,
             aggStar, parent, true);
     }
 
-    public void addMemberConstraint(
-        SqlQuery sqlQuery,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap,
-        AggStar aggStar,
-        List<RolapMember> parents)
-    {
+    public void addMemberConstraint(final SqlQuery sqlQuery,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final Map<String, RolapStar.Table> relationNamesToStarTableMap,
+            final AggStar aggStar,
+            final List<? extends Member> parents) {
         SqlConstraintUtils.addMemberConstraint(
             sqlQuery,
             levelToColumnMap,
@@ -63,11 +59,9 @@
             false);
     }
 
-    public void addLevelConstraint(
-        SqlQuery query,
-        AggStar aggStar,
-        RolapLevel level,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap) {
+    public void addLevelConstraint(final  SqlQuery query,
+            final AggStar aggStar, final RolapLevel level,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap) {
     }
 
     public String toString() {
Index: src/main/mondrian/rolap/SmartMemberListCache.java
===================================================================
--- src/main/mondrian/rolap/SmartMemberListCache.java	
+++ src/main/mondrian/rolap/SmartMemberListCache.java	
@@ -100,7 +100,7 @@
     }
 
     public V get(K key, SqlConstraint constraint) {
-        Key2<K, Object> key2 = new Key2<K, Object>(key, constraint.getCacheKey());
+        Key2<K,Object> key2 = new Key2<K,Object>(key, constraint.getCacheKey());
         return cache.get(key2);
     }
 
Index: src/main/mondrian/rolap/RolapEvaluator.java
===================================================================
--- src/main/mondrian/rolap/RolapEvaluator.java	
+++ src/main/mondrian/rolap/RolapEvaluator.java	
@@ -53,7 +53,7 @@
      */
     private static final Object nullResult = new Object();
 
-    private final RolapMember[] currentMembers;
+    private final Member[] currentMembers;
     private final Evaluator parent;
     protected CellReader cellReader;
     private final int depth;
@@ -64,7 +64,7 @@
     private int iterationLength;
     private boolean evalAxes;
 
-    private final Member[] calcMembers;
+    private final List<Member> calcMembers;
     private int calcMemberCount;
 
     /**
@@ -95,8 +95,8 @@
             nonEmpty = false;
             evalAxes = false;
             cellReader = null;
-            currentMembers = new RolapMember[root.cube.getDimensions().length];
-            calcMembers = new Member[this.currentMembers.length];
+            currentMembers = new Member[root.cube.getDimensions().length];
+            calcMembers = new ArrayList<Member>(this.currentMembers.length);
             calcMemberCount = 0;
             slicerMembers = new ArrayList<Member>();
             aggregationLists = null;
@@ -106,7 +106,7 @@
             evalAxes = parent.evalAxes;
             cellReader = parent.cellReader;
             currentMembers = parent.currentMembers.clone();
-            calcMembers = parent.calcMembers.clone();
+            calcMembers = new ArrayList<Member>(parent.calcMembers);
             calcMemberCount = parent.calcMemberCount;
             slicerMembers = new ArrayList<Member> (parent.slicerMembers);
             if (parent.aggregationLists != null) {
@@ -298,8 +298,8 @@
         return LOGGER;
     }
 
-    public final Member[] getMembers() {
-        return currentMembers;
+    public final List<Member> getMembers() {
+        return Arrays.asList(currentMembers.clone());
     }
 
     final void setCellReader(CellReader cellReader) {
@@ -330,7 +330,7 @@
         return root.getQueryStartTime();
     }
     
-    public final RolapEvaluator push(Member[] members) {
+    public final RolapEvaluator push(List<Member> members) {
         final RolapEvaluator evaluator = _push();
         evaluator.setContext(members);
         return evaluator;
@@ -383,7 +383,7 @@
     }
 
     public final int hashCode() {
-        return Util.hashArray(0, this.currentMembers);
+        return Util.hash(0, this.currentMembers);
     }
 
     /**
@@ -468,42 +468,25 @@
     public void setContext(List<Member> memberList) {
         int i = 0;
         for (Member member : memberList) {
-            // more than one usage
-            if (member == null) {
+            // member can be null when iterating over high cardinality elements.
+            // In this case, no setContext should be called.
+            if (member != null) {
+                setContext(member);
+            } else {
                 if (getLogger().isDebugEnabled()) {
                     getLogger().debug(
                         "RolapEvaluator.setContext: member == null "
                          + " , count=" + i);
                 }
                 assert false;
-            } else {
-                setContext(member);
             }
             i++;
         }
     }
 
-    public final void setContext(Member[] members) {
-        for (int i = 0; i < members.length; i++) {
-            final Member member = members[i];
-
-            // more than one usage
-            if (member == null) {
-                if (getLogger().isDebugEnabled()) {
-                    getLogger().debug(
-                        "RolapEvaluator.setContext: member == null "
-                         + " , count=" + i);
-                }
-                assert false;
-                continue;
-            }
-
-            setContext(member);
-        }
-    }
-
     public final RolapMember getContext(Dimension dimension) {
-        return currentMembers[dimension.getOrdinal(root.cube)];
+        return (RolapMember) 
+                currentMembers[dimension.getOrdinal(root.cube)];
     }
 
     public final Object evaluateCurrent() {
@@ -811,7 +794,8 @@
     final void addCalcMember(Member member) {
         assert member != null;
         assert member.isCalculated();
-        calcMembers[calcMemberCount++] = member;
+        calcMembers.add(member);
+        calcMemberCount = calcMembers.size();
     }
 
     private Member peekCalcMember() {
@@ -820,14 +804,14 @@
             return null;
 
         case 1:
-            return calcMembers[0];
+            return calcMembers.get(0);
 
         default:
             // Find member with the highest solve order.
-            Member maxSolveMember = calcMembers[0];
+            Member maxSolveMember = calcMembers.get(0);
             int maxSolve = maxSolveMember.getSolveOrder();
             for (int i = 1; i < calcMemberCount; i++) {
-                Member member = calcMembers[i];
+                Member member = calcMembers.get(i);
                 int solve = member.getSolveOrder();
                 if (solve >= maxSolve) {
                     // If solve orders tie, the dimension with the lower
@@ -847,12 +831,12 @@
 
     private void removeCalcMember(Member previous) {
         for (int i = 0; i < calcMemberCount; i++) {
-            final Member calcMember = calcMembers[i];
+            final Member calcMember = calcMembers.get(i);
             if (calcMember == previous) {
                 // overwrite this member with the end member
                 --calcMemberCount;
-                calcMembers[i] = calcMembers[calcMemberCount];
-                calcMembers[calcMemberCount] = null; // to allow gc
+                calcMembers.set(i, calcMembers.get(calcMemberCount));
+                calcMembers.remove(calcMemberCount); // to allow gc
             }
         }
     }
Index: src/main/mondrian/rolap/DescendantsConstraint.java
===================================================================
--- src/main/mondrian/rolap/DescendantsConstraint.java	
+++ src/main/mondrian/rolap/DescendantsConstraint.java	
@@ -13,6 +13,7 @@
 import java.util.Collections;
 
 import mondrian.olap.Evaluator;
+import mondrian.olap.Member;
 import mondrian.rolap.sql.TupleConstraint;
 import mondrian.rolap.sql.MemberChildrenConstraint;
 import mondrian.rolap.sql.SqlQuery;
@@ -27,28 +28,25 @@
  * @version $Id: //open/mondrian/src/main/mondrian/rolap/DescendantsConstraint.java#9 $
  */
 class DescendantsConstraint implements TupleConstraint {
-    List<RolapMember> parentMembers;
+    List<? extends Member> parentMembers;
     MemberChildrenConstraint mcc;
 
     /**
      * Creates a DescendantsConstraint.
      *
      * @param parentMembers list of parents all from the same level
-     * @param mcc the constraint that would return the children for each single parent
+     * @param mcc the constraint that would return the children for 
+     * each single parent
      */
-    public DescendantsConstraint(
-        List<RolapMember> parentMembers,
-        MemberChildrenConstraint mcc)
-    {
+    public DescendantsConstraint(final List<? extends Member> parentMembers,
+            final MemberChildrenConstraint mcc) {
         this.parentMembers = parentMembers;
         this.mcc = mcc;
     }
 
-    public void addConstraint(
-        SqlQuery sqlQuery,
+    public void addConstraint(SqlQuery sqlQuery,
         Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap)
-    {
+        Map<String, RolapStar.Table> relationNamesToStarTableMap) {
         if (levelToColumnMap == null) {
             levelToColumnMap = Collections.emptyMap();
         }
@@ -57,14 +55,14 @@
             null, parentMembers);
     }
 
-    public void addLevelConstraint(
-        SqlQuery sqlQuery, AggStar aggStar,
-        RolapLevel level, Map<RolapLevel, RolapStar.Column> levelToColumnMap)
-    {
+    public void addLevelConstraint(final SqlQuery sqlQuery, 
+            final AggStar aggStar, final RolapLevel level, 
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap) {
         mcc.addLevelConstraint(sqlQuery, aggStar, level, levelToColumnMap);
     }
 
-    public MemberChildrenConstraint getMemberChildrenConstraint(RolapMember parent) {
+    public MemberChildrenConstraint getMemberChildrenConstraint(
+            final RolapMember parent) {
         return mcc;
     }
 
Index: src/main/mondrian/rolap/NoCacheMemberReader.java
===================================================================
--- src/main/mondrian/rolap/NoCacheMemberReader.java	
+++ src/main/mondrian/rolap/NoCacheMemberReader.java	
@@ -0,0 +1,392 @@
+/*
+// $Id: //open/mondrian/src/main/mondrian/rolap/NoCacheMemberReader.java#41 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2001-2002 Kana Software, Inc.
+// Copyright (C) 2004-2005 TONBELLER AG
+// Copyright (C) 2007-2008 StrateBI
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+//
+*/
+
+package mondrian.rolap;
+import mondrian.olap.Util;
+import mondrian.olap.Id;
+import mondrian.olap.Member;
+import mondrian.rolap.TupleReader.MemberBuilder;
+import mondrian.rolap.cache.SmartCache;
+import mondrian.rolap.cache.SoftSmartCache;
+import mondrian.rolap.sql.MemberChildrenConstraint;
+import mondrian.rolap.sql.TupleConstraint;
+
+import mondrian.spi.DataSourceChangeListener;
+
+import java.util.*;
+import org.apache.log4j.Logger;
+
+/**
+ * <code>NoCacheMemberReader</code> implements {@link MemberReader} but
+ * without doing any kind of caching and avoiding to read all members.
+ *
+ * @author jlopez, lcanals 
+ * @since 06 October, 2007
+ * @version $Id: //open/mondrian/src/main/mondrian/rolap/NoCacheMemberReader.java#41 $
+ */
+public class NoCacheMemberReader implements MemberReader, MemberCache {
+    private static final Logger LOGGER = 
+            Logger.getLogger(NoCacheMemberReader.class);
+
+    private final SqlConstraintFactory sqlConstraintFactory =
+            SqlConstraintFactory.instance();
+
+    private final MemberReader source;
+
+
+    NoCacheMemberReader(MemberReader source) {
+        this.source = source;
+        if (!source.setCache(this)) {
+            throw Util.newInternal(
+                    "MemberSource (" + source + ", " + source.getClass() +
+                    ") does not support cache-writeback");
+        }
+    }
+
+    // implement MemberReader
+    public RolapHierarchy getHierarchy() {
+        return source.getHierarchy();
+    }
+
+    // implement MemberCache
+    public boolean setCache(MemberCache cache) {
+        return false;
+    }
+
+    // implement MemberCache
+    public Object makeKey(final RolapMember parent, final Object key) {
+        LOGGER.debug("Entering makeKey");
+        return new MemberKey(parent, key);
+    }
+
+    public synchronized RolapMember getMember(final Object key) {
+        return getMember(key, true);
+    }
+
+    public RolapMember getMember(final Object key, 
+            final boolean mustCheckCacheStatus) {
+        LOGGER.debug("Returning null member: no cache");
+        return null;
+    }
+
+
+    // implement MemberCache
+    public Object putMember(final Object key, final RolapMember value) {
+        LOGGER.debug("putMember void for no caching");
+        return value;
+    }
+
+    // implement MemberReader
+    public List<? extends Member> getMembers() {
+        System.out.println("NoCache getMembers");
+        List<Member> v = new ArrayList<Member>();
+        RolapLevel[] levels = (RolapLevel[]) getHierarchy().getLevels();
+        // todo: optimize by walking to children for members we know about
+        for (RolapLevel level : levels) {
+            List<? extends Member> membersInLevel = getMembersInLevel(
+                    level, 0, Integer.MAX_VALUE);
+            v.addAll(membersInLevel);
+        }
+        return v;
+    }
+
+    public List<? extends Member> getRootMembers() {
+        LOGGER.debug("Getting root members");
+        return source.getRootMembers();
+    }
+
+
+    public List<? extends Member> getMembersInLevel(
+                final RolapLevel level, final int startOrdinal,
+                final int endOrdinal) {
+        TupleConstraint constraint =
+                sqlConstraintFactory.getLevelMembersConstraint(null);
+        return getMembersInLevel(level, startOrdinal, endOrdinal, constraint);
+    }
+
+    public List<? extends Member> getMembersInLevel(
+            final RolapLevel level, final int startOrdinal, 
+            final int endOrdinal, final TupleConstraint constraint) {
+        LOGGER.debug("Entering getMembersInLevel");
+        return source.getMembersInLevel(
+                level, startOrdinal, endOrdinal, constraint);
+    }
+
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children) {
+        MemberChildrenConstraint constraint =
+                sqlConstraintFactory.getMemberChildrenConstraint(null);
+        getMemberChildren(parentMember, children, constraint);
+    }
+
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
+        List<? extends Member> parentMembers = new ArrayList<Member>();
+        ((List) parentMembers).add(parentMember);
+        getMemberChildren(parentMembers, children, constraint);
+    }
+
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children) {
+        MemberChildrenConstraint constraint =
+                sqlConstraintFactory.getMemberChildrenConstraint(null);
+        getMemberChildren(parentMembers, children, constraint);
+    }
+
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+                final List<? extends Member> children,
+                final MemberChildrenConstraint constraint) {
+        assert(constraint != null);
+        LOGGER.debug("Entering getMemberChildren");
+        source.getMemberChildren(parentMembers, children, constraint);
+    }
+
+    public RolapMember lookupMember(final List<Id.Segment> uniqueNameParts,
+                final boolean failIfNotFound) {
+        return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound);
+    }
+
+    public List<RolapMember> getChildrenFromCache(final RolapMember member,
+                final MemberChildrenConstraint constraint) {
+        return null;
+    }
+
+    public List getLevelMembersFromCache(final RolapLevel level,
+                final TupleConstraint constraint) {
+        return null;
+    }
+
+    public void putChildren(final RolapMember member,
+            final MemberChildrenConstraint constraint,
+            final List<? extends Member> children) {
+    }
+
+    public RolapMember getLeadMember(RolapMember member, int n) {
+        if (n == 0 || member.isNull()) {
+            return member;
+        } else {
+            SiblingIterator iter = new SiblingIterator(this, member);
+            if (n > 0) {
+                RolapMember sibling = null;
+                while (n-- > 0) {
+                    if (!iter.hasNext()) {
+                        return (RolapMember) member.getHierarchy()
+                                .getNullMember();
+                    }
+                    sibling = iter.nextMember();
+                }
+                return sibling;
+            } else {
+                n = -n;
+                RolapMember sibling = null;
+                while (n-- > 0) {
+                    if (!iter.hasPrevious()) {
+                        return (RolapMember) member.getHierarchy()
+                                .getNullMember();
+                    }
+                    sibling = iter.previousMember();
+                }
+                return sibling;
+            }
+        }
+    }
+
+    public void getMemberRange(final RolapLevel level,
+            final RolapMember startMember, final RolapMember endMember,
+            final List<? extends Member> list) {
+        Util.assertPrecondition(startMember != null, "startMember != null");
+        Util.assertPrecondition(endMember != null, "endMember != null");
+        Util.assertPrecondition(startMember.getLevel() == endMember.getLevel(),
+                "startMember.getLevel() == endMember.getLevel()");
+
+        if (compare(startMember, endMember, false) > 0) {
+            return;
+        }
+        ((List) list).add(startMember);
+        if (startMember == endMember) {
+            return;
+        }
+        SiblingIterator siblings = new SiblingIterator(this, startMember);
+        while (siblings.hasNext()) {
+            final RolapMember member = siblings.nextMember();
+            ((List) list).add(member);
+            if (member == endMember) {
+                return;
+            }
+        }
+        throw Util.newInternal("sibling iterator did not hit end point, start="
+                + startMember
+                + ", end="
+                + endMember);
+    }
+
+    public int getMemberCount() {
+        return source.getMemberCount();
+    }
+
+    public int compare(final RolapMember m1, final RolapMember m2,
+                       final boolean siblingsAreEqual) {
+        if (m1 == m2) {
+            return 0;
+        }
+        if (m1.getParentMember() == m2.getParentMember()) {
+            // including case where both parents are null
+            if (siblingsAreEqual) {
+                return 0;
+            } else if (m1.getParentMember() == null) {
+                // at this point we know that both parent members are null.
+                int pos1 = -1, pos2 = -1;
+                List siblingList = getRootMembers();
+                for (int i = 0, n = siblingList.size(); i < n; i++) {
+                    RolapMember child = (RolapMember) siblingList.get(i);
+                    if (child == m1) {
+                        pos1 = i;
+                    }
+                    if (child == m2) {
+                        pos2 = i;
+                    }
+                }
+                if (pos1 == -1) {
+                    throw Util.newInternal(m1 + " not found among siblings");
+                }
+                if (pos2 == -1) {
+                    throw Util.newInternal(m2 + " not found among siblings");
+                }
+                Util.assertTrue(pos1 != pos2);
+                return pos1 < pos2 ? -1 : 1;
+            } else {
+                List<RolapMember> children = new ArrayList<RolapMember>();
+                getMemberChildren(m1.getParentMember(), children);
+                int pos1 = -1, pos2 = -1;
+                for (int i = 0, n = children.size(); i < n; i++) {
+                    RolapMember child = children.get(i);
+                    if (child == m1) {
+                        pos1 = i;
+                    }
+                    if (child == m2) {
+                        pos2 = i;
+                    }
+                }
+                if (pos1 == -1) {
+                    throw Util.newInternal(m1 + " not found among siblings");
+                }
+                if (pos2 == -1) {
+                    throw Util.newInternal(m2 + " not found among siblings");
+                }
+                Util.assertTrue(pos1 != pos2);
+                return pos1 < pos2 ? -1 : 1;
+            }
+        }
+        int levelDepth1 = m1.getLevel().getDepth();
+        int levelDepth2 = m2.getLevel().getDepth();
+        if (levelDepth1 < levelDepth2) {
+            final int c = compare(m1, m2.getParentMember(), false);
+            return (c == 0) ? -1 : c;
+
+        } else if (levelDepth1 > levelDepth2) {
+            final int c = compare(m1.getParentMember(), m2, false);
+            return (c == 0) ? 1 : c;
+
+        } else {
+            return compare(m1.getParentMember(), m2.getParentMember(), false);
+        }
+    }
+
+    /**
+     * <code>SiblingIterator</code> helps traverse a hierarchy of members, by
+     * remembering the position at each level. Each SiblingIterator has a
+     * parent, to which it defers when the last child of the current member is
+     * reached.
+     */
+    class SiblingIterator {
+        private final MemberReader reader;
+        private final SiblingIterator parentIterator;
+        private List<? extends Member> siblings;
+        private int position;
+
+        SiblingIterator(MemberReader reader, RolapMember member) {
+            this.reader = reader;
+            RolapMember parent = member.getParentMember();
+            List<? extends Member> siblingList;
+            if (parent == null) {
+                siblingList = reader.getRootMembers();
+                this.parentIterator = null;
+            } else {
+                siblingList = new ArrayList<RolapMember>();
+                reader.getMemberChildren(parent, siblingList);
+                this.parentIterator = new SiblingIterator(reader, parent);
+            }
+            this.siblings = siblingList;
+            this.position = -1;
+            for (int i = 0; i < this.siblings.size(); i++) {
+                if (siblings.get(i) == member) {
+                    this.position = i;
+                    break;
+                }
+            }
+            if (this.position == -1) {
+                throw Util.newInternal(
+                    "member " + member + " not found among its siblings");
+            }
+        }
+        boolean hasNext() {
+            return (this.position < this.siblings.size() - 1) ||
+                (parentIterator != null) &&
+                parentIterator.hasNext();
+        }
+        Object next() {
+            return nextMember();
+        }
+        RolapMember nextMember() {
+            if (++this.position >= this.siblings.size()) {
+                if (parentIterator == null) {
+                    throw Util.newInternal("there is no next member");
+                }
+                RolapMember parent = parentIterator.nextMember();
+                List<RolapMember> siblingList = new ArrayList<RolapMember>();
+                reader.getMemberChildren(parent, siblingList);
+                this.siblings = siblingList;
+                this.position = 0;
+            }
+            return (RolapMember) this.siblings.get(this.position);
+        }
+        boolean hasPrevious() {
+            return (this.position > 0) ||
+                (parentIterator != null) &&
+                parentIterator.hasPrevious();
+        }
+        Object previous() {
+            return previousMember();
+        }
+        RolapMember previousMember() {
+            if (--this.position < 0) {
+                if (parentIterator == null) {
+                    throw Util.newInternal("there is no next member");
+                }
+                RolapMember parent = parentIterator.previousMember();
+                List<RolapMember> siblingList = new ArrayList<RolapMember>();
+                reader.getMemberChildren(parent, siblingList);
+                this.siblings = siblingList;
+                this.position = this.siblings.size() - 1;
+            }
+            return (RolapMember) this.siblings.get(this.position);
+        }
+    }
+
+    public MemberBuilder getMemberBuilder() {
+        return source.getMemberBuilder();
+    }
+}
+
+// End NoCacheMemberReader.java
Index: src/main/mondrian/rolap/RolapHierarchy.java
===================================================================
--- src/main/mondrian/rolap/RolapHierarchy.java	
+++ src/main/mondrian/rolap/RolapHierarchy.java	
@@ -370,15 +370,12 @@
         // use lazy initialization to get around bootstrap issues
         if (defaultMember == null) {
             List rootMembers = memberReader.getRootMembers();
-            if (rootMembers.size() == 0) {
-                throw MondrianResource.instance().InvalidHierarchyCondition.ex(this.getUniqueName());
-/*
-                throw Util.newError(
-                    "cannot get default member: hierarchy " + getUniqueName() +
-                    " has no root members");
-*/
+            try {
+                defaultMember = (RolapMember) rootMembers.get(0);
+            } catch(Exception e) {
+                throw MondrianResource.instance().InvalidHierarchyCondition
+                        .ex(this.getUniqueName());
             }
-            defaultMember = (RolapMember) rootMembers.get(0);
         }
         return defaultMember;
     }
@@ -779,7 +776,8 @@
             dimension.getSchema(),
             dimension.getName() + "$Closure",
             ((RolapDimension)dimension).getNextOrdinal(),
-            DimensionType.StandardDimension);
+            DimensionType.StandardDimension,
+            dimension.isHighCardinality());
 
         // Create a peer hierarchy.
         RolapHierarchy peerHier = peerDimension.newHierarchy(subName, true);
Index: src/main/mondrian/rolap/TupleReader.java
===================================================================
--- src/main/mondrian/rolap/TupleReader.java	
+++ src/main/mondrian/rolap/TupleReader.java	
@@ -15,6 +15,8 @@
 
 import javax.sql.DataSource;
 
+import mondrian.olap.Member;
+
 /**
  * Describes the public methods of {@link mondrian.rolap.SqlTupleReader}.
  *
@@ -57,14 +59,14 @@
      */
     void addLevelMembers(
         RolapLevel level, MemberBuilder memberBuilder,
-        RolapMember[] srcMembers);
+        List<RolapMember> srcMembers);
 
     /**
      * Performs the read.
      *
-     * @return a list of RolapMember[]
+     * @return a list of List<RolapMember>
      */
-    List<RolapMember[]> readTuples(
+    List<List<? extends Member>> readTuples(
         DataSource dataSource,
         List<List<RolapMember>> partialResult,
         List<List<RolapMember>> newPartialResult);
Index: src/main/mondrian/rolap/sql/MemberChildrenConstraint.java
===================================================================
--- src/main/mondrian/rolap/sql/MemberChildrenConstraint.java	
+++ src/main/mondrian/rolap/sql/MemberChildrenConstraint.java	
@@ -12,6 +12,7 @@
 import java.util.List;
 import java.util.Map;
 
+import mondrian.olap.Member;
 import mondrian.rolap.RolapLevel;
 import mondrian.rolap.RolapMember;
 import mondrian.rolap.RolapStar;
@@ -54,14 +55,15 @@
      * @param levelToColumnMap where to find each level's key
      * @param relationNamesToStarTableMap table alias map
      * @param aggStar Aggregate table, or null if query is against fact table
-     * @param parents list of parent members that restrict the returned children.
+     * @param parents list of parent members that restrict the returned 
+     * children.
      */
     public void addMemberConstraint(
         SqlQuery sqlQuery,
         Map<RolapLevel, RolapStar.Column> levelToColumnMap,
         Map<String, RolapStar.Table> relationNamesToStarTableMap,        
         AggStar aggStar,
-        List<RolapMember> parents);
+        List<? extends Member> parents);
 
     /**
      * Will be called once for the level that contains the
Index: src/main/mondrian/rolap/FastBatchingCellReader.java
===================================================================
--- src/main/mondrian/rolap/FastBatchingCellReader.java	
+++ src/main/mondrian/rolap/FastBatchingCellReader.java	
@@ -87,7 +87,7 @@
     }
 
     public Object get(RolapEvaluator evaluator) {
-        final Member[] currentMembers = evaluator.getMembers();
+        final List<Member> currentMembers = evaluator.getMembers();
         final CellRequest request =
             RolapAggregationManager.makeRequest(currentMembers);
         if (request == null || request.isUnsatisfiable()) {
@@ -95,6 +95,7 @@
         }
         // Try to retrieve a cell and simultaneously pin the segment which
         // contains it.
+        
         final Object o = aggMgr.getCellFromCache(request, pinnedSegments);
 
         if (o == Boolean.TRUE) {
@@ -108,6 +109,7 @@
         // if there is no such cell, record that we need to fetch it, and
         // return 'error'
         recordCellRequest(request);
+
         return RolapUtil.valueNotReadyException;
     }
 
@@ -216,6 +218,8 @@
         if (!isDirty()) {
             return false;
         }
+        final ThreadGroup threadGroup = new ThreadGroup(Aggregation.getParallelThreadGroups(), "Aggregation Threads");
+        int numThreads = 0;
 
         // Sort the batches into deterministic order.
         List<Batch> batchList = new ArrayList<Batch>(batches.values());
@@ -224,15 +228,27 @@
             LOGGER.debug("Using grouping sets");
             List<CompositeBatch> groupedBatches = groupBatches(batchList);
             for (CompositeBatch batch : groupedBatches) {
-                loadAggregation(query, batch);
+                numThreads++;
+                loadAggregation(query, batch, threadGroup);
             }
         } else {
             // Load batches in turn.
             for (Batch batch : batchList) {
-                loadAggregation(query, batch);
+                numThreads++;
+                loadAggregation(query, batch, threadGroup);
             }
         }
 
+        final Thread runningThreads[] = new Thread[numThreads];
+        threadGroup.enumerate(runningThreads);
+        try {
+            for(int i=0; i<numThreads; i++) {
+                if(runningThreads[i]!=null) runningThreads[i].join();
+            }
+        } catch(InterruptedException ie) {
+            throw new RuntimeException(ie);
+        }
+
         batches.clear();
         dirty = false;
 
@@ -244,11 +260,12 @@
         return true;
     }
 
-    private void loadAggregation(Query query, Loadable batch) {
+    private void loadAggregation(final Query query, final Loadable batch, 
+            final ThreadGroup threadGroup) {
         if (query != null) {
             query.checkCancelOrTimeout();
         }
-        batch.loadAggregation();
+        batch.loadAggregation(threadGroup);
     }
 
     List<CompositeBatch> groupBatches(List<Batch> batchList) {
@@ -371,13 +388,13 @@
             summaryBatches.addAll(summaryBatch.summaryBatches);
         }
 
-        public void loadAggregation() {
+        public void loadAggregation(final ThreadGroup threadGroup) {
             GroupingSetsCollector batchCollector =
                 new GroupingSetsCollector(true);
-            this.detailedBatch.loadAggregation(batchCollector);
+            this.detailedBatch.loadAggregation(batchCollector, threadGroup);
 
             for (Batch batch : summaryBatches) {
-                batch.loadAggregation(batchCollector);
+                batch.loadAggregation(batchCollector, threadGroup);
             }
 
             getSegmentLoader().load(
@@ -398,7 +415,7 @@
      * aggregations into the cache.
      */
     interface Loadable {
-        void loadAggregation();
+        void loadAggregation(final ThreadGroup threadGroup);
     }
 
     class Batch implements Loadable {
@@ -451,15 +468,15 @@
             return measure.getStar();
         }
 
-        public final void loadAggregation() {
+        public final void loadAggregation(final ThreadGroup threadGroup) {
             GroupingSetsCollector collectorWithGroupingSetsTurnedOff =
                 new GroupingSetsCollector(false);
-            loadAggregation(collectorWithGroupingSetsTurnedOff);
+            loadAggregation(collectorWithGroupingSetsTurnedOff, threadGroup);
         }
 
         final void loadAggregation(
-            GroupingSetsCollector groupingSetsCollector)
-        {
+                final GroupingSetsCollector groupingSetsCollector,
+                final ThreadGroup threadGroup) {
             if (generateAggregateSql) {
                 generateAggregateSql();
             }
@@ -508,7 +525,8 @@
                     aggmgr.loadAggregation(
                         measures, columns,
                         constrainedColumnsBitKey,
-                        predicates, pinnedSegments, groupingSetsCollector);
+                        predicates, pinnedSegments, groupingSetsCollector,
+                        threadGroup);
                     measuresList.remove(measure);
                 }
             }
@@ -520,7 +538,8 @@
                 aggmgr.loadAggregation(
                     measures, columns,
                     constrainedColumnsBitKey,
-                    predicates, pinnedSegments, groupingSetsCollector);
+                    predicates, pinnedSegments, groupingSetsCollector, 
+                    threadGroup);
             }
 
             if (BATCH_LOGGER.isDebugEnabled()) {
@@ -567,7 +586,7 @@
                     measures, columns,
                     constrainedColumnsBitKey,
                     predicates,
-                    pinnedSegments, groupingSetsCollector);
+                    pinnedSegments, groupingSetsCollector, null);
             }
         }
 
@@ -604,7 +623,8 @@
             final RolapCube cube = FastBatchingCellReader.this.cube;
             if (cube == null || cube.isVirtual()) {
                 final StringBuilder buf = new StringBuilder(64);
-                buf.append("AggGen: Sorry, can not create SQL for virtual Cube \"");
+                buf.append("AggGen: Sorry,can not create SQL for "
+                        + "virtual Cube \"");
                 buf.append(cube.getName());
                 buf.append("\", operation not currently supported");
                 BATCH_LOGGER.error(buf.toString());
Index: src/main/mondrian/rolap/RolapDimension.java
===================================================================
--- src/main/mondrian/rolap/RolapDimension.java	
+++ src/main/mondrian/rolap/RolapDimension.java	
@@ -74,13 +74,15 @@
     RolapDimension(Schema schema,
                    String name,
                    int globalOrdinal,
-                   DimensionType dimensionType) {
+                   DimensionType dimensionType,
+                   final boolean highCardinality) {
         super(
                 name,
                 globalOrdinal,
                 // todo: recognition of a time dimension should be improved
                 // allow multiple time dimensions
-                dimensionType);
+                dimensionType,
+                highCardinality);
 
         this.schema = schema;
         Util.assertTrue((globalOrdinal == 0) == name.equals(MEASURES_NAME));
@@ -99,7 +101,8 @@
         this(schema,
              xmlDimension.name,
              chooseOrdinal(cube, xmlCubeDimension),
-             xmlDimension.getDimensionType());
+             xmlDimension.getDimensionType(),
+             xmlDimension.highCardinality);
 
         Util.assertPrecondition(schema != null);
 
@@ -240,10 +243,11 @@
             String name,
             MondrianDef.CubeDimension xmlCubeDimension) {
         RolapDimension dimension = new RolapDimension(
-            schema,
+            this.schema,
             name,
-            getNextOrdinal(),
-            dimensionType);
+            this.getNextOrdinal(),
+            this.dimensionType,
+            this.highCardinality);
         dimension.hierarchies = (Hierarchy[]) hierarchies.clone();
         for (int i = 0; i < hierarchies.length; i++) {
             final RolapHierarchy hierarchy = (RolapHierarchy) hierarchies[i];
Index: src/main/mondrian/rolap/SqlConstraintUtils.java
===================================================================
--- src/main/mondrian/rolap/SqlConstraintUtils.java	
+++ src/main/mondrian/rolap/SqlConstraintUtils.java	
@@ -51,7 +51,7 @@
         Evaluator evaluator,
         boolean restrictMemberTypes) {
 
-        Member[] members = evaluator.getMembers();
+        List<Member> members = evaluator.getMembers();
         if (restrictMemberTypes) {
             if (containsCalculatedMember(members)) {
                 throw Util.newInternal(
@@ -136,30 +136,31 @@
      * @param members Array of members
      * @return Array of members with default members removed
      */
-    private static Member[] removeDefaultMembers(Member[] members) {
+    private static List<Member> removeDefaultMembers(List<Member> members) {
         List<Member> result = new ArrayList<Member>();
-        result.add(members[0]); // add the measure
-        for (int i = 1; i < members.length; i++) {
-            Member m = members[i];
+        result.add(members.get(0)); // add the measure
+        for (int i = 1; i < members.size(); i++) {
+            Member m = members.get(i);
             if (m.getHierarchy().getDefaultMember().equals(m)) {
                 continue;
             }
             result.add(m);
         }
-        return result.toArray(new Member[result.size()]);
+        return result;
     }
 
-    private static Member[] removeCalculatedMembers(Member[] members) {
+    private static List<Member> removeCalculatedMembers(List<Member> members) {
+if(members.get(0).getDimension().isHighCardinality()) System.out.println("SqlConstraintUtils: 153 ...Ouch...");
         List<Member> result = new ArrayList<Member>();
         for (Member member : members) {
             if (!member.isCalculated()) {
                 result.add(member);
             }
         }
-        return result.toArray(new Member[result.size()]);
+        return result;
     }
 
-    public static boolean containsCalculatedMember(Member[] members) {
+    public static boolean containsCalculatedMember(List<Member> members) {
         for (Member member : members) {
             if (member.isCalculated()) {
                 return true;
@@ -257,7 +258,7 @@
         Map<RolapLevel, RolapStar.Column> levelToColumnMap,
         Map<String, RolapStar.Table> relationNamesToStarTableMap,
         AggStar aggStar,
-        List<RolapMember> members,
+        List<? extends Member> members,
         boolean restrictMemberTypes,
         boolean crossJoin)
     {
@@ -272,7 +273,7 @@
 
         // Find out the first(lowest) unqiue parent level.
         // Only need to compare members up to that level.
-        RolapMember member = members.get(0);
+        RolapMember member = (RolapMember) members.get(0);
         RolapLevel memberLevel = member.getLevel();
         RolapMember firstUniqueParent = member;
         RolapLevel firstUniqueParentLevel = null;
@@ -292,25 +293,15 @@
         // are multiple values for the parent members, then we can't
         // use single value IN clauses
         if (crossJoin &&
-            !memberLevel.isUnique() && !membersAreCrossProduct(members)) {
+                !memberLevel.isUnique() && !membersAreCrossProduct(members)) {
             assert (member.getParentMember() != null);
-            condition +=
-                constrainMultiLevelMembers(
-                    sqlQuery,
-                    levelToColumnMap,
-                    relationNamesToStarTableMap,
-                    members,
-                    firstUniqueParentLevel,
-                    restrictMemberTypes);
+            condition += constrainMultiLevelMembers(sqlQuery,
+                    levelToColumnMap, relationNamesToStarTableMap,
+                    members, firstUniqueParentLevel, restrictMemberTypes);
         } else {
-            condition +=
-                generateSingleValueInExpr(
-                    sqlQuery, 
-                    levelToColumnMap,
-                    relationNamesToStarTableMap,
-                    members,
-                    firstUniqueParentLevel,
-                    restrictMemberTypes);                  
+            condition += generateSingleValueInExpr(sqlQuery, 
+                    levelToColumnMap, relationNamesToStarTableMap,
+                    members, firstUniqueParentLevel, restrictMemberTypes);                  
         }
 
         if (condition.length() > 1) {
@@ -322,32 +313,32 @@
     }
 
     private static StarColumnPredicate getColumnPredicates(
-        RolapStar.Column column,
-        Collection<RolapMember> members)
-    {
+            final RolapStar.Column column, 
+            final Collection<? extends Member> members) {
         switch (members.size()) {
         case 0:
             return new LiteralStarPredicate(column, false);
         case 1:
-            return new MemberColumnPredicate(column, members.iterator().next());
+            return new MemberColumnPredicate(column, (RolapMember)
+                    members.iterator().next());
         default:
             List<StarColumnPredicate> predicateList =
                 new ArrayList<StarColumnPredicate>();
-            for (RolapMember member : members) {
-                predicateList.add(new MemberColumnPredicate(column, member));
+            for (Member member : members) {
+                predicateList.add(new MemberColumnPredicate(column, 
+                        (RolapMember) member));
             }
             return new ListColumnPredicate(column, predicateList);
         }
     }
 
-    private static LinkedHashSet<RolapMember> getUniqueParentMembers(
-        Collection<RolapMember> members)
-    {
-        LinkedHashSet<RolapMember> set = new LinkedHashSet<RolapMember>();
-        for (RolapMember m : members) {
+    private static Set<? extends Member> getUniqueParentMembers(
+            final Collection<? extends Member> members) {
+        final Set<? extends Member> set = new LinkedHashSet<Member>();
+        for (Member m : members) {
             m = m.getParentMember();
             if (m != null) {
-                set.add(m);
+                ((Set) set).add(m);
             }
         }
         return set;
@@ -362,18 +353,18 @@
      * @param relationNamesToStarTableMap map to disambiguate table aliases
      * @param members list of constraining members
      * @param fromLevel lowest parent level that is unique
-     * @param restrictMemberTypes defines the behavior when calculated members are present
+     * @param restrictMemberTypes defines the behavior when calculated 
+     * members are present
      * 
-     * @return a non-empty String if SQL is generated for the multi-level member list.
+     * @return a non-empty String if SQL is generated for the multi-level 
+     * member list.
      */    
     private static String constrainMultiLevelMembers(
-        SqlQuery sqlQuery,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap,        
-        List<RolapMember> members,
-        RolapLevel fromLevel,
-        boolean restrictMemberTypes)
-    {
+            final SqlQuery sqlQuery,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final Map<String, RolapStar.Table> relationNamesToStarTableMap,
+            final List<? extends Member> members, 
+            final RolapLevel fromLevel, final boolean restrictMemberTypes) {
         // Use LinkedHashMap so that keySet() is deterministic.
         Map<RolapMember, List<RolapMember>> parentChildrenMap =
             new LinkedHashMap<RolapMember, List<RolapMember>>();
@@ -381,15 +372,9 @@
 
         // First try to generate IN list for all members
         if (sqlQuery.getDialect().supportsMultiValueInExpr()) {
-            condition +=
-                generateMultiValueInExpr(
-                    sqlQuery, 
-                    levelToColumnMap,
-                    relationNamesToStarTableMap,
-                    members,
-                    fromLevel,
-                    restrictMemberTypes,
-                    parentChildrenMap);
+            condition += generateMultiValueInExpr(
+                    sqlQuery, levelToColumnMap, relationNamesToStarTableMap,
+                    members, fromLevel, restrictMemberTypes, parentChildrenMap);
             
             // The members list might contain NULL values in the member levels.
             //
@@ -403,8 +388,8 @@
             // Pick out such members to generate SQL later.
             // These members are organized in a map that maps the parant levels
             // containing NULL to all its children members in the list. e.g. the
-            // member list above becomes the following map, after SQL is generated
-            // for [USA].[CA].[San Jose] in the call above.
+            // member list above becomes the following map, after SQL is 
+            // generated for [USA].[CA].[San Jose] in the call above.
             //
             //   [null].[null]->([San Francisco], [Los Angeles])
             //   [null]->([CA].[San Diego], [CA].[Sacramento])
@@ -421,11 +406,11 @@
             //   [null].[null]->([San Francisco], [Los Angesles])
             //   [null].[CA]->([San Diego],[Sacramento])
             //
-            // The idea is to be able to "compress" the original member list into
-            // groups that can use single value IN list for part of the comparison
-            // that does not involve NULLs.
+            // The idea is to be able to "compress" the original member 
+            // list into groups that can use single value IN list for 
+            // part of the comparison that does not involve NULLs.
             //
-            for (RolapMember m : members) {            
+            for (Member m : members) {            
                 if (m.isCalculated()) {
                     if (restrictMemberTypes) {
                         throw Util.newInternal("addMemberConstraint: cannot " +
@@ -433,13 +418,13 @@
                     }
                     continue;
                 }
-                RolapMember p = m.getParentMember();
+                RolapMember p = (RolapMember) m.getParentMember();
                 List<RolapMember> childrenList = parentChildrenMap.get(p);
                 if (childrenList == null) {
                     childrenList = new ArrayList<RolapMember>();
                     parentChildrenMap.put(p, childrenList);
                 }
-                childrenList.add(m);
+                ((List) childrenList).add(m);
             }
         }
 
@@ -455,7 +440,7 @@
             firstParent = false;
         }
 
-        RolapLevel memberLevel = members.get(0).getLevel();
+        RolapLevel memberLevel = (RolapLevel) members.get(0).getLevel();
         
         // The children for each parent are turned into IN list so they
         // should not contain null.
@@ -466,7 +451,8 @@
             
             condition += "(";
             
-            // First generate ANDs for all members in the parent lineage of this parent-children group
+            // First generate ANDs for all members in the parent lineage 
+            // of this parent-children group
             boolean firstLevel = true;
             for (RolapMember gp = p; gp!= null; gp = gp.getParentMember()) {
                 if (gp.isAll()) {
@@ -481,7 +467,7 @@
                 // first parent-children group we're generating sql for
                 if (firstParent) {
                     RolapHierarchy hierarchy =
-                        (RolapHierarchy) level.getHierarchy();
+                            (RolapHierarchy) level.getHierarchy();
 
                     RolapStar.Column column = levelToColumnMap.get(level);
 
@@ -503,14 +489,10 @@
                     firstLevel = false;
                 }
 
-                condition += constrainLevel(
-                    level,
-                    levelToColumnMap,
-                    sqlQuery,
-                    getColumnValue(
-                        gp.getSqlKey(),
-                        sqlQuery.getDialect(),
-                        level.getDatatype()),
+                condition += constrainLevel(level,
+                        levelToColumnMap, sqlQuery, getColumnValue(
+                                gp.getSqlKey(), sqlQuery.getDialect(),
+                                level.getDatatype()),
                         false);
                 if (gp.getLevel() == fromLevel) {
                     // SQL is completely generated for this parent
@@ -574,12 +556,12 @@
      * @return true if the members comprise the cross product of all unique
      * member keys referenced at each level
      */
-    private static boolean membersAreCrossProduct(List<RolapMember> members)
-    {
+    private static boolean membersAreCrossProduct(
+            final List<? extends Member> members) {
         int crossProdSize = getNumUniqueMemberKeys(members);
-        for (Collection<RolapMember> parents = getUniqueParentMembers(members);
-            !parents.isEmpty(); parents = getUniqueParentMembers(parents))
-        {
+        for (Collection<? extends Member> parents 
+                    = getUniqueParentMembers(members);
+                !parents.isEmpty(); parents = getUniqueParentMembers(parents)) {
             crossProdSize *= parents.size();
         }
         return (crossProdSize == members.size());
@@ -590,11 +572,10 @@
      *
      * @return number of unique member keys in a list of members
      */
-    private static int getNumUniqueMemberKeys(List<RolapMember> members)
-    {
-        Set<Object> set = new HashSet<Object>();
-        for (RolapMember m : members) {
-            set.add(m.getKey());
+    private static int getNumUniqueMemberKeys(List<? extends Member> members) {
+        final Set set = new HashSet();
+        for (final Member m : members) {
+            set.add(((RolapMember) m).getKey());
         }
         return set.size();
     }
@@ -606,11 +587,8 @@
      *
      * @return string value corresponding to the member
      */
-    private static String getColumnValue(
-        Object key,
-        SqlQuery.Dialect dialect,
-        SqlQuery.Datatype datatype)
-    {
+    private static String getColumnValue(final Object key,
+            final SqlQuery.Dialect dialect, final SqlQuery.Datatype datatype) {
         if (key != RolapUtil.sqlNullValue) {
             return key.toString();
         } else {
@@ -631,12 +609,10 @@
      * @return generated string corresponding to the expression
      */
     public static String constrainLevel(
-        RolapLevel level,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        SqlQuery query,
-        String columnValue,
-        boolean caseSensitive)
-    {
+            final RolapLevel level,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final SqlQuery query, final String columnValue,
+            final boolean caseSensitive) {
         MondrianDef.Expression exp = level.getNameExp();
         SqlQuery.Datatype datatype;
         if (exp == null) {
@@ -689,20 +665,21 @@
      * @param relationNamesToStarTableMap map to disambiguate table aliases
      * @param members list of constraining members
      * @param fromLevel lowest parent level that is unique
-     * @param restrictMemberTypes defines the behavior when calculated members are present
+     * @param restrictMemberTypes defines the behavior when calculated 
+     * members are present
      * @param parentWithNullToChildrenMap upon return this map contains members
      *        that have Null values in its (parent) levels
-     * @return a non-empty String if multi-value IN list was generated for some members.
+     * @return a non-empty String if multi-value IN list was generated for 
+     * some members.
      */
     private static String generateMultiValueInExpr(
-        SqlQuery sqlQuery,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap,        
-        List<RolapMember> members,
-        RolapLevel fromLevel,
-        boolean restrictMemberTypes,
-        Map<RolapMember, List<RolapMember>> parentWithNullToChildrenMap)
-    {
+            final SqlQuery sqlQuery,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final Map<String, RolapStar.Table> relationNamesToStarTableMap,
+            final List<? extends Member> members,
+            final RolapLevel fromLevel, final boolean restrictMemberTypes,
+            final Map<RolapMember, List<RolapMember>> 
+                                        parentWithNullToChildrenMap) {
         final StringBuilder columnBuf = new StringBuilder();
         final StringBuilder valueBuf = new StringBuilder();
 
@@ -710,7 +687,8 @@
 
         // generate the left-hand side of the IN expression
         boolean isFirstLevelInMultiple = true;        
-        for (RolapMember m = members.get(0); m != null; m = m.getParentMember()) {
+        for (RolapMember m = (RolapMember) members.get(0); 
+                m!=null; m = (RolapMember) m.getParentMember()) {
             if (m.isAll()) {
                 continue;
             }
@@ -763,7 +741,7 @@
         valueBuf.append("(");
         boolean isFirstMember = true;
         String memberString;
-        for (RolapMember m : members) {            
+        for (Member m : members) {            
             if (m.isCalculated()) {
                 if (restrictMemberTypes) {
                     throw Util.newInternal("addMemberConstraint: cannot " +
@@ -776,8 +754,8 @@
             memberString = "(";
 
             boolean containsNull = false;
-            for (RolapMember p = m; p != null; p = p.getParentMember()) {
-                
+            for (RolapMember p = (RolapMember) m; p != null; 
+                    p = p.getParentMember()) {
                 if (p.isAll()) {
                     // Ignore the ALL level.
                     // Generate SQL condition for the next level
@@ -803,7 +781,7 @@
                     
                     // If p has children
                     if (m != p) {
-                        childrenList.add(m);
+                        ((List) childrenList).add(m);
                     }
                     
                     // Skip generating condition for this parent
@@ -828,8 +806,8 @@
             }
             
             // now check if sql string is sucessfully generated for this member
-            // If parent levels do not contain NULL then SQL must have been generated
-            //successfully.
+            // If parent levels do not contain NULL then SQL must have 
+            // been generated successfully.
             if (!containsNull) {
                 memberString += ")";
                 if (!isFirstMember) {
@@ -860,30 +838,25 @@
      * @param relationNamesToStarTableMap map to disambiguate table aliases
      * @param members list of constraining members
      * @param fromLevel lowest parent level that is unique
-     * @param restrictMemberTypes defines the behavior when calculated members are present
+     * @param restrictMemberTypes defines the behavior when calculated 
+     * members are present
      * @return a non-empty String if IN list was generated for the members.
      */
     private static String generateSingleValueInExpr(
-        SqlQuery sqlQuery,
-        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
-        Map<String, RolapStar.Table> relationNamesToStarTableMap,
-        List<RolapMember> members,
-        RolapLevel fromLevel,        
-        boolean restrictMemberTypes)
-    {
+            final SqlQuery sqlQuery,
+            final Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+            final Map<String, RolapStar.Table> relationNamesToStarTableMap,
+            final List<? extends Member> members,
+            final RolapLevel fromLevel, final boolean restrictMemberTypes) {
         int maxConstraints = 
             MondrianProperties.instance().MaxConstraints.get();
         
         String condition = "";
         boolean firstLevel = true;
-        for (Collection<RolapMember> c = members;
-            !c.isEmpty();
-            c = getUniqueParentMembers(c))
-        {
-            RolapMember m = c.iterator().next();
-            if (m.isAll()) {
-                continue;
-            }
+        for (Collection<? extends Member> c = members;
+                !c.isEmpty(); c = getUniqueParentMembers(c)) {
+            Member m = c.iterator().next();
+            if (m.isAll()) continue;
             if (m.isCalculated()) {
                 if (restrictMemberTypes) {
                     throw Util.newInternal("addMemberConstraint: cannot " +
@@ -891,11 +864,10 @@
                 }
                 continue;
             }
-            RolapLevel level = m.getLevel();
+            RolapLevel level = (RolapLevel) m.getLevel();
             RolapHierarchy hierarchy = level.getHierarchy();
 
-            String q = 
-                level.getExpressionWithAlias(
+            String q = level.getExpressionWithAlias(
                     sqlQuery, levelToColumnMap, level.getKeyExp());
             RolapStar.Column column = levelToColumnMap.get(level);
             StarColumnPredicate cc = getColumnPredicates(column, c);
@@ -912,9 +884,8 @@
             }
 
             if (cc instanceof ListColumnPredicate &&
-                ((ListColumnPredicate) cc).getPredicates().size() > 
-                maxConstraints)
-            {
+                    ((ListColumnPredicate) cc).getPredicates().size() > 
+                        maxConstraints) {
                 // Simply get them all, do not create where-clause.
                 // Below are two alternative approaches (and code). They
                 // both have problems.
Index: src/main/mondrian/rolap/HighCardSqlTupleReader.java
===================================================================
--- src/main/mondrian/rolap/HighCardSqlTupleReader.java	
+++ src/main/mondrian/rolap/HighCardSqlTupleReader.java	
@@ -0,0 +1,473 @@
+/*
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2004-2005 TONBELLER AG
+// Copyright (C) 2005-2007 Julian Hyde and others
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.rolap;
+
+import mondrian.calc.ResultStyle;
+import mondrian.olap.*;
+import mondrian.olap.fun.FunUtil;
+import mondrian.resource.MondrianResource;
+import mondrian.rolap.sql.MemberChildrenConstraint;
+import mondrian.rolap.sql.SqlQuery;
+import mondrian.rolap.sql.TupleConstraint;
+import mondrian.util.*;
+
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+import javax.sql.DataSource;
+
+/**
+ * Reads the members of a single level (level.members) or of multiple levels
+ * (crossjoin).
+ *
+ * @author luis f. canals
+ * @since Dec,2007 
+ * @version $Id: //open/mondrian/src/main/mondrian/rolap/SqlTupleReader.java#34 $
+ */
+public class HighCardSqlTupleReader implements TupleReader {
+    private ResultLoader resultLoader;
+    private boolean moreRows;
+
+    private final TupleConstraint constraint;
+    private final List<Target> targets = new ArrayList<Target>();
+    int maxRows = 0;
+
+    public HighCardSqlTupleReader(final TupleConstraint constraint) {
+        this.constraint = constraint;
+    }
+
+    public void addLevelMembers(final RolapLevel level,
+            final MemberBuilder memberBuilder, 
+            final List<RolapMember> srcMembers) {
+        targets.add(new Target(level, memberBuilder, srcMembers, constraint,
+                this));
+                
+    }
+
+    public Object getCacheKey() {
+        List<Object> key = new ArrayList<Object>();
+        key.add(constraint.getCacheKey());
+        key.add(SqlTupleReader.class);
+        for (Target target : targets) {
+            // don't include the level in the key if the target isn't
+            // processed through native sql
+            if (target.getSrcMembers() != null) {
+                key.add(target.getLevel());
+            }
+        }
+        return key;
+    }
+
+    /**
+     * @return number of targets that contain enumerated sets with calculated
+     * members
+     */
+    public int getEnumTargetCount() {
+        int enumTargetCount = 0;
+        for (Target target : targets) {
+            if (target.getSrcMembers() != null) {
+                enumTargetCount++;
+            }
+        }
+        return enumTargetCount;
+    }
+
+    protected void prepareTuples(final DataSource dataSource,
+            final List<List<RolapMember>> partialResult,
+            final List<List<RolapMember>> newPartialResult) {
+        String message = "Populating member cache with members for " + targets;
+        SqlStatement stmt = null;
+        final ResultSet resultSet;
+        boolean execQuery = (partialResult == null);
+        try {
+            if (execQuery) {
+                // we're only reading tuples from the targets that are
+                // non-enum targets
+                List<Target> partialTargets = new ArrayList<Target>();
+                for (Target target : targets) {
+                    if (target.getSrcMembers() == null) {
+                        partialTargets.add(target);
+                    }
+                }
+                String sql = makeLevelMembersSql(dataSource);
+                stmt = RolapUtil.executeQuery(dataSource, sql, maxRows,
+                        "HighCardSqlTupleReader.readTuples " + partialTargets,
+                        message, -1, -1);
+                resultSet = stmt.getResultSet();
+            } else {
+                resultSet = null;
+            }
+
+            for (Target target : targets) {
+                target.open();
+            }
+
+            // determine how many enum targets we have
+            int enumTargetCount = getEnumTargetCount();
+            int[] srcMemberIdxes = null;
+            if (enumTargetCount > 0) {
+                srcMemberIdxes = new int[enumTargetCount];
+            }
+
+            int currPartialResultIdx = 0;
+            if (execQuery) {
+                this.moreRows = resultSet.next();
+                if(this.moreRows) {
+                    ++stmt.rowCount;
+                }
+            } else {
+                this.moreRows = currPartialResultIdx < partialResult.size();
+            }
+
+            this.resultLoader = new ResultLoader(enumTargetCount,
+                    targets, stmt, resultSet, execQuery, partialResult, 
+                    newPartialResult);
+
+            // Read first and second elements if exists (or marks
+            // source as having "no more rows")
+            readNextTuple();
+            readNextTuple();
+        } catch(SQLException sqle) {
+            if(stmt!=null) stmt.handle(sqle);
+            else throw Util.newError(sqle, message);
+        }
+    }
+
+    public List<RolapMember> readMembers(final DataSource dataSource,
+            final List<List<RolapMember>> partialResult,
+            final List<List<RolapMember>> newPartialResult) {
+        prepareTuples(dataSource, partialResult, newPartialResult);
+        assert targets.size() == 1;
+        return targets.get(0).close();
+    }
+
+    public List<List<? extends Member>> readTuples(
+            final DataSource jdbcConnection, 
+            final List<List<RolapMember>> partialResult,
+            final List<List<RolapMember>> newPartialResult) {
+        prepareTuples(jdbcConnection, partialResult, newPartialResult);
+
+        // List of tuples
+        final int n = targets.size();
+        final List<RolapMember>[] lists = new List[n];
+        for (int i = 0; i < n; i++) {
+            lists[i] = targets.get(i).close();
+        }
+
+        final List<List<? extends Member>> tupleList = 
+                new TraversalList<Member>(lists);
+                        
+
+        // need to hierarchize the columns from the enumerated targets
+        // since we didn't necessarily add them in the order in which
+        // they originally appeared in the cross product
+        int enumTargetCount = getEnumTargetCount();
+        if (enumTargetCount > 0) {
+            FunUtil.hierarchize(tupleList, false);
+        }
+        return tupleList;
+    }
+
+    
+    /**
+     * Avoids loading of more results.
+     */
+    public void noMoreRows() {
+        this.moreRows = false;
+    }
+
+    /**
+     * Reads next tuple notifing all internal targets.
+     */
+    public boolean readNextTuple() {
+        if(!this.moreRows) return false;
+        else {
+            try {
+                if(this.moreRows) this.moreRows 
+                        = this.resultLoader.loadResult();
+            } catch(SQLException sqle) {
+                this.resultLoader.handle(sqle);
+                this.moreRows = false;
+            }
+            if(!this.moreRows) this.resultLoader.close();
+            return this.moreRows;
+        }
+    }
+
+    public void setMaxRows(int maxRows) { this.maxRows = maxRows; }
+    public int getMaxRows() { return maxRows; }
+
+    //
+    // Private stuff ------------------------------------------
+    //
+
+    private String makeLevelMembersSql(DataSource dataSource) {
+        // In the case of a virtual cube, if we need to join to the fact
+        // table, we do not necessarily have a single underlying fact table,
+        // as the underlying base cubes in the virtual cube may all reference
+        // different fact tables.
+        //
+        // Therefore, we need to gather the underlying fact tables by going
+        // through the list of measures referenced in the query.  And then
+        // we generate one sub-select per fact table, joining against each
+        // underlying fact table, unioning the sub-selects.
+        RolapCube cube = null;
+        boolean virtualCube = false;
+        if (constraint instanceof SqlContextConstraint) {
+            SqlContextConstraint sqlConstraint =
+                (SqlContextConstraint) constraint;
+            if (sqlConstraint.isJoinRequired()) {
+                Query query = constraint.getEvaluator().getQuery();
+                cube = (RolapCube) query.getCube();
+                virtualCube = cube.isVirtual();
+            }
+        }
+
+        if (virtualCube) {
+            String selectString = "";
+            Query query = constraint.getEvaluator().getQuery();
+            Map<RolapCube, Map<RolapLevel, RolapStar.Column>>
+                baseCubeToLevelToColumnMap =
+                    query.getBaseCubeToLevelToColumnMap();
+
+            // generate sub-selects, each one joining with one of
+            // underlying fact tables
+            int k = -1;
+            for (Map.Entry<RolapCube, Map<RolapLevel, RolapStar.Column>> entry :
+                baseCubeToLevelToColumnMap.entrySet())
+            {
+                final RolapCube baseCube = entry.getKey();
+                boolean finalSelect =
+                    (++k == baseCubeToLevelToColumnMap.size() - 1);
+                WhichSelect whichSelect =
+                    finalSelect ? WhichSelect.LAST :
+                        WhichSelect.NOT_LAST;
+                selectString +=
+                    generateSelectForLevels(
+                        dataSource,
+                        entry.getValue(),
+                        baseCube.getStar().getRelationNamesToStarTableMap(baseCube),
+                        whichSelect);
+                if (!finalSelect) {
+                    selectString += " union ";
+                }
+            }
+            return selectString;
+        } else {
+            Map<RolapLevel, RolapStar.Column> levelToColumnMap =
+                cube == null ?
+                    null :
+                    cube.getStar().getLevelToColumnMap(cube);
+
+            // Pass in the new map to make shared dimensions know about
+            // their relational aliases.
+            Map<String, RolapStar.Table> relationNamesToStarTableMap =
+                cube == null ?
+                    null :
+                    cube.getStar().getRelationNamesToStarTableMap(cube);
+
+            return generateSelectForLevels(
+                dataSource,
+                levelToColumnMap,
+                relationNamesToStarTableMap,
+                WhichSelect.ONLY);
+        }
+    }
+
+    /**
+     * Generates the SQL string corresponding to the levels referenced.
+     *
+     * @param dataSource jdbc connection that they query will execute
+     * against
+     * @param levelToColumnMap set only in the case of virtual cubes;
+     * provides the appropriate mapping for the base cube being processed
+     * @param relationNamesToStarTableMap map to disambiguate table aliases
+     * @param whichSelect Position of this select statement in a union
+     * @return SQL statement string
+     */
+    private String generateSelectForLevels(
+        DataSource dataSource,
+        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+        Map<String, RolapStar.Table> relationNamesToStarTableMap,
+        WhichSelect whichSelect) {
+
+        String s = "while generating query to retrieve members of level(s) " + targets;
+        SqlQuery sqlQuery = SqlQuery.newQuery(dataSource, s);
+
+        // add the selects for all levels to fetch
+        for (Target target : targets) {
+            // if we're going to be enumerating the values for this target,
+            // then we don't need to generate sql for it
+            if (target.getSrcMembers() == null) {
+                addLevelMemberSql(
+                    sqlQuery,
+                    target.getLevel(),
+                    levelToColumnMap,
+                    relationNamesToStarTableMap,
+                    whichSelect);
+            }
+        }
+
+        // additional constraints
+        constraint.addConstraint(
+            sqlQuery, levelToColumnMap, relationNamesToStarTableMap);
+
+        return sqlQuery.toString();
+    }
+
+    /**
+     * Generates the SQL statement to access members of <code>level</code>. For
+     * example, <blockquote>
+     * <pre>SELECT "country", "state_province", "city"
+     * FROM "customer"
+     * GROUP BY "country", "state_province", "city", "init", "bar"
+     * ORDER BY "country", "state_province", "city"</pre>
+     * </blockquote> accesses the "City" level of the "Customers"
+     * hierarchy. Note that:<ul>
+     *
+     * <li><code>"country", "state_province"</code> are the parent keys;</li>
+     *
+     * <li><code>"city"</code> is the level key;</li>
+     *
+     * <li><code>"init", "bar"</code> are member properties.</li>
+     * </ul>
+     *
+     * @param sqlQuery the query object being constructed
+     * @param level level to be added to the sql query
+     * @param levelToColumnMap set only in the case of virtual cubes;
+     * provides the appropriate mapping for the base cube being processed
+     * @param relationNamesToStarTableMap map to disambiguate table aliases
+     * @param whichSelect describes whether this select belongs to a larger
+     * select containing unions or this is a non-union select
+     */
+    private void addLevelMemberSql(
+        SqlQuery sqlQuery,
+        RolapLevel level,
+        Map<RolapLevel, RolapStar.Column> levelToColumnMap,
+        Map<String, RolapStar.Table> relationNamesToStarTableMap,
+        WhichSelect whichSelect)
+    {
+        RolapHierarchy hierarchy = level.getHierarchy();
+
+        RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels();
+        int levelDepth = level.getDepth();
+        for (int i = 0; i <= levelDepth; i++) {
+            RolapLevel level2 = levels[i];
+            if (level2.isAll()) {
+                continue;
+            }
+
+            MondrianDef.Expression keyExp = level2.getKeyExp();
+            MondrianDef.Expression ordinalExp = level2.getOrdinalExp();
+            MondrianDef.Expression captionExp = level2.getCaptionExp();
+
+            String keySql =
+                level2.getExpressionWithAlias(
+                    sqlQuery, levelToColumnMap, keyExp);
+            String ordinalSql =
+                    level2.getExpressionWithAlias(
+                        sqlQuery, levelToColumnMap, ordinalExp);
+
+            String captionSql = null;
+            if (captionExp != null) {
+                captionSql =
+                    level2.getExpressionWithAlias(
+                        sqlQuery, levelToColumnMap, captionExp);
+            }
+
+            if (levelToColumnMap != null &&
+                relationNamesToStarTableMap != null) {
+
+                RolapStar.Table targetTable =
+                    levelToColumnMap.get(level2).getTable();
+
+                hierarchy.addToFrom(
+                    sqlQuery,
+                    relationNamesToStarTableMap,
+                    targetTable);
+            } else {
+                hierarchy.addToFrom(sqlQuery, keyExp);
+
+                hierarchy.addToFrom(sqlQuery, ordinalExp);
+
+                if (captionExp != null) {
+                    hierarchy.addToFrom(sqlQuery, captionExp);
+                }
+            }
+
+            sqlQuery.addSelect(keySql);
+            sqlQuery.addGroupBy(keySql);
+
+            if (!ordinalSql.equals(keySql)) {
+                sqlQuery.addSelect(ordinalSql);
+                sqlQuery.addGroupBy(ordinalSql);
+            }
+
+            if (captionSql != null) {
+                sqlQuery.addSelect(captionSql);
+                sqlQuery.addGroupBy(captionSql);
+            }
+
+            constraint.addLevelConstraint(
+                sqlQuery, null, level2, levelToColumnMap);
+
+            // If this is a select on a virtual cube, the query will be
+            // a union, so the order by columns need to be numbers,
+            // not column name strings or expressions.
+            switch (whichSelect) {
+            case LAST:
+                sqlQuery.addOrderBy(
+                    Integer.toString(
+                        sqlQuery.getCurrentSelectListSize()),
+                        true, false, true);
+                break;
+            case ONLY:
+                sqlQuery.addOrderBy(ordinalSql, true, false, true);
+                break;
+            }
+
+            RolapProperty[] properties = level2.getProperties();
+            for (RolapProperty property : properties) {
+                String propSql =
+                    level2.getExpressionWithAlias(
+                        sqlQuery,
+                        levelToColumnMap,
+                        property.getExp());
+
+                sqlQuery.addSelect(propSql);
+                sqlQuery.addGroupBy(propSql);
+            }
+        }
+    }
+
+    /**
+     * Description of the position of a SELECT statement in a UNION. Queries
+     * on virtual cubes tend to generate unions.
+     */
+    enum WhichSelect {
+        /**
+         * Select statement does not belong to a union.
+         */
+        ONLY,
+        /**
+         * Select statement belongs to a UNION, but is not the last. Typically
+         * this occurs when querying a virtual cube.
+         */
+        NOT_LAST,
+        /**
+         * Select statement is the last in a UNION. Typically
+         * this occurs when querying a virtual cube.
+         */
+        LAST
+    }
+}
+
+// End SqlTupleReader.java
Index: src/main/mondrian/rolap/MemberSource.java
===================================================================
--- src/main/mondrian/rolap/MemberSource.java	
+++ src/main/mondrian/rolap/MemberSource.java	
@@ -16,6 +16,7 @@
 import java.util.List;
 
 import mondrian.olap.Id;
+import mondrian.olap.Member;
 
 /**
  * A <code>MemberSource</code> has the basic operations to read the members of a
@@ -73,7 +74,7 @@
      * <p>If this object {@link #setCache supports cache-writeaback}, also
      * writes these members to the cache.
      */
-    RolapMember[] getMembers();
+    List<? extends Member> getMembers();
     /**
      * Returns all members of this hierarchy which do not have a parent,
      * sorted by ordinal.
@@ -83,7 +84,7 @@
      *
      * @return {@link List} of {@link RolapMember}s
      */
-    List<RolapMember> getRootMembers();
+    List<? extends Member> getRootMembers();
 
     /**
      * Writes all children <code>parentMember</code> to <code>children</code>.
@@ -91,9 +92,7 @@
      * <p>If this object {@link #setCache supports cache-writeback}, also
      * writes these members to the cache.
      */
-    void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children);
+    void getMemberChildren(Member parentMember,List<? extends Member> children);
 
     /**
      * Returns all members which are a child of one of the members in
@@ -102,9 +101,8 @@
      * <p>If this object {@link #setCache supports cache-writeaback}, also
      * writes these members to the cache.
      */
-    void getMemberChildren(
-        List<RolapMember> parentMembers,
-        List<RolapMember> children);
+    void getMemberChildren(List<? extends Member> parentMembers,
+            List<? extends Member> children);
 
     /**
      * Returns an estimate of number of members in this hierarchy.
@@ -114,9 +112,8 @@
     /**
      * Finds a member based upon its unique name.
      */
-    RolapMember lookupMember(
-        List<Id.Segment> uniqueNameParts,
-        boolean failIfNotFound);
+    Member lookupMember(List<Id.Segment> uniqueNameParts,
+            boolean failIfNotFound);
 }
 
 // End MemberSource.java
Index: src/main/mondrian/rolap/SqlTupleReader.java
===================================================================
--- src/main/mondrian/rolap/SqlTupleReader.java	
+++ src/main/mondrian/rolap/SqlTupleReader.java	
@@ -76,19 +76,19 @@
         List<RolapMember> list;
         int levelDepth;
         boolean parentChild;
-        RolapMember[] members;
-        List<RolapMember>[] siblings;
+        List<RolapMember> members;
+        List<List<RolapMember>> siblings;
         final MemberBuilder memberBuilder;
         // if set, the rows for this target come from the array rather
         // than native sql
-        private final RolapMember[] srcMembers;
+        private final List<RolapMember> srcMembers;
         // current member within the current result set row
         // for this target
         private RolapMember currMember;
 
         public Target(
             RolapLevel level, MemberBuilder memberBuilder,
-            RolapMember[] srcMembers) {
+            List<RolapMember> srcMembers) {
             this.level = level;
             this.cache = memberBuilder.getMemberCache();
             this.memberBuilder = memberBuilder;
@@ -102,8 +102,12 @@
             parentChild = level.isParentChild();
             // members[i] is the current member of level#i, and siblings[i]
             // is the current member of level#i plus its siblings
-            members = new RolapMember[levels.length];
-            siblings = new List[levels.length + 1];
+            members = new ArrayList<RolapMember>();
+            for(int i=0; i<levels.length; i++) members.add(null);
+            siblings = new ArrayList<List<RolapMember>>();
+            for(int i=0; i<levels.length+1; i++) {
+                siblings.add(new ArrayList<RolapMember>());
+            }
         }
 
         /**
@@ -122,7 +126,8 @@
             }
         }
 
-        private int internalAddRow(ResultSet resultSet, int column) throws SQLException {
+        private int internalAddRow(ResultSet resultSet, int column) 
+                throws SQLException {
             RolapMember member = null;
             if (currMember != null) {
                 member = currMember;
@@ -162,15 +167,16 @@
                     }
                     column += childLevel.getProperties().length;
 
-                    if (member != members[i]) {
+                    if (member != members.get(i)) {
                         // Flush list we've been building.
-                        List<RolapMember> children = siblings[i + 1];
+                        List<RolapMember> children = siblings.get(i + 1);
                         if (children != null) {
                             MemberChildrenConstraint mcc =
                                 constraint.getMemberChildrenConstraint(
-                                    members[i]);
+                                    members.get(i));
                             if (mcc != null) {
-                                cache.putChildren(members[i], mcc, children);
+                                cache.putChildren(members.get(i), 
+                                        mcc, children);
                             }
                         }
                         // Start a new list, if the cache needs one. (We don't
@@ -183,27 +189,27 @@
                         List cachedChildren =
                             cache.getChildrenFromCache(member, mcc);
                         if (i < levelDepth && cachedChildren == null) {
-                            siblings[i + 1] = new ArrayList<RolapMember>();
+                            siblings.set(i + 1, new ArrayList<RolapMember>());
                         } else {
                             // don't bother building up a list
-                            siblings[i + 1] = null;
+                            siblings.set(i + 1, null);
                         }
                         // Record new current member of this level.
-                        members[i] = member;
+                        members.set(i, member);
                         // If we're building a list of siblings at this level,
                         // we haven't seen this one before, so add it.
-                        if (siblings[i] != null) {
+                        if (siblings.get(i) != null) {
                             if (value == RolapUtil.sqlNullValue) {
-                                addAsOldestSibling(siblings[i], member);
+                                addAsOldestSibling(siblings.get(i), member);
                             } else {
-                                siblings[i].add(member);
+                                ((List) siblings.get(i)).add(member);
                             }
                         }
                     }
                 }
                 currMember = member;
             }
-            list.add(member);
+            ((List) list).add(member);
             return column;
         }
 
@@ -220,9 +226,9 @@
          * @return list of members
          */
         public List<RolapMember> internalClose() {
-            for (int i = 0; i < members.length; i++) {
-                RolapMember member = members[i];
-                final List<RolapMember> children = siblings[i + 1];
+            for (int i = 0; i < members.size(); i++) {
+                RolapMember member = members.get(i);
+                final List<RolapMember> children = siblings.get(i + 1);
                 if (member != null && children != null) {
                     // If we are finding the members of a particular level, and
                     // we happen to find some of the children of an ancestor of
@@ -273,7 +279,7 @@
     public void addLevelMembers(
         RolapLevel level,
         MemberBuilder memberBuilder,
-        RolapMember[] srcMembers)
+        List<RolapMember> srcMembers)
     {
         targets.add(new Target(level, memberBuilder, srcMembers));
     }
@@ -355,6 +361,7 @@
             int currPartialResultIdx = 0;
             if (execQuery) {
                 moreRows = resultSet.next();
+
                 if (moreRows) {
                     ++stmt.rowCount;
                 }
@@ -425,6 +432,7 @@
         }
     }
 
+
     public List<RolapMember> readMembers(
         DataSource dataSource,
         List<List<RolapMember>> partialResult,
@@ -435,7 +443,7 @@
         return targets.get(0).close();
     }
 
-    public List<RolapMember[]> readTuples(
+    public List<List<? extends Member>> readTuples(
         DataSource jdbcConnection,
         List<List<RolapMember>> partialResult,
         List<List<RolapMember>> newPartialResult)
@@ -444,18 +452,19 @@
 
         // List of tuples
         int n = targets.size();
-        List<RolapMember[]> tupleList = new ArrayList<RolapMember[]>();
+        final List<List<? extends Member>> tupleList = 
+                new ArrayList<List<? extends Member>>();
         Iterator<RolapMember>[] iter = new Iterator[n];
         for (int i = 0; i < n; i++) {
             Target t = targets.get(i);
             iter[i] = t.close().iterator();
         }
         while (iter[0].hasNext()) {
-            RolapMember[] tuples = new RolapMember[n];
+            List<? extends Member> tuples = new ArrayList<RolapMember>();
             for (int i = 0; i < n; i++) {
-                tuples[i] = iter[i].next();
+                ((List) tuples).add(iter[i].next());
             }
-            tupleList.add(tuples);
+            ((List) tupleList).add(tuples);
         }
 
         // need to hierarchize the columns from the enumerated targets
@@ -512,7 +521,7 @@
 
         // loop through the list of members for the current enum target
         Target currTarget = targets.get(currTargetIdx);
-        for (int i = 0; i < currTarget.srcMembers.length; i++) {
+        for (int i = 0; i < currTarget.srcMembers.size(); i++) {
             srcMemberIdxes[currEnumTargetIdx] = i;
             // if we're not on the last enum target, recursively move
             // to the next one
@@ -540,8 +549,8 @@
                             throw Util.newError(e, message);
                         }
                     } else {
-                        RolapMember member =
-                            target.srcMembers[srcMemberIdxes[enumTargetIdx++]];
+                        RolapMember member = target.srcMembers.get(
+                                    srcMemberIdxes[enumTargetIdx++]);
                         target.list.add(member);
                     }
                 }
Index: src/main/mondrian/rolap/RolapSchema.java
===================================================================
--- src/main/mondrian/rolap/RolapSchema.java	
+++ src/main/mondrian/rolap/RolapSchema.java	
@@ -139,7 +139,8 @@
     /**
      * Maps {@link String names of sets} to {@link NamedSet named sets}.
      */
-    private final Map<String, NamedSet> mapNameToSet = new HashMap<String, NamedSet>();
+    private final Map<String, NamedSet> mapNameToSet = 
+            new HashMap<String, NamedSet>();
     /**
      * Table containing all standard MDX functions, plus user-defined functions
      * for this schema.
@@ -176,12 +177,14 @@
         this.internalConnection =
             new RolapConnection(connectInfo, this, dataSource);
 
-        this.mapSharedHierarchyNameToHierarchy = new HashMap<String, RolapHierarchy>();
+        this.mapSharedHierarchyNameToHierarchy = 
+                new HashMap<String, RolapHierarchy>();
         this.mapSharedHierarchyToReader = new HashMap<String, MemberReader>();
         this.mapNameToCube = new HashMap<String, RolapCube>();
         this.mapNameToRole = new HashMap<String, Role>();
         this.aggTableManager = new AggTableManager(this);
-        this.dataSourceChangeListener = createDataSourceChangeListener(connectInfo);
+        this.dataSourceChangeListener = createDataSourceChangeListener(
+                connectInfo);
     }
 
     /**
@@ -260,12 +263,14 @@
                 // and then some.
                 FileSystemManager fsManager = VFS.getManager();
                 if (fsManager == null) {
-                    throw Util.newError("Cannot get virtual file system manager");
+                    throw Util.newError("Cannot get virtual file "
+                            + "system manager");
                 }
 
                 // Workaround VFS bug.
                 if (catalogUrl.startsWith("file://localhost")) {
-                    catalogUrl = catalogUrl.substring("file://localhost".length());
+                    catalogUrl = catalogUrl.substring("file://localhost"
+                            .length());
                 }
                 if (catalogUrl.startsWith("file:")) {
                     catalogUrl = catalogUrl.substring("file:".length());
@@ -377,7 +382,8 @@
         // function table.
         final Map<String, UserDefinedFunction> mapNameToUdf =
             new HashMap<String, UserDefinedFunction>();
-        for (MondrianDef.UserDefinedFunction udf : xmlSchema.userDefinedFunctions) {
+        for (MondrianDef.UserDefinedFunction udf : 
+                xmlSchema.userDefinedFunctions) {
             defineFunction(mapNameToUdf, udf.name, udf.className);
         }
         final RolapSchemaFunctionTable funTable =
@@ -451,7 +457,8 @@
         if (xmlSchema.defaultRole != null) {
             Role role = lookupRole(xmlSchema.defaultRole);
             if (role == null) {
-                throw Util.newError("Role '" + xmlSchema.defaultRole + "' not found");
+                throw Util.newError("Role '" + xmlSchema.defaultRole 
+                        + "' not found");
             }
             // At this stage, the only roles in mapNameToRole are
             // RoleImpl roles so it is safe to case.
@@ -485,23 +492,27 @@
             for (MondrianDef.CubeGrant cubeGrant : schemaGrant.cubeGrants) {
                 RolapCube cube = lookupCube(cubeGrant.cube);
                 if (cube == null) {
-                    throw Util.newError("Unknown cube '" + cubeGrant.cube + "'");
+                    throw Util.newError("Unknown cube '"+cubeGrant.cube+"'");
                 }
                 role.grant(cube, getAccess(cubeGrant.access, cubeAllowed));
                 final SchemaReader schemaReader = cube.getSchemaReader(null);
-                for (MondrianDef.DimensionGrant dimensionGrant : cubeGrant.dimensionGrants) {
+                for (MondrianDef.DimensionGrant dimensionGrant 
+                        : cubeGrant.dimensionGrants) {
                     Dimension dimension = (Dimension)
                         schemaReader.lookupCompound(
-                            cube, Util.parseIdentifier(dimensionGrant.dimension), true,
+                            cube, Util.parseIdentifier(
+                                    dimensionGrant.dimension), true,
                             Category.Dimension);
                     role.grant(
                         dimension,
                         getAccess(dimensionGrant.access, dimensionAllowed));
                 }
-                for (MondrianDef.HierarchyGrant hierarchyGrant : cubeGrant.hierarchyGrants) {
+                for (MondrianDef.HierarchyGrant hierarchyGrant 
+                        : cubeGrant.hierarchyGrants) {
                     Hierarchy hierarchy = (Hierarchy)
                         schemaReader.lookupCompound(
-                            cube, Util.parseIdentifier(hierarchyGrant.hierarchy), true,
+                            cube, Util.parseIdentifier(
+                                    hierarchyGrant.hierarchy), true,
                             Category.Hierarchy);
                     final Access hierarchyAccess =
                         getAccess(hierarchyGrant.access, hierarchyAllowed);
@@ -509,28 +520,33 @@
                     if (hierarchyGrant.topLevel != null) {
                         if (hierarchyAccess != Access.CUSTOM) {
                             throw Util.newError(
-                                "You may only specify 'topLevel' if access='custom'");
+                                "You may only specify 'topLevel' if "
+                                + "access='custom'");
                         }
                         topLevel = (Level) schemaReader.lookupCompound(
-                            cube, Util.parseIdentifier(hierarchyGrant.topLevel), true,
-                            Category.Level);
+                            cube, Util.parseIdentifier(hierarchyGrant.topLevel),
+                                    true, Category.Level);
                     }
                     Level bottomLevel = null;
                     if (hierarchyGrant.bottomLevel != null) {
                         if (hierarchyAccess != Access.CUSTOM) {
                             throw Util.newError(
-                                "You may only specify 'bottomLevel' if access='custom'");
+                                "You may only specify 'bottomLevel' if "
+                                + "access='custom'");
                         }
                         bottomLevel = (Level) schemaReader.lookupCompound(
-                            cube, Util.parseIdentifier(hierarchyGrant.bottomLevel),
+                            cube, Util.parseIdentifier(hierarchyGrant.
+                                    bottomLevel),
                             true, Category.Level);
                     }
                     role.grant(
                         hierarchy, hierarchyAccess, topLevel, bottomLevel);
-                    for (MondrianDef.MemberGrant memberGrant : hierarchyGrant.memberGrants) {
+                    for (MondrianDef.MemberGrant memberGrant : 
+                            hierarchyGrant.memberGrants) {
                         if (hierarchyAccess != Access.CUSTOM) {
                             throw Util.newError(
-                                "You may only specify <MemberGrant> if <Hierarchy> has access='custom'");
+                                "You may only specify <MemberGrant> if "
+                                    + "<Hierarchy> has access='custom'");
                         }
                         Member member = schemaReader.getMemberByUniqueName(
                             Util.parseIdentifier(memberGrant.member), false);
@@ -614,36 +630,13 @@
         return cube;
     }
 
-/*
-    public Cube createCube(String xml) {
-        MondrianDef.Cube xmlDimension;
-        try {
-            final Parser xmlParser = XOMUtil.createDefaultParser();
-            final DOMWrapper def = xmlParser.parse(xml);
-            final String tagName = def.getTagName();
-            if (tagName.equals("Cube")) {
-                xmlDimension = new MondrianDef.Cube(def);
-            } else {
-                throw new XOMException("Got <" + tagName +
-                    "> when expecting <Cube>");
-            }
-        } catch (XOMException e) {
-            throw Util.newError(e, "Error while creating cube from XML [" +
-                xml + "]");
-        }
-        // Create empty XML schema, to keep the method happy. This is okay,
-        // because there are no forward-references to resolve.
-        final MondrianDef.Schema xmlSchema = new MondrianDef.Schema();
-        RolapCube cube = new RolapCube(this, xmlSchema, xmlDimension);
-        return cube;
-    }
-*/
 
     /**
      * A collection of schemas, identified by their connection properties
      * (catalog name, JDBC URL, and so forth).
      *
-     * <p>To lookup a schema, call <code>Pool.instance().{@link #get(String, DataSource, Util.PropertyList)}</code>.
+     * <p>To lookup a schema, call <code>Pool.instance()
+     * .{@link #get(String, DataSource, Util.PropertyList)}</code>.
      */
     static class Pool {
         private final MessageDigest md;
@@ -884,7 +877,8 @@
                             dataSource);
                     }
 
-                    mapUrlToSchema.put(key, new SoftReference<RolapSchema>(schema));
+                    mapUrlToSchema.put(key, new SoftReference<RolapSchema>(
+                            schema));
 
                     if (LOGGER.isDebugEnabled()) {
                         String msg = "Pool.get: create schema \"" +
@@ -1071,7 +1065,7 @@
     }
 
     /**
-     * @deprecated Use {@link mondrian.olap.CacheControl#flushSchema(String, String, String, String)}.
+     * @deprecated Use {@link mondrian.olap.CacheControl#flushSchema(String,String, String, String)}.
      * This method will be removed in mondrian-2.5.
      */
     public static void flushSchema(
@@ -1088,7 +1082,9 @@
     }
 
     /**
-     * @deprecated Use {@link mondrian.olap.CacheControl#flushSchema(String, javax.sql.DataSource)}.
+     * @deprecated Use 
+     * {@link mondrian.olap.CacheControl#flushSchema(String, 
+     * javax.sql.DataSource)}.
      * This method will be removed in mondrian-2.5.
      */
     public static void flushSchema(
@@ -1198,21 +1194,6 @@
     }
 
     RolapHierarchy getSharedHierarchy(final String name) {
-/*
-        RolapHierarchy rh = (RolapHierarchy) mapSharedHierarchyNameToHierarchy.get(name);
-        if (rh == null) {
-System.out.println("RolapSchema.getSharedHierarchy: "+
-" name=" + name +
-", hierarchy is NULL"
-);
-        } else {
-System.out.println("RolapSchema.getSharedHierarchy: "+
-" name=" + name +
-", hierarchy=" +  rh.getName()
-);
-        }
-        return rh;
-*/
         return mapSharedHierarchyNameToHierarchy.get(name);
     }
 
@@ -1378,33 +1359,9 @@
                 reader = createMemberReader(hierarchy, memberReaderClass);
                 // share, for other uses of the same shared hierarchy
                 if (false) mapSharedHierarchyToReader.put(sharedName, reader);
-/*
-System.out.println("RolapSchema.createMemberReader: "+
-"add to sharedHierName->Hier map"+
-" sharedName=" + sharedName +
-", hierarchy=" + hierarchy.getName() +
-", hierarchy.dim=" + hierarchy.getDimension().getName()
-);
-if (mapSharedHierarchyNameToHierarchy.containsKey(sharedName)) {
-System.out.println("RolapSchema.createMemberReader: CONTAINS NAME");
-} else {
-                mapSharedHierarchyNameToHierarchy.put(sharedName, hierarchy);
-}
-*/
-                if (! mapSharedHierarchyNameToHierarchy.containsKey(sharedName)) {
-                    mapSharedHierarchyNameToHierarchy.put(sharedName, hierarchy);
+                if(!mapSharedHierarchyNameToHierarchy.containsKey(sharedName)) {
+                    mapSharedHierarchyNameToHierarchy.put(sharedName,hierarchy);
                 }
-                //mapSharedHierarchyNameToHierarchy.put(sharedName, hierarchy);
-            } else {
-//                final RolapHierarchy sharedHierarchy = (RolapHierarchy)
-//                        mapSharedHierarchyNameToHierarchy.get(sharedName);
-//                final RolapDimension sharedDimension = (RolapDimension)
-//                        sharedHierarchy.getDimension();
-//                final RolapDimension dimension =
-//                    (RolapDimension) hierarchy.getDimension();
-//                Util.assertTrue(
-//                        dimension.getGlobalOrdinal() ==
-//                        sharedDimension.getGlobalOrdinal());
             }
         } else {
             reader = createMemberReader(hierarchy, memberReaderClass);
@@ -1434,7 +1391,7 @@
                     return new CacheMemberReader((MemberSource) o);
                 } else {
                     throw Util.newInternal("member reader class " + clazz +
-                                                    " does not implement " + MemberSource.class);
+                            " does not implement " + MemberSource.class);
                 }
             } catch (ClassNotFoundException e) {
                 e2 = e;
@@ -1451,26 +1408,15 @@
                     "while instantiating member reader '" + memberReaderClass);
         } else {
             SqlMemberSource source = new SqlMemberSource(hierarchy);
-
-            // The following code is disabled bcause
-            // counting members is too slow. The test suite
-            // runs faster without this. So the optimization here
-            // is not to be too clever!
-
-            // Also, the CacheMemberReader is buggy.
-
-            int memberCount;
-            if (false) {
-                memberCount = source.getMemberCount();
+            if(hierarchy.getDimension().isHighCardinality()) {
+                LOGGER.debug("High cardinality for " 
+                        + hierarchy.getDimension());
+                return new NoCacheMemberReader(source);
             } else {
-                memberCount = Integer.MAX_VALUE;
+                LOGGER.debug("Normal cardinality for " 
+                        + hierarchy.getDimension());
+                return new SmartMemberReader(source);
             }
-            int largeDimensionThreshold =
-                    MondrianProperties.instance().LargeDimensionThreshold.get();
-
-            return (memberCount > largeDimensionThreshold)
-                ? new SmartMemberReader(source)
-                : new CacheMemberReader(source);
         }
     }
 
@@ -1483,7 +1429,8 @@
     }
 
     /**
-     * Creates a {@link DataSourceChangeListener} with which to detect changes to datasources.
+     * Creates a {@link DataSourceChangeListener} with which to detect 
+     * changes to datasources.
      */
     private DataSourceChangeListener createDataSourceChangeListener(
             Util.PropertyList connectInfo) {
@@ -1498,25 +1445,19 @@
 
         if ( ! Util.isEmpty(dataSourceChangeListenerStr)) {
             try {
-
                 Class<?> clazz = Class.forName(dataSourceChangeListenerStr);
                 Constructor<?> constructor = clazz.getConstructor();
-                changeListener = (DataSourceChangeListener)constructor.newInstance();
-
-/*                final Class<DataSourceChangeListener> clazz =
-                    (Class<DataSourceChangeListener>) Class.forName(dataSourceChangeListenerStr);
-                final Constructor<DataSourceChangeListener> ctor =
-                    clazz.getConstructor();
-                changeListener = ctor.newInstance(); */
-
+                changeListener = (DataSourceChangeListener)
+                        constructor.newInstance();
             } catch (Exception e) {
                 throw Util.newError(e, "loading DataSourceChangeListener "
                     + dataSourceChangeListenerStr);
             }
 
             if (LOGGER.isDebugEnabled()) {
-                String msg = "RolapSchema.createDataSourceChangeListener: create datasource change listener \"" +
-                dataSourceChangeListenerStr;
+                String msg = "RolapSchema.createDataSourceChangeListener: "
+                        + "create datasource change listener \""
+                        + dataSourceChangeListenerStr;
 
                 LOGGER.debug(msg);
             }
@@ -1549,7 +1490,8 @@
      * <code>RolapStarRegistry</code> is a registry for {@link RolapStar}s.
      */
     class RolapStarRegistry {
-        private final Map<String, RolapStar> stars = new HashMap<String, RolapStar>();
+        private final Map<String, RolapStar> stars = 
+                new HashMap<String, RolapStar>();
 
         RolapStarRegistry() {
         }
@@ -1559,7 +1501,8 @@
          *
          * <p> {@link RolapStar.Table#addJoin} works in a similar way.
          */
-        synchronized RolapStar getOrCreateStar(final MondrianDef.Relation fact) {
+        synchronized RolapStar getOrCreateStar(
+                final MondrianDef.Relation fact) {
             String factTableName = fact.toString();
             RolapStar star = stars.get(factTableName);
             if (star == null) {
Index: src/main/mondrian/rolap/SmartMemberReader.java
===================================================================
--- src/main/mondrian/rolap/SmartMemberReader.java	
+++ src/main/mondrian/rolap/SmartMemberReader.java	
@@ -15,11 +15,13 @@
 package mondrian.rolap;
 import mondrian.olap.Util;
 import mondrian.olap.Id;
+import mondrian.olap.Member;
 import mondrian.rolap.TupleReader.MemberBuilder;
 import mondrian.rolap.cache.SmartCache;
 import mondrian.rolap.cache.SoftSmartCache;
 import mondrian.rolap.sql.MemberChildrenConstraint;
 import mondrian.rolap.sql.TupleConstraint;
+import mondrian.util.ConcatenableList;
 
 import mondrian.spi.DataSourceChangeListener;
 
@@ -54,17 +56,19 @@
     private final MemberReader source;
 
     /** maps a parent member to a list of its children */
-    final SmartMemberListCache<RolapMember, List<RolapMember>> mapMemberToChildren;
+    final SmartMemberListCache<RolapMember, List<? extends Member>> 
+            mapMemberToChildren;
 
     /** a cache for alle members to ensure uniqueness */
     SmartCache<Object, RolapMember> mapKeyToMember;
 
     /** maps a level to its members */
-    final SmartMemberListCache<RolapLevel, List<RolapMember>> mapLevelToMembers;
+    final SmartMemberListCache<RolapLevel, List<? extends Member>> 
+            mapLevelToMembers;
 
     DataSourceChangeListener changeListener;
 
-    private List<RolapMember> rootMembers;
+    private List<? extends Member> rootMembers;
 
     SmartMemberReader(MemberReader source) {
         this.source = source;
@@ -73,11 +77,11 @@
                     "MemberSource (" + source + ", " + source.getClass() +
                     ") does not support cache-writeback");
         }
-        this.mapLevelToMembers =
-            new SmartMemberListCache<RolapLevel, List<RolapMember>>();
+        this.mapLevelToMembers = 
+                new SmartMemberListCache<RolapLevel, List<? extends Member>>();
         this.mapKeyToMember = new SoftSmartCache<Object, RolapMember>();
         this.mapMemberToChildren =
-            new SmartMemberListCache<RolapMember, List<RolapMember>>();
+            new SmartMemberListCache<RolapMember, List<? extends Member>>();
 
         if (source.getHierarchy() != null) {
             changeListener = source.getHierarchy().getRolapSchema().getDataSourceChangeListener();
@@ -110,7 +114,7 @@
             }
         }
     }
-
+    
     // implement MemberCache
     public Object makeKey(RolapMember parent, Object key) {
         return new MemberKey(parent, key);
@@ -129,7 +133,6 @@
         if (mustCheckCacheStatus) {
             checkCacheStatus();
         }
-
         return mapKeyToMember.get(key);
     }
 
@@ -141,21 +144,19 @@
     }
 
     // implement MemberReader
-    public RolapMember[] getMembers() {
-        List<RolapMember> v = new ArrayList<RolapMember>();
+    public List<? extends Member> getMembers() {
+        List<? extends Member> v = new ArrayList<Member>();
         RolapLevel[] levels = (RolapLevel[]) getHierarchy().getLevels();
         // todo: optimize by walking to children for members we know about
         for (RolapLevel level : levels) {
-            List<RolapMember> membersInLevel = getMembersInLevel(
-                level,
-                0,
-                Integer.MAX_VALUE);
-            v.addAll(membersInLevel);
+            List<? extends Member> membersInLevel = getMembersInLevel(
+                    level, 0, Integer.MAX_VALUE);
+            ((List) v).addAll(membersInLevel);
         }
-        return v.toArray(new RolapMember[v.size()]);
+        return v;
     }
 
-    public List<RolapMember> getRootMembers() {
+    public List<? extends Member> getRootMembers() {
         if (rootMembers == null) {
             rootMembers = source.getRootMembers();
         }
@@ -164,81 +165,70 @@
 
 
     // Synchronization: modifies mapLevelToMembers
-    public synchronized List<RolapMember> getMembersInLevel(
-            RolapLevel level,
-            int startOrdinal,
-            int endOrdinal) {
+    public synchronized List<? extends Member> getMembersInLevel(
+            final RolapLevel level, final int startOrdinal,
+            final int endOrdinal) {
         TupleConstraint constraint =
                 sqlConstraintFactory.getLevelMembersConstraint(null);
         return getMembersInLevel(level, startOrdinal, endOrdinal, constraint);
     }
 
-    public synchronized List<RolapMember> getMembersInLevel(
-        RolapLevel level,
-        int startOrdinal,
-        int endOrdinal,
-        TupleConstraint constraint)
-    {
+    public synchronized List<? extends Member> getMembersInLevel(
+            final RolapLevel level, final int startOrdinal,
+            final int endOrdinal, final TupleConstraint constraint) {
         checkCacheStatus();
-
-        List<RolapMember> members = mapLevelToMembers.get(level, constraint);
+        List<? extends Member> members = 
+                mapLevelToMembers.get(level, constraint);
         if (members != null) {
             return members;
         }
 
-        members =
-            source.getMembersInLevel(
-                level, startOrdinal, endOrdinal, constraint);
+        members = source.getMembersInLevel(level, startOrdinal, 
+                endOrdinal, constraint);
         mapLevelToMembers.put(level, constraint, members);
         return members;
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children)
-    {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children) {
         MemberChildrenConstraint constraint =
                 sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMember, children, constraint);
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
-        List<RolapMember> parentMembers = new ArrayList<RolapMember>();
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
+        List<Member> parentMembers = new ArrayList<Member>();
         parentMembers.add(parentMember);
         getMemberChildren(parentMembers, children, constraint);
     }
 
     public synchronized void getMemberChildren(
-            List<RolapMember> parentMembers,
-            List<RolapMember> children) {
+            final List<? extends Member> parentMembers,
+            final List<? extends Member> children) {
         MemberChildrenConstraint constraint =
                 sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMembers, children, constraint);
     }
 
     public synchronized void getMemberChildren(
-            List<RolapMember> parentMembers,
-            List<RolapMember> children,
-            MemberChildrenConstraint constraint) {
-
+            final List<? extends Member> parentMembers,
+            final List<? extends Member> children,
+            final MemberChildrenConstraint constraint) {
         checkCacheStatus();
-
         List<RolapMember> missed = new ArrayList<RolapMember>();
-        for (RolapMember parentMember : parentMembers) {
-            List<RolapMember> list =
-                mapMemberToChildren.get(parentMember, constraint);
+        for (final Member parentMember : parentMembers) {
+            List<? extends Member> list =
+                mapMemberToChildren.get((RolapMember) parentMember, constraint);
             if (list == null) {
                 if (parentMember.isNull()) {
                     // the null member has no children
                 } else {
-                    missed.add(parentMember);
+                    ((List) missed).add(parentMember);
                 }
             } else {
-                children.addAll(list);
+                ((List) children).addAll(list);
             }
         }
         if (missed.size() > 0) {
@@ -246,9 +236,8 @@
         }
     }
 
-    public RolapMember lookupMember(
-            List<Id.Segment> uniqueNameParts,
-            boolean failIfNotFound) {
+    public RolapMember lookupMember(final List<Id.Segment> uniqueNameParts,
+            final boolean failIfNotFound) {
         return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound);
     }
 
@@ -261,11 +250,9 @@
      * @param constraint restricts the returned members if possible (optional
      *             optimization)
      */
-    private void readMemberChildren(
-        List<RolapMember> members,
-        List<RolapMember> result,
-        MemberChildrenConstraint constraint)
-    {
+    private void readMemberChildren(final List<? extends Member> members,
+            final List<? extends Member> result, 
+            final MemberChildrenConstraint constraint) {
         if (false) {
             // Pre-condition disabled. It makes sense to have the pre-
             // condition, because lists of parent members are typically
@@ -276,27 +263,27 @@
             //   -- jhyde, 2004/6/10.
             Util.assertPrecondition(isSorted(members), "isSorted(members)");
         }
-        List<RolapMember> children = new ArrayList<RolapMember>();
+        List<RolapMember> children = new ConcatenableList<RolapMember>();
         source.getMemberChildren(members, children, constraint);
         // Put them in a temporary hash table first. Register them later, when
         // we know their size (hence their 'cost' to the cache pool).
-        Map<RolapMember, List<RolapMember>> tempMap =
-            new HashMap<RolapMember, List<RolapMember>>();
-        for (RolapMember member1 : members) {
-            tempMap.put(member1, Collections.EMPTY_LIST);
+        Map<? extends Member, List<? extends Member>> tempMap =
+            new HashMap<Member, List<? extends Member>>();
+        for (Member member1 : members) {
+            ((Map) tempMap).put(member1, new ArrayList<Member>());
         }
-        for (int i = 0, childrenCount = children.size(); i < childrenCount; i++) {
+        for (int i = 0, childrenCount = children.size(); i<childrenCount; i++) {
             // todo: We could optimize here. If members.length is small, it's
             // more efficient to drive from members, rather than hashing
             // children.length times. We could also exploit the fact that the
             // result is sorted by ordinal and therefore, unless the "members"
             // contains members from different levels, children of the same
             // member will be contiguous.
-            RolapMember child = children.get(i);
+            Member child = children.get(i);
             assert child != null : "child";
             assert tempMap != null : "tempMap";
-            final RolapMember parentMember = child.getParentMember();
-            List<RolapMember> list = tempMap.get(parentMember);
+            final Member parentMember = child.getParentMember();
+            List<? extends Member> list = tempMap.get(parentMember);
             if (list == null) {
                 // The list is null if, due to dropped constraints, we now
                 // have a children list of a member we didn't explicitly
@@ -304,19 +291,18 @@
                 // let's ignore it.
                 continue;
             } else if (list == Collections.EMPTY_LIST) {
-                list = new ArrayList<RolapMember>();
-                tempMap.put(parentMember, list);
+                list = new ArrayList<Member>();
+                ((Map) tempMap).put(parentMember, list);
             }
-            list.add(child);
-            result.add(child);
+            ((List) list).add(child);
+            ((List) result).add(child);
         }
         synchronized (this) {
-            for (Map.Entry<RolapMember, List<RolapMember>> entry :
-                tempMap.entrySet())
-            {
-                final RolapMember member = entry.getKey();
+            for (Map.Entry<? extends Member, List<? extends Member>> entry :
+                    tempMap.entrySet()) {
+                final RolapMember member = (RolapMember) entry.getKey();
                 if (getChildrenFromCache(member, constraint) == null) {
-                final List<RolapMember> list = entry.getValue();
+                    final List<? extends Member> list = entry.getValue();
                     putChildren(member, constraint, list);
                 }
             }
@@ -327,19 +313,19 @@
      * Returns true if every element of <code>members</code> is not null and is
      * strictly less than the following element; false otherwise.
      */
-    public boolean isSorted(List<RolapMember> members) {
+    public boolean isSorted(List<? extends Member> members) {
         final int count = members.size();
         if (count == 0) {
             return true;
         }
-        RolapMember m1 = members.get(0);
+        RolapMember m1 = (RolapMember) members.get(0);
         if (m1 == null) {
             // Special case check for 0th element, just in case length == 1.
             return false;
         }
         for (int i = 1; i < count; i++) {
             RolapMember m0 = m1;
-            m1 = members.get(i);
+            m1 = (RolapMember) members.get(i);
             if (m1 == null || compare(m0, m1, false) >= 0) {
                 return false;
             }
@@ -347,7 +333,7 @@
         return true;
     }
 
-    public synchronized List<RolapMember> getChildrenFromCache(
+    public synchronized List<? extends Member> getChildrenFromCache(
             RolapMember member,
             MemberChildrenConstraint constraint) {
         if (constraint == null) {
@@ -365,15 +351,12 @@
         return mapLevelToMembers.get(level, constraint);
     }
 
-    public synchronized void putChildren(
-        RolapMember member,
-        MemberChildrenConstraint constraint,
-        List<RolapMember> children)
-    {
-        if (constraint == null) {
-            constraint = sqlConstraintFactory.getMemberChildrenConstraint(null);
-        }
-        mapMemberToChildren.put(member, constraint, children);
+    public synchronized void putChildren(final RolapMember member,
+            final MemberChildrenConstraint constraint,
+            final List<? extends Member> children) {
+        mapMemberToChildren.put(member, constraint==null ? 
+            sqlConstraintFactory.getMemberChildrenConstraint(null) : constraint,
+            children);
     }
 
     // synchronization: Must synchronize, because uses mapMemberToChildren
@@ -386,7 +369,8 @@
                 RolapMember sibling = null;
                 while (n-- > 0) {
                     if (!iter.hasNext()) {
-                        return (RolapMember) member.getHierarchy().getNullMember();
+                        return (RolapMember) 
+                                member.getHierarchy().getNullMember();
                     }
                     sibling = iter.nextMember();
                 }
@@ -396,7 +380,8 @@
                 RolapMember sibling = null;
                 while (n-- > 0) {
                     if (!iter.hasPrevious()) {
-                        return (RolapMember) member.getHierarchy().getNullMember();
+                        return (RolapMember) 
+                                member.getHierarchy().getNullMember();
                     }
                     sibling = iter.previousMember();
                 }
@@ -405,10 +390,9 @@
         }
     }
 
-    public void getMemberRange(RolapLevel level,
-                               RolapMember startMember,
-                               RolapMember endMember,
-                               List<RolapMember> list) {
+    public void getMemberRange(final RolapLevel level, 
+            final RolapMember startMember, final RolapMember endMember,
+            final List<? extends Member> list) {
         Util.assertPrecondition(startMember != null, "startMember != null");
         Util.assertPrecondition(endMember != null, "endMember != null");
         Util.assertPrecondition(startMember.getLevel() == endMember.getLevel(),
@@ -417,14 +401,14 @@
         if (compare(startMember, endMember, false) > 0) {
             return;
         }
-        list.add(startMember);
+        ((List) list).add(startMember);
         if (startMember == endMember) {
             return;
         }
         SiblingIterator siblings = new SiblingIterator(this, startMember);
         while (siblings.hasNext()) {
             final RolapMember member = siblings.nextMember();
-            list.add(member);
+            ((List) list).add(member);
             if (member == endMember) {
                 return;
             }
@@ -517,13 +501,13 @@
     class SiblingIterator {
         private final MemberReader reader;
         private final SiblingIterator parentIterator;
-        private RolapMember[] siblings;
+        private List<? extends Member> siblings;
         private int position;
 
         SiblingIterator(MemberReader reader, RolapMember member) {
             this.reader = reader;
             RolapMember parent = member.getParentMember();
-            List<RolapMember> siblingList;
+            List<? extends Member> siblingList;
             if (parent == null) {
                 siblingList = reader.getRootMembers();
                 this.parentIterator = null;
@@ -532,10 +516,10 @@
                 reader.getMemberChildren(parent, siblingList);
                 this.parentIterator = new SiblingIterator(reader, parent);
             }
-            this.siblings = RolapUtil.toArray(siblingList);
+            this.siblings = siblingList;
             this.position = -1;
-            for (int i = 0; i < this.siblings.length; i++) {
-                if (siblings[i] == member) {
+            for (int i = 0; i < this.siblings.size(); i++) {
+                if (siblings.get(i) == member) {
                     this.position = i;
                     break;
                 }
@@ -546,7 +530,7 @@
             }
         }
         boolean hasNext() {
-            return (this.position < this.siblings.length - 1) ||
+            return (this.position < this.siblings.size()- 1) ||
                 (parentIterator != null) &&
                 parentIterator.hasNext();
         }
@@ -554,17 +538,18 @@
             return nextMember();
         }
         RolapMember nextMember() {
-            if (++this.position >= this.siblings.length) {
+            if (++this.position >= this.siblings.size()) {
                 if (parentIterator == null) {
                     throw Util.newInternal("there is no next member");
                 }
                 RolapMember parent = parentIterator.nextMember();
-                List<RolapMember> siblingList = new ArrayList<RolapMember>();
+                List<? extends Member> siblingList = 
+                        new ArrayList<RolapMember>();
                 reader.getMemberChildren(parent, siblingList);
-                this.siblings = RolapUtil.toArray(siblingList);
+                this.siblings = siblingList;
                 this.position = 0;
             }
-            return this.siblings[this.position];
+            return (RolapMember) this.siblings.get(this.position);
         }
         boolean hasPrevious() {
             return (this.position > 0) ||
@@ -582,10 +567,10 @@
                 RolapMember parent = parentIterator.previousMember();
                 List<RolapMember> siblingList = new ArrayList<RolapMember>();
                 reader.getMemberChildren(parent, siblingList);
-                this.siblings = RolapUtil.toArray(siblingList);
-                this.position = this.siblings.length - 1;
+                this.siblings = siblingList;
+                this.position = this.siblings.size() - 1;
             }
-            return this.siblings[this.position];
+            return (RolapMember) this.siblings.get(this.position);
         }
     }
 
Index: src/main/mondrian/rolap/RolapAxis.java
===================================================================
--- src/main/mondrian/rolap/RolapAxis.java	
+++ src/main/mondrian/rolap/RolapAxis.java	
@@ -28,7 +28,7 @@
 /**
  * Derived classes of RolapAxis implements the Axis interface which are
  * specializations based upon the number of Positions, how each Position's
- * Members are orgainized and whether the Members/Member[]s are in a List
+ * Members are orgainized and whether the Members/List<Member>s are in a List
  * or an Iterable.
  *
  * @author <a>Richard M. Emberson</a>
@@ -319,6 +319,8 @@
         public List<Position> getPositions() {
             return new MemberList.PositionList();
         }
+
+        public String toString() { return this.list.toString(); }
         /**
          *  Each Position has a single Member.
          */
@@ -331,10 +333,26 @@
             public Position get(int index) {
                 return new MemberList.MLPosition(index);
             }
+            public Iterator<Position> iterator() {
+                return new Iterator<Position>() {
+                    private final Iterator it = list.iterator();
+                    private int cursor = 0;
+                    public boolean hasNext() {
+                        return it.hasNext();
+                    }
+                    public Position next() {
+                        it.next();
+                        return get(cursor++);
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
         }
 
         /**
-         *  Allows access only the the Member at the given offset.
+         *  Allows access only to the Member at the given offset.
          */
         class MLPosition extends PositionBase {
             protected final int offset;
@@ -349,23 +367,23 @@
                     throw new IndexOutOfBoundsException(
                         "Index: "+index+", Size: 1");
                 }
-                return list.get(offset);
+                return list.get(this.offset);
             }
         }
     }
 
     /**
-     * A MemberArrayIterable takes an Iterable&lt;Member[]&gt; where
+     * A MemberArrayIterable takes an Iterable&lt;List<Member>&gt; where
      * each Position has
      * an array of Members from the corresponding location in the iterator.
      * If the client request any of the List, non-Iterable, API, then
      * a List is materialized from the Iterable.
      */
     public static class MemberArrayIterable extends RolapAxis {
-        private Iterable<Member[]> iter;
-        private List<Member[]> list;
+        private Iterable<List<Member>> iter;
+        private List<List<Member>> list;
         private int len;
-        public MemberArrayIterable(Iterable<Member[]> iter) {
+        public MemberArrayIterable(Iterable<List<Member>> iter) {
             this.iter = iter;
             this.list = null;
             this.len = 0;
@@ -378,15 +396,15 @@
         protected synchronized void materialize() {
 //System.out.println("RolapAxis.materialize: 3");
             if (list == null) {
-                Iterator<Member[]> it = iter.iterator();
-                list = new ArrayList<Member[]>();
+                Iterator<List<Member>> it = iter.iterator();
+                list = new ArrayList<List<Member>>();
                 while (it.hasNext()) {
                     list.add(it.next());
                 }
                 // allow gc of iter
                 iter = null;
 
-                len = (list.size() == 0) ? 0 : list.get(0).length;
+                len = (list.size() == 0) ? 0 : list.get(0).size();
             }
         }
 
@@ -404,10 +422,9 @@
                 positionList = new PositionIter();
             }
             protected synchronized void materialize() {
-//System.out.println("RolapAxis.materialize: 4");
                 if (LOGGER.isDebugEnabled()) {
                     LOGGER.debug(
-                        "PositionWrapper.materialize: Member[] iter.class="
+                        "PositionWrapper.materialize: List<Member> iter.class="
                         + ((iter != null) ? iter.getClass().getName() : null));
                 }
                 RolapAxis.MemberArrayIterable.this.materialize();
@@ -441,7 +458,7 @@
          * has two or more Members.
          */
         class PositionIter extends PositionIterBase {
-            private Iterator<Member[]> it;
+            private Iterator<List<Member>> it;
             PositionIter() {
                 it = iter.iterator();
             }
@@ -466,29 +483,18 @@
          * Each Iterator&lt;Member&gt; two or more Members.
          */
         class MIPosition extends PositionBase  {
-            Member[] members;
-            MIPosition(Member[] members) {
+            List<Member> members;
+            MIPosition(List<Member> members) {
                 this.members = members;
             }
             public int size() {
-                return members.length;
+                return members.size();
             }
             public Member get(int index) {
-                return members[index];
+                return members.get(index);
             }
             public Iterator<Member> iterator() {
-                return new Iterator<Member>() {
-                    int index = 0;
-                    public boolean hasNext() {
-                        return (index < members.length);
-                    }
-                    public Member next() {
-                        return members[index++];
-                    }
-                    public void remove() {
-                        throw new UnsupportedOperationException("remove");
-                    }
-                };
+                return members.iterator();
             }
         }
 
@@ -525,7 +531,7 @@
                         ", Size: " +
                         RolapAxis.MemberArrayIterable.this.len);
                 }
-                return list.get(offset)[index];
+                return list.get(offset).get(index);
             }
         }
     }
@@ -533,17 +539,17 @@
 
 
     /**
-     * A MemberArrayList takes a List&lt;Member[]&gt; where each Position has
+     * A MemberArrayList takes a List&lt;List<Member>&gt; where each Position has
      * the Member's from the corresponding location in the list.
      * It is assumed that each element of the list has an array of Members of
      * the same size.
      */
     public static class MemberArrayList extends RolapAxis {
-        private final List<Member[]> list;
+        private final List<List<Member>> list;
         private final int len;
-        public MemberArrayList(List<Member[]> list) {
+        public MemberArrayList(List<List<Member>> list) {
             this.list = list;
-            this.len = (list.size() == 0) ? 0 : list.get(0).length;
+            this.len = (list.size() == 0) ? 0 : list.get(0).size();
         }
         public List<Position> getPositions() {
             return new MemberArrayList.PositionList();
@@ -558,6 +564,7 @@
                 return list.size();
             }
             public Position get(int index) {
+                if(index>=list.size()) throw new IndexOutOfBoundsException();
                 return new MemberArrayList.MALPosition(index);
             }
         }
@@ -580,7 +587,7 @@
                         ", Size: " +
                         RolapAxis.MemberArrayList.this.len);
                 }
-                return list.get(offset)[index];
+                return list.get(offset).get(index);
             }
         }
     }
Index: src/main/mondrian/rolap/RolapLevel.java
===================================================================
--- src/main/mondrian/rolap/RolapLevel.java	
+++ src/main/mondrian/rolap/RolapLevel.java	
@@ -473,20 +473,15 @@
         return lookupChild(schemaReader, name, MatchType.EXACT);
     }
 
-    public OlapElement lookupChild(
-        SchemaReader schemaReader, Id.Segment name, MatchType matchType)
-    {
-        Member[] levelMembers = schemaReader.getLevelMembers(this, true);
-        if (levelMembers.length > 0) {
-            Member parent = levelMembers[0].getParentMember();
+    public OlapElement lookupChild(final SchemaReader schemaReader, 
+            final Id.Segment name, MatchType matchType) {
+        List<? extends Member> levelMembers = 
+                schemaReader.getLevelMembers(this, true);
+        if (levelMembers.size() > 0) {
+            Member parent = levelMembers.get(0).getParentMember();
             return
-                RolapUtil.findBestMemberMatch(
-                    Arrays.asList(levelMembers),
-                    (RolapMember) parent,
-                    this,
-                    name,
-                    matchType,
-                    false);
+                RolapUtil.findBestMemberMatch(levelMembers, 
+                        (RolapMember) parent, this, name, matchType, false);
         }
         return null;
     }
Index: src/main/mondrian/rolap/SqlMemberSource.java
===================================================================
--- src/main/mondrian/rolap/SqlMemberSource.java	
+++ src/main/mondrian/rolap/SqlMemberSource.java	
@@ -251,11 +251,11 @@
     }
 
 
-    public RolapMember[] getMembers() {
+    public List<? extends Member> getMembers() {
         return getMembers(dataSource);
     }
 
-    private RolapMember[] getMembers(DataSource dataSource) {
+    private List<? extends Member> getMembers(DataSource dataSource) {
         String sql = makeKeysSql(dataSource);
         RolapLevel[] levels = (RolapLevel[]) hierarchy.getLevels();
         SqlStatement stmt =
@@ -263,13 +263,13 @@
                 dataSource, sql, "SqlMemberSource.getMembers",
                 "while building member cache");
         try {
-            List<RolapMember> list = new ArrayList<RolapMember>();
+            List<? extends Member> list = new ArrayList<Member>();
             Map<MemberKey, RolapMember> map =
                 new HashMap<MemberKey, RolapMember>();
             RolapMember root = null;
             if (hierarchy.hasAll()) {
                 root = hierarchy.getAllMember();
-                list.add(root);
+                ((List) list).add(root);
             }
 
             int limit = MondrianProperties.instance().ResultLimit.get();
@@ -309,7 +309,7 @@
                         if (value == RolapUtil.sqlNullValue) {
                             addAsOldestSibling(list, member);
                         } else {
-                            list.add(member);
+                            ((List) list).add(member);
                         }
                         map.put(key, member);
                     }
@@ -334,7 +334,8 @@
                 }
             }
 
-            return RolapUtil.toArray(list);
+//            return RolapUtil.toArray(list);
+            return list;
         } catch (SQLException e) {
             throw stmt.handle(e);
         } finally {
@@ -353,15 +354,16 @@
      * Adds <code>member</code> just before the first element in
      * <code>list</code> which has the same parent.
      */
-    private void addAsOldestSibling(List<RolapMember> list, RolapMember member) {
+    private void addAsOldestSibling(final List<? extends Member> list, 
+            final RolapMember member) {
         int i = list.size();
         while (--i >= 0) {
-            RolapMember sibling = list.get(i);
+            RolapMember sibling = (RolapMember) list.get(i);
             if (sibling.getParentMember() != member.getParentMember()) {
                 break;
             }
         }
-        list.add(i + 1, member);
+        ((List) list).add(i + 1, member);
     }
 
     private String makeKeysSql(DataSource dataSource) {
@@ -401,7 +403,7 @@
     }
 
     // implement MemberReader
-    public List<RolapMember> getMembersInLevel(
+    public List<? extends Member> getMembersInLevel(
             RolapLevel level,
             int startOrdinal,
             int endOrdinal) {
@@ -410,32 +412,78 @@
         return getMembersInLevel(level, startOrdinal, endOrdinal, constraint);
     }
 
-    public List<RolapMember> getMembersInLevel(
+    public List<? extends Member> getMembersInLevel(
             RolapLevel level,
             int startOrdinal,
             int endOrdinal,
             TupleConstraint constraint) {
         if (level.isAll()) {
-            return Collections.singletonList(hierarchy.getAllMember());
+            final ArrayList<Member> list = new ArrayList<Member>();
+            list.add(hierarchy.getAllMember());
+//            return Collections.singletonList(hierarchy.getAllMember());
+            return list;
         }
+//System.out.println("SqlMemberSource.getMembersInLevel ignoring startOrdinal, endOrdinal. DANGER!!!");
         return getMembersInLevel(level, constraint);
     }
 
-    private List<RolapMember> getMembersInLevel(
+    private List<? extends Member> getMembersInLevel(
         RolapLevel level,
         TupleConstraint constraint)
     {
-        TupleReader tupleReader = new SqlTupleReader(constraint);
+        final TupleReader tupleReader = level.getDimension().isHighCardinality()
+                    ? new HighCardSqlTupleReader(constraint) 
+                    : new SqlTupleReader(constraint);
         tupleReader.addLevelMembers(level, this, null);
-        List<RolapMember[]> tupleList =
-            tupleReader.readTuples(dataSource, null, null);
-        List<RolapMember> memberList =
-            new ArrayList<RolapMember>(tupleList.size());
-        for (RolapMember[] tuple : tupleList) {
-            assert tuple.length == 1;
-            memberList.add(tuple[0]);
-        }
-        return memberList;
+        final List<List<? extends Member>> tupleList =
+                tupleReader.readTuples(dataSource, null, null);
+
+        return new AbstractList<Member>() {
+                public Member get(final int index) {
+                    return tupleList.get(index).get(0);
+                }
+
+                public int size() {
+                    return tupleList.size();
+                }
+
+                public Object[] toArray() {
+                    final List<Member> l = new ArrayList<Member>();
+                    for(final List<? extends Member> tuple : tupleList) {
+                        l.add(tuple.get(0));
+                    }
+                    return l.toArray(new Member[0]);
+                }
+
+                public <Member> Member[] toArray(final Member[] pattern) {
+                    return (Member[]) toArray();
+                }
+
+                public Iterator<Member> iterator() {
+                    final Iterator<List<? extends Member>> it = 
+                            tupleList.iterator();
+                    return new Iterator<Member>() {
+                            public boolean hasNext() {
+                                return it.hasNext();
+                            }
+                            public Member next() {
+                                return it.next().get(0);
+                            }
+                            public void remove() {
+                                it.remove();
+                            }
+                        };
+                }
+
+                public boolean isEmpty() {
+                    try {
+                        this.get(0);
+                        return true;
+                    } catch(IndexOutOfBoundsException e) {
+                        return false;
+                    }
+                }
+            };
     }
 
     public MemberCache getMemberCache() {
@@ -443,7 +491,7 @@
     }
 
     // implement MemberSource
-    public List<RolapMember> getRootMembers() {
+    public List<? extends Member> getRootMembers() {
         return getMembersInLevel(
                 (RolapLevel) hierarchy.getLevels()[0],
                 0,
@@ -554,8 +602,8 @@
 
         // Convert global ordinal to cube based ordinal (the 0th dimension
         // is always [Measures])
-        final Member[] members = evaluator.getMembers();
-        Member measure = members[0];
+        final List<Member> members = evaluator.getMembers();
+        Member measure = members.get(0);
         int ordinal = measure.getOrdinal();
 
         // get the level using the current depth
@@ -588,16 +636,16 @@
                 star, levelBitKey, measureBitKey, new boolean[]{ false });
     }
 
-    public void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children) {
-        MemberChildrenConstraint constraint = sqlConstraintFactory.getMemberChildrenConstraint(null);
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children) {
+        MemberChildrenConstraint constraint = 
+                sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMembers, children, constraint);
     }
 
-    public void getMemberChildren(
-        List<RolapMember> parentMembers,
-        List<RolapMember> children,
-        MemberChildrenConstraint mcc)
-    {
+    public void getMemberChildren(final List<? extends Member> parentMembers,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint mcc) {
         // try to fetch all children at once
         RolapLevel childLevel =
             getCommonChildLevelForDescendants(parentMembers);
@@ -605,37 +653,33 @@
             TupleConstraint lmc =
                 sqlConstraintFactory.getDescendantsConstraint(
                     parentMembers, mcc);
-            List<RolapMember> list =
+            List<? extends Member> list =
                 getMembersInLevel(childLevel, 0, Integer.MAX_VALUE, lmc);
-            children.addAll(list);
+            ((List) children).addAll(list);
             return;
         }
 
         // fetch them one by one
-        for (RolapMember parentMember : parentMembers) {
+        for (Member parentMember : parentMembers) {
             getMemberChildren(parentMember, children, mcc);
         }
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children)
-    {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children) {
         MemberChildrenConstraint constraint =
             sqlConstraintFactory.getMemberChildrenConstraint(null);
         getMemberChildren(parentMember, children, constraint);
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         // allow parent child calculated members through
         // this fixes the non closure parent child hierarchy bug
         if (!parentMember.isAll() && 
                 parentMember.isCalculated() && 
-                !parentMember.getLevel().isParentChild()) {
+                !((RolapLevel) parentMember.getLevel()).isParentChild()) {
             return;
         }
         getMemberChildren2(parentMember, children, constraint);
@@ -647,22 +691,21 @@
      * fetched at once. Otherwise returns null.
      */
     private RolapLevel getCommonChildLevelForDescendants(
-        List<RolapMember> parents)
-    {
+            final List<? extends Member> parents) {
         // at least two members required
         if (parents.size() < 2) {
             return null;
         }
         RolapLevel parentLevel = null;
         RolapLevel childLevel = null;
-        for (RolapMember member : parents) {
+        for (Member member : parents) {
             // we can not fetch children of calc members
             if (member.isCalculated()) {
                 return null;
             }
             // first round?
             if (parentLevel == null) {
-                parentLevel = member.getLevel();
+                parentLevel = (RolapLevel) member.getLevel();
                 // check for parent/child
                 if (parentLevel.isParentChild()) {
                     return null;
@@ -681,17 +724,15 @@
         return childLevel;
     }
 
-    private void getMemberChildren2(
-        RolapMember parentMember,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+    private void getMemberChildren2(final Member parentMember,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         String sql;
         boolean parentChild;
-        final RolapLevel parentLevel = parentMember.getLevel();
+        final RolapLevel parentLevel = (RolapLevel) parentMember.getLevel();
         RolapLevel childLevel;
         if (parentLevel.isParentChild()) {
-            sql = makeChildMemberSqlPC(parentMember);
+            sql = makeChildMemberSqlPC((RolapMember) parentMember);
             parentChild = true;
             childLevel = parentLevel;
         } else {
@@ -701,10 +742,11 @@
                 return;
             }
             if (childLevel.isParentChild()) {
-                sql = makeChildMemberSql_PCRoot(parentMember);
+                sql = makeChildMemberSql_PCRoot((RolapMember) parentMember);
                 parentChild = true;
             } else {
-                sql = makeChildMemberSql(parentMember, dataSource, constraint);
+                sql = makeChildMemberSql((RolapMember) parentMember, 
+                        dataSource, constraint);
                 parentChild = false;
             }
         }
@@ -713,7 +755,6 @@
                 dataSource, sql, "SqlMemberSource.getMemberChildren",
                 "while building member cache");
         try {
-
             int limit = MondrianProperties.instance().ResultLimit.get();
             boolean checkCacheStatus=true;
 
@@ -741,18 +782,19 @@
                     columnOffset = 1;
                     captionValue = null;
                 }
-                Object key = cache.makeKey(parentMember, value);
+                Object key = cache.makeKey((RolapMember) parentMember, value);
                 RolapMember member = cache.getMember(key, checkCacheStatus);
                 checkCacheStatus = false; /* Only check the first time */
                 if (member == null) {
-                    member = makeMember(
-                            parentMember, childLevel, value, captionValue,
+                    member = makeMember((RolapMember) parentMember, 
+                            childLevel, value, captionValue,
                             parentChild, resultSet, key, columnOffset);
                 }
                 if (value == RolapUtil.sqlNullValue) {
+                    children.toArray();
                     addAsOldestSibling(children, member);
                 } else {
-                    children.add(member);
+                    ((List) children).add(member);
                 }
             }
         } catch (SQLException e) {
@@ -772,7 +814,6 @@
             Object key,
             int columnOffset)
             throws SQLException {
-
         RolapMember member = new RolapMember(parentMember, childLevel, value);
         if (!childLevel.getOrdinalExp().equals(childLevel.getKeyExp())) {
             member.setOrdinal(lastOrdinal++);
@@ -949,7 +990,7 @@
     public void getMemberRange(RolapLevel level,
                                RolapMember startMember,
                                RolapMember endMember,
-                               List<RolapMember> memberList) {
+                               List<? extends Member> memberList) {
         throw new UnsupportedOperationException();
     }
 
@@ -976,8 +1017,7 @@
             super(parentMember, childLevel, value);
             this.dataMember = dataMember;
             this.depth = (parentMember != null)
-                ? parentMember.getDepth() + 1
-                : 0;
+                ? parentMember.getDepth() + 1 : 0;
         }
 
         public Member getDataMember() {
@@ -985,9 +1025,10 @@
         }
 
         public Object getPropertyValue(String propertyName, boolean matchCase) {
-            if (Util.equal(propertyName, Property.CONTRIBUTING_CHILDREN.name, matchCase)) {
-                List<RolapMember> list = new ArrayList<RolapMember>();
-                list.add(dataMember);
+            if (Util.equal(propertyName, 
+                    Property.CONTRIBUTING_CHILDREN.name, matchCase)) {
+                List<? extends Member> list = new ArrayList<Member>();
+                ((List) list).add(dataMember);
                 RolapHierarchy hierarchy = getHierarchy();
                 hierarchy.getMemberReader().getMemberChildren(dataMember, list);
                 return list;
Index: src/main/mondrian/rolap/SqlContextConstraint.java
===================================================================
--- src/main/mondrian/rolap/SqlContextConstraint.java	
+++ src/main/mondrian/rolap/SqlContextConstraint.java	
@@ -261,7 +261,7 @@
         Map<RolapLevel, RolapStar.Column> levelToColumnMap,
         Map<String, RolapStar.Table> relationNamesToStarTableMap,
         AggStar aggStar,
-        List<RolapMember> parents)
+        List<? extends Member> parents)
     {
         SqlConstraintUtils.addContextConstraint(
             sqlQuery, aggStar, evaluator, strict);
@@ -290,10 +290,10 @@
      * optimization.
      */
     protected boolean isJoinRequired() {
-        Member[] members = evaluator.getMembers();
+        List<Member> members = evaluator.getMembers();
         // members[0] is the Measure, so loop starts at 1
-        for (int i = 1; i < members.length; i++) {
-            if (!members[i].isAll()) {
+        for (int i = 1; i < members.size(); i++) {
+            if (!members.get(i).isAll()) {
                 return true;
             }
         }
Index: src/main/mondrian/rolap/MeasureMemberSource.java
===================================================================
--- src/main/mondrian/rolap/MeasureMemberSource.java	
+++ src/main/mondrian/rolap/MeasureMemberSource.java	
@@ -13,6 +13,8 @@
 
 package mondrian.rolap;
 
+import java.util.*;
+
 /**
  * A <code>MeasureMemberSource</code> implements the {@link MemberReader}
  * interface for the special Measures dimension.
@@ -26,7 +28,7 @@
  * @version $Id: //open/mondrian/src/main/mondrian/rolap/MeasureMemberSource.java#7 $
  */
 class MeasureMemberSource extends ArrayMemberSource {
-    MeasureMemberSource(RolapHierarchy hierarchy, RolapMember[] members) {
+    MeasureMemberSource(RolapHierarchy hierarchy, List<RolapMeasure> members) {
         super(hierarchy, members);
     }
 }
Index: src/main/mondrian/rolap/agg/AggregationManager.java
===================================================================
--- src/main/mondrian/rolap/agg/AggregationManager.java	
+++ src/main/mondrian/rolap/agg/AggregationManager.java	
@@ -64,34 +64,35 @@
      * @param groupingSetsCollector grouping sets collector
      */
     public void loadAggregation(
-            RolapStar.Measure[] measures,
-            RolapStar.Column[] columns,
-            BitKey constrainedColumnsBitKey,
-            StarColumnPredicate[] predicates,
-            PinSet pinnedSegments,
-            GroupingSetsCollector groupingSetsCollector) {
+            final RolapStar.Measure[] measures,
+            final RolapStar.Column[] columns,
+            final BitKey constrainedColumnsBitKey,
+            final StarColumnPredicate[] predicates,
+            final PinSet pinnedSegments,
+            final GroupingSetsCollector groupingSetsCollector,
+            final ThreadGroup threadGroup) {
         RolapStar star = measures[0].getStar();
         Aggregation aggregation =
                 star.lookupOrCreateAggregation(constrainedColumnsBitKey);
 
             // try to eliminate unneccessary constraints
             // for Oracle: prevent an IN-clause with more than 1000 elements
-            predicates = aggregation.optimizePredicates(columns, predicates);
-            aggregation.load(columns, measures, predicates, pinnedSegments, groupingSetsCollector);
+            final StarColumnPredicate[] predicates2 = 
+                    aggregation.optimizePredicates(columns, predicates);
+            aggregation.load(columns, measures, predicates2, 
+                    pinnedSegments, groupingSetsCollector, threadGroup);
     }
 
     public Object getCellFromCache(CellRequest request) {
         final RolapStar.Measure measure = request.getMeasure();
-        final Aggregation aggregation =
-            measure.getStar().lookupAggregation(
+        final Aggregation aggregation = measure.getStar().lookupAggregation(
                 request.getConstrainedColumnsBitKey());
 
         if (aggregation == null) {
             // cell is not in any aggregation
             return null;
         }
-        final Object o =
-            aggregation.getCellValue(
+        final Object o = aggregation.getCellValue(
                 measure, request.getSingleValues(), null);
         if (o != null) {
             return o;
Index: src/main/mondrian/rolap/agg/Aggregation.java
===================================================================
--- src/main/mondrian/rolap/agg/Aggregation.java	
+++ src/main/mondrian/rolap/agg/Aggregation.java	
@@ -13,14 +13,38 @@
 
 package mondrian.rolap.agg;
 
-import mondrian.olap.*;
-import mondrian.rolap.*;
-
+import java.io.PrintWriter;
 import java.lang.ref.SoftReference;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.io.PrintWriter;
 
+import mondrian.olap.CacheControl;
+import mondrian.olap.Level;
+import mondrian.olap.Member;
+import mondrian.olap.MondrianProperties;
+import mondrian.olap.SchemaReader;
+import mondrian.olap.Util;
+import mondrian.rolap.BitKey;
+import mondrian.rolap.CellKey;
+import mondrian.rolap.GroupingSetsCollector;
+import mondrian.rolap.RolapAggregationManager;
+import mondrian.rolap.RolapCacheRegion;
+import mondrian.rolap.RolapStar;
+import mondrian.rolap.RolapUtil;
+import mondrian.rolap.StarColumnPredicate;
+import mondrian.rolap.StarPredicate;
+
+
+
 /**
  * A <code>Aggregation</code> is a pre-computed aggregation over a set of
  * columns.
@@ -57,6 +81,25 @@
  * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/Aggregation.java#48 $
  */
 public class Aggregation {
+    
+    private static ThreadGroup parallelThreadGroups = new ThreadGroup("AggregationParallelThreadGroups");
+    public static ThreadGroup getParallelThreadGroups() {
+        return parallelThreadGroups;
+    }
+    private static int getParallelThreadsInThreadGroupsCount() {
+        int groupCount = parallelThreadGroups.activeGroupCount();
+        if(groupCount == 0)
+            return 0;
+        
+        ThreadGroup[] threadGroupList = new ThreadGroup[groupCount]; 
+        parallelThreadGroups.enumerate(threadGroupList);
+        
+        int totalThreads = 0;
+        for(int i = 0; i < groupCount; i++) {
+            totalThreads += threadGroupList[i].activeCount();
+        }
+        return totalThreads;
+    }
     private int maxConstraints;
 
     private final RolapStar star;
@@ -69,8 +112,9 @@
 
     /**
      * List of soft references to segments.
-     * This List implementation should be Thread safe on all mutative operations 
-     * (add, set, and so on). Access to this list is not synchronized in the code.
+     * This List implementation should be Thread safe on all mutative 
+     * operations (add, set, and so on). Access to this list is not 
+     * synchronized in the code.
      * This is the only mutable field in the class.
      */
     private final List<SoftReference<Segment>> segmentRefs;
@@ -132,12 +176,12 @@
      *   state = {CA, OR},
      *   gender = unconstrained
      */
-    public void load(
-        RolapStar.Column[] columns, RolapStar.Measure[] measures,
-        StarColumnPredicate[] predicates,
-        RolapAggregationManager.PinSet pinnedSegments,
-        GroupingSetsCollector groupingSetsCollector)
-    {
+    public void load(final RolapStar.Column[] columns, 
+            final RolapStar.Measure[] measures,
+            final StarColumnPredicate[] predicates,
+            final RolapAggregationManager.PinSet pinnedSegments,
+            final GroupingSetsCollector groupingSetsCollector,
+            final ThreadGroup threadGroup) {
         // all constrained columns
         if (this.columns == null) {
             this.columns = columns;
@@ -164,9 +208,21 @@
             //Segments are loaded using group by grouping sets
             // by CompositeBatch.loadAggregation
         } else {
-            ArrayList<GroupingSet> groupingSets = new ArrayList<GroupingSet>();
+            final ArrayList<GroupingSet> groupingSets = 
+                    new ArrayList<GroupingSet>();
+            final RolapAggregationManager.PinSet pinnedSegments2 = 
+                    pinnedSegments;
             groupingSets.add(groupingSet);
-            new SegmentLoader().load(groupingSets, pinnedSegments);
+
+            final Runnable runner = new Runnable() {
+                public void run() {
+                    new SegmentLoader().load(groupingSets, pinnedSegments2);
+                }};
+            if(threadGroup!=null && getParallelThreadsInThreadGroupsCount() < MondrianProperties.instance().MaximumParallelThreads.get()) {
+                new Thread(threadGroup,runner).start();
+            } else {
+                runner.run();
+            }
         }
     }
 
Index: src/main/mondrian/rolap/agg/CellRequest.java
===================================================================
--- src/main/mondrian/rolap/agg/CellRequest.java	
+++ src/main/mondrian/rolap/agg/CellRequest.java	
@@ -362,6 +362,28 @@
     }
 
     public enum Mode { AND, OR }
+
+
+    public String toString() {
+        return "CellRequest: [Measure=" + measure + ", predicateList=" +
+                predicateList + ",columnPredicateList=" + columnPredicateList 
+                + ", constrainedColumnList=" + constrainedColumnList
+                + ", columnsCache=" +java.util.Arrays.asList(columnsCache)+ "]";
+/*
+
+    private final RolapStar.Measure measure;
+    public final boolean extendedContext;
+    public final boolean drillThrough;
+    final List<RolapStar.Column> constrainedColumnList =
+    final List<StarColumnPredicate> columnPredicateList =
+    Object[] singleValues;
+    RolapStar.Column[] columnsCache = null;
+    final BitKey constrainedColumnsBitKey;
+    boolean unsatisfiable;
+    boolean isDirty = true;
+    List<StarPredicate> predicateList = new ArrayList<StarPredicate>();
+*/
+    }
 }
 
 // End CellRequest.java
Index: src/main/mondrian/rolap/agg/SegmentLoader.java
===================================================================
--- src/main/mondrian/rolap/agg/SegmentLoader.java	
+++ src/main/mondrian/rolap/agg/SegmentLoader.java	
@@ -17,6 +17,8 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 
+
+
 /**
  * <p>The <code>SegmentLoader</code> queries database and loads the data into
  * the given set of segments.</p>
@@ -64,12 +66,13 @@
         List<GroupingSet> groupingSets,
         RolapAggregationManager.PinSet pinnedSegments)
     {
-        GroupingSetsList groupingSetsList =
+        final GroupingSetsList groupingSetsList =
             new GroupingSetsList(groupingSets);
         boolean useGroupingSet = groupingSetsList.useGroupingSets();
         RolapStar.Column[] defaultColumns =
             groupingSetsList.getDefaultColumns();
         SqlStatement stmt = null;
+    
         try {
             stmt = createExecuteSql(groupingSetsList);
             int arity = defaultColumns.length;
@@ -122,7 +125,7 @@
             setFailOnStillLoadingSegments(groupingSetsList);
         }
     }
-
+    
     void setFailOnStillLoadingSegments(GroupingSetsList groupingSetsList) {
         for (GroupingSet groupingset : groupingSetsList.getGroupingSets()) {
             for (Segment segment : groupingset.getSegments()) {
Index: src/main/mondrian/rolap/Test.java
===================================================================
--- src/main/mondrian/rolap/Test.java	
+++ src/main/mondrian/rolap/Test.java	
@@ -15,6 +15,8 @@
 
 import mondrian.olap.DriverManager;
 import mondrian.olap.Id;
+import mondrian.olap.Member;
+import mondrian.olap.Level;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -116,32 +118,33 @@
                     new Id.Segment("Customers", Id.Quoting.QUOTED), false);
         testMemberReader(customerHierarchy.getMemberReader());
     }
-    void testMemberReader(MemberReader reader)
-    {
+
+    void testMemberReader(MemberReader reader) {
         pw.println();
         pw.println("MemberReader class=" + reader.getClass());
         pw.println("Count=" + reader.getMemberCount());
 
         pw.print("Root member(s)=");
-        RolapMember[] rootMembers = RolapUtil.toArray(reader.getRootMembers());
+        List<? extends Member> rootMembers = reader.getRootMembers();
         print(rootMembers);
         pw.println();
 
-        RolapLevel[] levels = (RolapLevel[]) rootMembers[0].getHierarchy().getLevels();
-        RolapLevel level = levels[levels.length > 1 ? 1 : 0];
+        Level[] levels = rootMembers.get(0).getHierarchy().getLevels();
+        Level level = levels[levels.length > 1 ? 1 : 0];
         pw.print("Members at level " + level.getUniqueName() + " are ");
-        RolapMember[] members = RolapUtil.toArray(reader.getMembersInLevel(level, 0, Integer.MAX_VALUE));
+        List<? extends Member> members = reader
+                .getMembersInLevel((RolapLevel) level, 0, Integer.MAX_VALUE);
         print(members);
         pw.println();
 
         pw.println("First children of first children: {");
-        List<RolapMember> firstChildren = new ArrayList<RolapMember>();
-        RolapMember member = rootMembers[0];
+        List<? extends Member> firstChildren = new ArrayList<Member>();
+        RolapMember member = (RolapMember) rootMembers.get(0);
         while (member != null) {
-            firstChildren.add(member);
+            ((List) firstChildren).add(member);
             pw.print("\t");
             print(member);
-            ArrayList<RolapMember> children = new ArrayList<RolapMember>();
+            ArrayList<? extends Member> children = new ArrayList<Member>();
             reader.getMemberChildren(member, children);
             if (children.isEmpty()) {
                 break;
@@ -151,9 +154,9 @@
             pw.print(", lead(5)=");
             print(leadMember);
             if (children.size() > 1) {
-                member = children.get(1);
+                member = (RolapMember) children.get(1);
             } else if (children.size() > 0) {
-                member = children.get(0);
+                member = (RolapMember) children.get(0);
             } else {
                 member = null;
             }
@@ -169,14 +172,14 @@
         }
         pw.print("Member(" + member.getUniqueName() + ")");
     }
-    private void print(RolapMember[] members)
+    private void print(List<? extends Member> members)
     {
         pw.print("{");
-        for (int i = 0; i < members.length; i++) {
+        for (int i = 0; i < members.size(); i++) {
             if (i > 0) {
                 pw.print(", ");
             }
-            print(members[i]);
+            print((RolapMember) members.get(i));
         }
         pw.print("}");
     }
Index: src/main/mondrian/rolap/RolapAggregationManager.java
===================================================================
--- src/main/mondrian/rolap/RolapAggregationManager.java	
+++ src/main/mondrian/rolap/RolapAggregationManager.java	
@@ -48,15 +48,15 @@
      * @param members Set of members which constrain the cell
      * @return Cell request, or null if the requst is unsatisfiable
      *
-     * @see #makeDrillThroughRequest(mondrian.olap.Member[], boolean)
+     * @see #makeDrillThroughRequest(mondrian.olap.List<Member>, boolean)
      */
-    public static CellRequest makeRequest(final Member[] members)
+    public static CellRequest makeRequest(final List<Member> members)
     {
-        if (!(members[0] instanceof RolapStoredMeasure)) {
+        if (!(members.get(0) instanceof RolapStoredMeasure)) {
             return null;
         }
 
-        final RolapStoredMeasure measure = (RolapStoredMeasure) members[0];
+        final RolapStoredMeasure measure = (RolapStoredMeasure) members.get(0);
         final RolapStar.Measure starMeasure =
             (RolapStar.Measure) measure.getStarMeasure();
         assert starMeasure != null;
@@ -66,8 +66,8 @@
         final Map<RolapLevel, RolapStar.Column> levelToColumnMap =
             star.getLevelToColumnMap(measure.getCube());
 
-        for (int i = 1; i < members.length; i++) {
-            RolapMember member = (RolapMember) members[i];
+        for (int i = 1; i < members.size(); i++) {
+            RolapMember member = (RolapMember) members.get(i);
             final RolapLevel level = member.getLevel();
             final boolean needToReturnNull =
                 level.getLevelReader().constrainRequest(
@@ -95,18 +95,18 @@
      *
      * @return Cell request, or null if the requst is unsatisfiable
      *
-     * @see #makeRequest(mondrian.olap.Member[])
+     * @see #makeRequest(mondrian.olap.List<Member>)
      */
     public static CellRequest makeDrillThroughRequest(
-        final Member[] members,
+        final List<Member> members,
         final boolean extendedContext)
     {
         boolean drillThrough = true;
-        if (!(members[0] instanceof RolapStoredMeasure)) {
+        if (!(members.get(0) instanceof RolapStoredMeasure)) {
             return null;
         }
 
-        final RolapStoredMeasure measure = (RolapStoredMeasure) members[0];
+        final RolapStoredMeasure measure = (RolapStoredMeasure) members.get(0);
         final RolapStar.Measure starMeasure =
             (RolapStar.Measure) measure.getStarMeasure();
         assert starMeasure != null;
@@ -119,8 +119,8 @@
         // Since 'request.extendedContext == false' is a well-worn code path,
         // we have moved the test outside the loop.
         if (extendedContext) {
-            for (int i = 1; i < members.length; i++) {
-                final RolapMember member = (RolapMember) members[i];
+            for (int i = 1; i < members.size(); i++) {
+                final RolapMember member = (RolapMember) members.get(i);
                 addNonConstrainingColumns(member, levelToColumnMap, request);
 
                 final RolapLevel level = member.getLevel();
@@ -132,8 +132,8 @@
                 }
             }
         } else {
-            for (int i = 1; i < members.length; i++) {
-                RolapMember member = (RolapMember) members[i];
+            for (int i = 1; i < members.size(); i++) {
+                RolapMember member = (RolapMember) members.get(i);
                 final RolapLevel level = member.getLevel();
                 final boolean needToReturnNull =
                     level.getLevelReader().constrainRequest(
@@ -202,7 +202,7 @@
     /**
      * Returns the value of a cell from an existing aggregation.
      */
-    public Object getCellFromCache(final Member[] members) {
+    public Object getCellFromCache(final List<Member> members) {
         final CellRequest request = makeRequest(members);
         return (request == null || request.isUnsatisfiable())
             // request out of bounds
@@ -225,11 +225,11 @@
         PinSet pinSet);
 
     private static Object getCellFromStar(
-        Member[] members,
+        List<Member> members,
         List<List<Member>> aggregationLists)
     {
         final CellRequest request = makeRequest(members);
-        final RolapStoredMeasure measure = (RolapStoredMeasure) members[0];
+        final RolapStoredMeasure measure = (RolapStoredMeasure) members.get(0);
         final RolapStar.Measure starMeasure =
             (RolapStar.Measure) measure.getStarMeasure();
 
@@ -340,7 +340,8 @@
         if (region instanceof CacheControlImpl.MemberCellRegion) {
             final CacheControlImpl.MemberCellRegion memberCellRegion =
                 (CacheControlImpl.MemberCellRegion) region;
-            final List<Member> memberList = memberCellRegion.getMemberList();
+            final List<? extends Member> memberList = 
+                    memberCellRegion.getMemberList();
             for (Member member : memberList) {
                 final RolapMember rolapMember = (RolapMember) member;
                 final RolapLevel level = rolapMember.getLevel();
@@ -380,7 +381,7 @@
         return new CellReader() {
             // implement CellReader
             public Object get(RolapEvaluator evaluator) {
-                Member[] members = evaluator.getMembers();
+                List<Member> members = evaluator.getMembers();
                 return getCellFromCache(members);
             }
 
@@ -391,7 +392,7 @@
             public Object getCompound(
                 RolapEvaluator evaluator, List<List<Member>> aggregationLists)
             {
-                Member[] members = evaluator.getMembers();
+                List<Member> members = evaluator.getMembers();
                 return getCellFromStar(members, aggregationLists);
             }
         };
Index: src/main/mondrian/rolap/RolapUtil.java
===================================================================
--- src/main/mondrian/rolap/RolapUtil.java	
+++ src/main/mondrian/rolap/RolapUtil.java	
@@ -37,7 +37,7 @@
 public class RolapUtil {
 
     static final Logger LOGGER = Logger.getLogger(RolapUtil.class);
-    static final RolapMember[] emptyMemberArray = new RolapMember[0];
+    static final List<Member> emptyMemberArray = Collections.emptyList();
     private static PrintWriter traceOut = null;
     private static boolean checkedTracing = false;
     private static boolean traceEnabled;
@@ -52,7 +52,7 @@
      * Hook to run when a query is executed.
      */
     static final ThreadLocal<ExecuteQueryHook> threadHooks =
-        new ThreadLocal<ExecuteQueryHook>();
+        new InheritableThreadLocal<ExecuteQueryHook>();
 
     /**
      * Special value represents a null key.
@@ -84,12 +84,6 @@
      */
     private static final Set<String> loadedDrivers = new HashSet<String>();
 
-    static RolapMember[] toArray(List<RolapMember> v) {
-        return v.isEmpty()
-            ? emptyMemberArray
-            : v.toArray(new RolapMember[v.size()]);
-    }
-
     static RolapMember lookupMember(
         MemberReader reader,
         List<Id.Segment> uniqueNameParts,
@@ -105,9 +99,9 @@
         // If this hierarchy has an 'all' member, we can omit it.
         // For example, '[Gender].[(All Gender)].[F]' can be abbreviated
         // '[Gender].[F]'.
-        final List<RolapMember> rootMembers = reader.getRootMembers();
+        final List<? extends Member> rootMembers = reader.getRootMembers();
         if (rootMembers.size() == 1) {
-            final RolapMember rootMember = rootMembers.get(0);
+            final RolapMember rootMember = (RolapMember) rootMembers.get(0);
             if (rootMember.isAll()) {
                 member =
                     lookupMemberInternal(
@@ -124,7 +118,7 @@
         boolean failIfNotFound)
     {
         for (Id.Segment segment : segments) {
-            List<RolapMember> children;
+            List<? extends Member> children;
             if (member == null) {
                 children = reader.getRootMembers();
             } else {
@@ -132,9 +126,9 @@
                 reader.getMemberChildren(member, children);
                 member = null;
             }
-            for (RolapMember child : children) {
+            for (Member child : children) {
                 if (child.getName().equals(segment.name)) {
-                    member = child;
+                    member = (RolapMember) child;
                     break;
                 }
             }
@@ -378,13 +372,9 @@
      * in the case of a BEFORE or AFTER search
      */
     public static Member findBestMemberMatch(
-        List<? extends Member> members,
-        RolapMember parent,
-        RolapLevel level,
-        Id.Segment searchName,
-        MatchType matchType,
-        boolean caseInsensitive)
-    {
+        List<? extends Member> members, RolapMember parent,
+        RolapLevel level, Id.Segment searchName, MatchType matchType,
+        boolean caseInsensitive) {
         // create a member corresponding to the member we're trying
         // to locate so we can use it to hierarchically compare against
         // the members array
Index: src/main/mondrian/rolap/RolapCell.java
===================================================================
--- src/main/mondrian/rolap/RolapCell.java	
+++ src/main/mondrian/rolap/RolapCell.java	
@@ -14,6 +14,7 @@
 import mondrian.rolap.agg.CellRequest;
 
 import java.sql.*;
+import java.util.*;
 
 /**
  * <code>RolapCell</code> implements {@link mondrian.olap.Cell} within a
@@ -60,7 +61,7 @@
      */
     public String getDrillThroughSQL(boolean extendedContext) {
         RolapAggregationManager aggMan = AggregationManager.instance();
-        final Member[] currentMembers = getMembers();
+        final List<Member> currentMembers = getMembers();
         CellRequest cellRequest =
             RolapAggregationManager.makeDrillThroughRequest(
                 currentMembers, extendedContext);
@@ -72,7 +73,7 @@
 
     public int getDrillThroughCount() {
         RolapAggregationManager aggMan = AggregationManager.instance();
-        final Member[] currentMembers = getMembers();
+        final List<Member> currentMembers = getMembers();
         CellRequest cellRequest =
             RolapAggregationManager.makeDrillThroughRequest(
                 currentMembers, false);
@@ -109,16 +110,16 @@
      */
     public boolean canDrillThrough() {
         // get current members
-        final Member[] currentMembers = getMembers();
+        final List<Member> currentMembers = getMembers();
         // First member is the measure, test if it is stored measure, return
         // true if it is, false if not.
-        return (currentMembers[0] instanceof RolapStoredMeasure);
+        return (currentMembers.get(0) instanceof RolapStoredMeasure);
     }
 
     private RolapEvaluator getEvaluator() {
         return result.getCellEvaluator(pos);
     }
-    private Member[] getMembers() {
+    private List<Member> getMembers() {
         return result.getCellMembers(pos);
     }
 
Index: src/main/mondrian/rolap/CacheMemberReader.java
===================================================================
--- src/main/mondrian/rolap/CacheMemberReader.java	
+++ src/main/mondrian/rolap/CacheMemberReader.java	
@@ -18,6 +18,7 @@
 import java.util.Map;
 
 import mondrian.olap.Id;
+import mondrian.olap.Member;
 import mondrian.olap.Util;
 import mondrian.rolap.TupleReader.MemberBuilder;
 import mondrian.rolap.sql.TupleConstraint;
@@ -37,7 +38,7 @@
  */
 class CacheMemberReader implements MemberReader, MemberCache {
     private final MemberSource source;
-    private final RolapMember[] members;
+    private final List<? extends Member> members;
     /** Maps a {@link MemberKey} to a {@link RolapMember}. */
     private final Map<Object, RolapMember> mapKeyToMember;
 
@@ -49,8 +50,8 @@
         }
         this.mapKeyToMember = new HashMap<Object, RolapMember>();
         this.members = source.getMembers();
-        for (int i = 0; i < members.length; i++) {
-            members[i].setOrdinal(i);
+        for (int i = 0; i < members.size(); i++) {
+            ((RolapMember) members.get(i)).setOrdinal(i);
         }
     }
 
@@ -66,7 +67,7 @@
     }
 
     // implement MemberReader
-    public RolapMember[] getMembers() {
+    public List<? extends Member> getMembers() {
         return members;
     }
 
@@ -90,10 +91,9 @@
 
     // don't need to implement this MemberCache method because we're never
     // used in a context where it is needed
-    public void putChildren(
-        RolapMember member,
-        MemberChildrenConstraint constraint,
-        List<RolapMember> children)
+    public void putChildren(final RolapMember member,
+            final MemberChildrenConstraint constraint,
+            final List<? extends Member> children)
     {
         throw new UnsupportedOperationException();
     }
@@ -109,7 +109,8 @@
 
     // don't need to implement this MemberCache method because we're never
     // used in a context where it is needed
-    public List getLevelMembersFromCache(RolapLevel level, TupleConstraint constraint) {
+    public List getLevelMembersFromCache(final RolapLevel level, 
+            final TupleConstraint constraint) {
         return null;
     }
 
@@ -118,9 +119,9 @@
         return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound);
     }
 
-    public List<RolapMember> getRootMembers() {
-        List<RolapMember> list = new ArrayList<RolapMember>();
-        for (RolapMember member : members) {
+    public List<? extends Member> getRootMembers() {
+        List<Member> list = new ArrayList<Member>();
+        for (Member member : members) {
             if (member.getParentUniqueName() == null) {
                 list.add(member);
             }
@@ -128,116 +129,98 @@
         return list;
     }
 
-    public List<RolapMember> getMembersInLevel(
-        RolapLevel level,
-        int startOrdinal,
-        int endOrdinal)
-    {
-        List<RolapMember> list = new ArrayList<RolapMember>();
+    public List<? extends Member> getMembersInLevel(final RolapLevel level,
+            final int startOrdinal, final int endOrdinal) {
+        List<Member> list = new ArrayList<Member>();
         int levelDepth = level.getDepth();
-        for (RolapMember member : members) {
+        for (Member member : members) {
             if ((member.getLevel().getDepth() == levelDepth) &&
                 (startOrdinal <= member.getOrdinal()) &&
                 (member.getOrdinal() < endOrdinal)) {
-
                 list.add(member);
             }
         }
         return list;
     }
 
-    public List<RolapMember> getMembersInLevel(
-        RolapLevel level,
-        int startOrdinal,
-        int endOrdinal,
-        TupleConstraint constraint)
-    {
+    public List<? extends Member> getMembersInLevel(final RolapLevel level,
+            final int startOrdinal, final int endOrdinal, 
+            final TupleConstraint constraint) {
         return getMembersInLevel(level, startOrdinal, endOrdinal);
     }
 
-    public void getMemberChildren(
-        RolapMember parentMember,
-        List<RolapMember> children)
-    {
-        for (RolapMember member : members) {
+    public void getMemberChildren(final Member parentMember,
+            final List<? extends Member> children) {
+        for (Member member : members) {
             if (member.getParentMember() == parentMember) {
-                children.add(member);
+                ((List) children).add(member);
             }
         }
     }
 
-    public void getMemberChildren(
-        RolapMember member,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+    public void getMemberChildren(final Member member,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         getMemberChildren(member, children);
     }
 
-    public void getMemberChildren(
-        List<RolapMember> parentMembers,
-        List<RolapMember> children) {
-        for (RolapMember member : members) {
+    public void getMemberChildren(final List<? extends Member> parentMembers,
+            final List<? extends Member> children) {
+        for (Member member : members) {
             if (parentMembers.contains(member.getParentMember())) {
-                children.add(member);
+                ((List) children).add(member);
             }
         }
     }
 
-    public void getMemberChildren(
-        List<RolapMember> parentMembers,
-        List<RolapMember> children,
-        MemberChildrenConstraint constraint)
-    {
+    public void getMemberChildren(final List<? extends Member> parentMembers,
+            final List<? extends Member> children, 
+            final MemberChildrenConstraint constraint) {
         getMemberChildren(parentMembers, children);
     }
 
     public RolapMember getLeadMember(RolapMember member, int n) {
         if (n >= 0) {
-            for (int ordinal = member.getOrdinal(); ordinal < members.length;
-                 ordinal++) {
-                if ((members[ordinal].getLevel() == member.getLevel()) &&
-                    (n-- == 0)) {
-
-                    return members[ordinal];
+            for (int ordinal = member.getOrdinal(); ordinal < members.size();
+                        ordinal++) {
+                if ((members.get(ordinal).getLevel() == member.getLevel()) &&
+                            (n-- == 0)) {
+                    return (RolapMember) members.get(ordinal);
                 }
             }
             return (RolapMember) member.getHierarchy().getNullMember();
-
         } else {
             for (int ordinal = member.getOrdinal(); ordinal >= 0; ordinal--) {
-                if ((members[ordinal].getLevel() == member.getLevel()) &&
+                if ((members.get(ordinal).getLevel() == member.getLevel()) &&
                     (n++ == 0)) {
-                    return members[ordinal];
+                    return (RolapMember) members.get(ordinal);
                 }
             }
             return (RolapMember) member.getHierarchy().getNullMember();
         }
     }
 
-    public void getMemberRange(
-        RolapLevel level,
-        RolapMember startMember,
-        RolapMember endMember,
-        List<RolapMember> list)
-    {
+    public void getMemberRange(final RolapLevel level, 
+            final RolapMember startMember, final RolapMember endMember,
+            final List<? extends Member> list) {
         Util.assertPrecondition(startMember != null, "startMember != null");
         Util.assertPrecondition(endMember != null, "endMember != null");
         Util.assertPrecondition(startMember.getLevel() == endMember.getLevel(),
                 "startMember.getLevel() == endMember.getLevel()");
 
-        for (int i = startMember.getOrdinal(); i <= endMember.getOrdinal(); i++) {
-            if (members[i].getLevel() == endMember.getLevel()) {
-                list.add(members[i]);
+        for (int i = startMember.getOrdinal(); i<=endMember.getOrdinal(); i++) {
+            if (members.get(i).getLevel() == endMember.getLevel()) {
+                ((List) list).add(members.get(i));
             }
         }
     }
 
     public int getMemberCount() {
-        return members.length;
+        return members.size();
     }
 
-    public int compare(RolapMember m1, RolapMember m2, boolean siblingsAreEqual) {
+    public int compare(final RolapMember m1, final RolapMember m2, 
+            boolean siblingsAreEqual) {
         if (m1 == m2) {
             return 0;
         }
@@ -245,8 +228,8 @@
             (m1.getParentMember() == m2.getParentMember())) {
             return 0;
         }
-        Util.assertTrue(members[m1.getOrdinal()] == m1);
-        Util.assertTrue(members[m2.getOrdinal()] == m2);
+        Util.assertTrue(members.get(m1.getOrdinal()) == m1);
+        Util.assertTrue(members.get(m2.getOrdinal()) == m2);
 
         return (m1.getOrdinal() < m2.getOrdinal()) ? -1 : 1;
     }
Index: src/main/mondrian/rolap/RolapSchemaReader.java
===================================================================
--- src/main/mondrian/rolap/RolapSchemaReader.java	
+++ src/main/mondrian/rolap/RolapSchemaReader.java	
@@ -59,12 +59,12 @@
         return role;
     }
 
-    public Member[] getHierarchyRootMembers(Hierarchy hierarchy) {
-        final Role.HierarchyAccess hierarchyAccess = role.getAccessDetails(hierarchy);
+    public List<? extends Member> getHierarchyRootMembers(Hierarchy hierarchy) {
+        final Role.HierarchyAccess hierarchyAccess = 
+                role.getAccessDetails(hierarchy);
         final Level[] levels = hierarchy.getLevels();
         final Level firstLevel = (hierarchyAccess == null)
-            ? levels[0]
-            : levels[hierarchyAccess.getTopLevelDepth()];
+                ? levels[0] : levels[hierarchyAccess.getTopLevelDepth()];
         return getLevelMembers(firstLevel, true);
     }
 
@@ -131,25 +131,26 @@
     }
 
 
-    public Member[] getMemberChildren(Member member) {
+    public List<? extends Member> getMemberChildren(Member member) {
         return getMemberChildren(member, null);
     }
 
-    public Member[] getMemberChildren(Member member, Evaluator context) {
+    public List<? extends Member> getMemberChildren(
+            Member member, Evaluator context) {
         MemberChildrenConstraint constraint =
                 sqlConstraintFactory.getMemberChildrenConstraint(context);
-        List<RolapMember> memberList =
-            internalGetMemberChildren(member, constraint);
-        return memberList.toArray(new Member[memberList.size()]);
+        List<? extends Member> memberList = 
+                internalGetMemberChildren(member, constraint);
+        return memberList;
     }
 
-    private List<RolapMember> internalGetMemberChildren(
+    private List<Member> internalGetMemberChildren(
             Member member, MemberChildrenConstraint constraint) {
-        List<RolapMember> children = new ArrayList<RolapMember>();
+        List<Member> children = new ArrayList<Member>();
         final Hierarchy hierarchy = member.getHierarchy();
         final MemberReader memberReader = getMemberReader(hierarchy);
-        memberReader.getMemberChildren(
-                (RolapMember) member, children, constraint);
+        memberReader.getMemberChildren((RolapMember) member, 
+                children, constraint);
         return children;
     }
 
@@ -213,7 +214,7 @@
             if (materialize) {
                 // Either the approximate row count hasn't been set,
                 // or they want the precise row count.
-                rowCount = getLevelMembers(level, false).length;
+                rowCount = getLevelMembers(level, false).size();
                 // Cache it for future.
                 ((RolapLevel) level).setApproxRowCount(rowCount);
             }
@@ -221,24 +222,23 @@
         return rowCount;
     }
 
-    public Member[] getMemberChildren(Member[] members) {
+    public List<? extends Member> getMemberChildren(
+            final List<? extends Member> members) {
         return getMemberChildren(members, null);
     }
 
-    public Member[] getMemberChildren(Member[] members, Evaluator context) {
-        if (members.length == 0) {
+    public List<? extends Member> getMemberChildren(
+            final List<? extends Member> members, final Evaluator context) {
+        if (members.size() == 0) {
             return RolapUtil.emptyMemberArray;
         } else {
             MemberChildrenConstraint constraint =
                     sqlConstraintFactory.getMemberChildrenConstraint(context);
-            final Hierarchy hierarchy = members[0].getHierarchy();
+            final Hierarchy hierarchy = members.get(0).getHierarchy();
             final MemberReader memberReader = getMemberReader(hierarchy);
             List<RolapMember> children = new ArrayList<RolapMember>();
-            memberReader.getMemberChildren(
-                (List<RolapMember>) (List) Arrays.asList(members),
-                children,
-                constraint);
-            return RolapUtil.toArray(children);
+            memberReader.getMemberChildren(members, children, constraint);
+            return children;
         }
     }
 
@@ -319,13 +319,14 @@
                     sqlConstraintFactory.getChildByNameConstraint(
                         (RolapMember)parent, childName) :
                     sqlConstraintFactory.getMemberChildrenConstraint(null);
-            List<RolapMember> children = internalGetMemberChildren(parent, constraint);
+            final List<? extends Member> children = 
+                    internalGetMemberChildren(parent, constraint);
             if (children.size() > 0) {
                 return
                     RolapUtil.findBestMemberMatch(
                         children,
                         (RolapMember) parent,
-                        children.get(0).getLevel(),
+                        (RolapLevel) children.get(0).getLevel(),
                         childName,
                         matchType,
                         true);
@@ -362,25 +363,30 @@
         return memberReader.getLeadMember((RolapMember) member, n);
     }
 
-    public Member[] getLevelMembers(Level level, boolean includeCalculated) {
-        return getLevelMembers(level, null);
+    public List<? extends Member> getLevelMembers(Level level, 
+            boolean includeCalculated) {
+        return getLevelMembers(level,null);
     }
 
-    public Member[] getLevelMembers(Level level, Evaluator context) {
+    public List<? extends Member> getLevelMembers(
+            final Level level, final Evaluator context) {
         TupleConstraint constraint =
                 sqlConstraintFactory.getLevelMembersConstraint(
                     context,
                     new Level [] { level });
         final MemberReader memberReader = getMemberReader(level.getHierarchy());
-        final List<RolapMember> membersInLevel =
-            memberReader.getMembersInLevel(
-                (RolapLevel) level, 0, Integer.MAX_VALUE, constraint);
-        return RolapUtil.toArray(membersInLevel);
+//System.out.println("RolapSchemaReader: 378, copia de array list");
+        List<? extends Member> membersInLevel = memberReader
+                .getMembersInLevel((RolapLevel) level, 0, 
+                                    Integer.MAX_VALUE, constraint);
+
+        return membersInLevel;
     }
 
     public Level[] getHierarchyLevels(Hierarchy hierarchy) {
         assert hierarchy != null;
-        final Role.HierarchyAccess hierarchyAccess = role.getAccessDetails(hierarchy);
+        final Role.HierarchyAccess hierarchyAccess = 
+                role.getAccessDetails(hierarchy);
         final Level[] levels = hierarchy.getLevels();
         if (hierarchyAccess == null) {
             return levels;
@@ -389,22 +395,27 @@
         Level bottomLevel = levels[hierarchyAccess.getBottomLevelDepth()];
         final int levelCount = bottomLevel.getDepth() - topLevel.getDepth() + 1;
         Level[] restrictedLevels = new Level[levelCount];
-        System.arraycopy(levels, topLevel.getDepth(), restrictedLevels, 0, levelCount);
-        Util.assertPostcondition(restrictedLevels.length >= 1, "return.length >= 1");
+        System.arraycopy(levels, topLevel.getDepth(), 
+                restrictedLevels, 0, levelCount);
+        Util.assertPostcondition(restrictedLevels.length >= 1, 
+                "return.length >= 1");
         return restrictedLevels;
     }
 
     public Member getHierarchyDefaultMember(Hierarchy hierarchy) {
         assert hierarchy != null;
         Member defaultMember = hierarchy.getDefaultMember();
-        // If the whole hierarchy is inaccessible, return the intrinsic default member.
+        // If the whole hierarchy is inaccessible, return the intrinsic 
+        // default member.
         // This is important to construct a evaluator.
         if (role.getAccess(hierarchy) != Access.NONE) {
             // If there's not an accessible intrinsic default member,
             // lookup the top accessible level's first accessible member.
             if (defaultMember == null || (!role.canAccess(defaultMember))) {
-                Member[] rootMembers = this.getHierarchyRootMembers(hierarchy);
-                defaultMember = (rootMembers.length > 0) ? rootMembers[0] : null;
+                List<? extends Member> rootMembers = 
+                        this.getHierarchyRootMembers(hierarchy);
+                defaultMember = (rootMembers.size()>0) 
+                        ? rootMembers.get(0) : null;
             }
         }
         return defaultMember;
@@ -417,7 +428,7 @@
             // the same level.
             //
             // todo: More efficient implementation
-            return getMemberChildren(member).length > 0;
+            return getMemberChildren(member).size() > 0;
         } else {
             // This is a regular level. It has children iff there is a lower
             // level.
Index: src/main/mondrian/rolap/aggmatcher/DefaultDef.java
===================================================================
--- src/main/mondrian/rolap/aggmatcher/DefaultDef.java	
+++ src/main/mondrian/rolap/aggmatcher/DefaultDef.java	
@@ -1,2667 +0,0 @@
-/*
-// This java file was automatically generated
-// from XOM model 'aggregates'
-// on Tue Mar 06 01:13:59 PST 2007
-// Do not edit this file by hand.
-*/
-
-package mondrian.rolap.aggmatcher;
-/**
- * This is the XML model for defining default aggregate table recognition
- * and level/measure mapping.
- * Revision is $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/DefaultRulesSchema.xml#9 $
- * <p>This class was generated from XOM model 'aggregates' on Tue Mar 06 01:13:59 PST 2007
- */
-public class DefaultDef {
-
-	public static java.lang.Class getXMLDefClass()
-	{
-		return DefaultDef.class;
-	}
-
-	public static String[] _elements = {
-		"AggRules",
-		"Base",
-		"CaseMatcher",
-		"NameMatcher",
-		"FactCountMatch",
-		"ForeignKeyMatch",
-		"TableMatch",
-		"Mapper",
-		"Regex",
-		"RegexMapper",
-		"Ref",
-		"LevelMapRef",
-		"MeasureMapRef",
-		"IgnoreMapRef",
-		"FactCountMatchRef",
-		"ForeignKeyMatchRef",
-		"TableMatchRef",
-		"LevelMap",
-		"MeasureMap",
-		"IgnoreMap",
-		"AggRule"
-	};
-
-	/**
-	 * The set of "named" rules for matching aggregate tables.
-	 * Only one rule can be applied to a given connection. In
-	 * addition, one rule must be set as the default - this rule
-	 * is always the choice when not selecting by name.
-	 * It is very important that the AggRules validate method is called
-	 * prior to using any of the object.
-	 */
-	public static class AggRules extends org.eigenbase.xom.ElementDef
-	{
-		public AggRules()
-		{
-		}
-
-		public AggRules(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				org.eigenbase.xom.NodeDef[] _tempArray = null;
-				_tempArray = _tempArray;
-				tag = (String)_parser.getAttribute("tag", "String", null, null, true);
-				_tempArray = _parser.getArray(TableMatch.class, 0, 0);
-				tableMatches = new TableMatch[_tempArray.length];
-				for(int _i=0; _i<tableMatches.length; _i++)
-					tableMatches[_i] = (TableMatch)_tempArray[_i];
-				_tempArray = _parser.getArray(FactCountMatch.class, 0, 0);
-				factCountMatches = new FactCountMatch[_tempArray.length];
-				for(int _i=0; _i<factCountMatches.length; _i++)
-					factCountMatches[_i] = (FactCountMatch)_tempArray[_i];
-				_tempArray = _parser.getArray(ForeignKeyMatch.class, 0, 0);
-				foreignKeyMatches = new ForeignKeyMatch[_tempArray.length];
-				for(int _i=0; _i<foreignKeyMatches.length; _i++)
-					foreignKeyMatches[_i] = (ForeignKeyMatch)_tempArray[_i];
-				_tempArray = _parser.getArray(LevelMap.class, 0, 0);
-				levelMaps = new LevelMap[_tempArray.length];
-				for(int _i=0; _i<levelMaps.length; _i++)
-					levelMaps[_i] = (LevelMap)_tempArray[_i];
-				_tempArray = _parser.getArray(MeasureMap.class, 0, 0);
-				measureMaps = new MeasureMap[_tempArray.length];
-				for(int _i=0; _i<measureMaps.length; _i++)
-					measureMaps[_i] = (MeasureMap)_tempArray[_i];
-				_tempArray = _parser.getArray(IgnoreMap.class, 0, 0);
-				ignoreMaps = new IgnoreMap[_tempArray.length];
-				for(int _i=0; _i<ignoreMaps.length; _i++)
-					ignoreMaps[_i] = (IgnoreMap)_tempArray[_i];
-				_tempArray = _parser.getArray(AggRule.class, 1, 0);
-				aggRules = new AggRule[_tempArray.length];
-				for(int _i=0; _i<aggRules.length; _i++)
-					aggRules[_i] = (AggRule)_tempArray[_i];
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String tag;  // required attribute
-
-		/**
-		 * All shared TableMatches.
-		 */
-		public TableMatch[] tableMatches;  //optional array
-		/**
-		 * All shared FactCountMatches.
-		 */
-		public FactCountMatch[] factCountMatches;  //optional array
-		/**
-		 * All shared ForeignKeyMatches.
-		 */
-		public ForeignKeyMatch[] foreignKeyMatches;  //optional array
-		/**
-		 * All shared LevelMap.
-		 */
-		public LevelMap[] levelMaps;  //optional array
-		/**
-		 * All shared MeasureMap.
-		 */
-		public MeasureMap[] measureMaps;  //optional array
-		/**
-		 * All shared IgnoreMap.
-		 */
-		public IgnoreMap[] ignoreMaps;  //optional array
-		/**
-		 * All AggRules (at least one).
-		 * Also, one of them must be marked with default=true.
-		 */
-		public AggRule[] aggRules;  //min 1
-
-		public String getName()
-		{
-			return "AggRules";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "tag", tag, _indent+1);
-			displayElementArray(_out, "tableMatches", tableMatches, _indent+1);
-			displayElementArray(_out, "factCountMatches", factCountMatches, _indent+1);
-			displayElementArray(_out, "foreignKeyMatches", foreignKeyMatches, _indent+1);
-			displayElementArray(_out, "levelMaps", levelMaps, _indent+1);
-			displayElementArray(_out, "measureMaps", measureMaps, _indent+1);
-			displayElementArray(_out, "ignoreMaps", ignoreMaps, _indent+1);
-			displayElementArray(_out, "aggRules", aggRules, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("AggRules", new org.eigenbase.xom.XMLAttrVector()
-				.add("tag", tag)
-				);
-			displayXMLElementArray(_out, tableMatches);
-			displayXMLElementArray(_out, factCountMatches);
-			displayXMLElementArray(_out, foreignKeyMatches);
-			displayXMLElementArray(_out, levelMaps);
-			displayXMLElementArray(_out, measureMaps);
-			displayXMLElementArray(_out, ignoreMaps);
-			displayXMLElementArray(_out, aggRules);
-			_out.endTag("AggRules");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			AggRules _cother = (AggRules)_other;
-			_diff = _diff && displayAttributeDiff("tag", tag, _cother.tag, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("tableMatches", tableMatches, _cother.tableMatches, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("factCountMatches", factCountMatches, _cother.factCountMatches, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("foreignKeyMatches", foreignKeyMatches, _cother.foreignKeyMatches, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("levelMaps", levelMaps, _cother.levelMaps, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("measureMaps", measureMaps, _cother.measureMaps, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("ignoreMaps", ignoreMaps, _cother.ignoreMaps, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("aggRules", aggRules, _cother.aggRules, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-private static final org.apache.log4j.Logger LOGGER =
-                org.apache.log4j.Logger.getLogger(DefaultDef.class);
-
-            protected static org.apache.log4j.Logger getLogger() {
-                return LOGGER;
-            }
-
-            public String getTag() {
-                return tag;
-            }
-
-            public AggRule getAggRule(String tag) {
-                for (int i = 0; i < aggRules.length; i++) {
-                    AggRule aggRule = aggRules[i];
-                    if (aggRule.isEnabled() && aggRule.getTag().equals(tag)) {
-                        return aggRule;
-                    }
-                }
-                return null;
-            }
-
-            public void validate(final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    validate(factCountMatches, msgRecorder);
-                    validate(tableMatches, msgRecorder);
-                    validate(levelMaps, msgRecorder);
-                    validate(measureMaps, msgRecorder);
-                    validate(ignoreMaps, msgRecorder);
-                    validate(aggRules, msgRecorder);
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            private void validate(final Base[] bases,
-                                  final mondrian.recorder.MessageRecorder msgRecorder) {
-                for (int i = 0; i < bases.length; i++) {
-                    Base base = bases[i];
-                    if (base.isEnabled()) {
-                        base.validate(this, msgRecorder);
-                    }
-                }
-            }
-
-            public boolean hasIgnoreMap(String id) {
-                return (lookupIgnoreMap(id) != null);
-            }
-            public IgnoreMap lookupIgnoreMap(String id) {
-                return (IgnoreMap) lookupBase(id, ignoreMaps);
-            }
-
-            public boolean hasFactCountMatch(String id) {
-                return (lookupFactCountMatch(id) != null);
-            }
-            public FactCountMatch lookupFactCountMatch(String id) {
-                return (FactCountMatch) lookupBase(id, factCountMatches);
-            }
-
-            public boolean hasForeignKeyMatch(String id) {
-                return (lookupForeignKeyMatch(id) != null);
-            }
-            public ForeignKeyMatch lookupForeignKeyMatch(String id) {
-                return (ForeignKeyMatch) lookupBase(id, foreignKeyMatches);
-            }
-
-            public boolean hasTableMatch(String id) {
-                return (lookupTableMatch(id) != null);
-            }
-            public TableMatch lookupTableMatch(String id) {
-                return (TableMatch) lookupBase(id, tableMatches);
-            }
-
-            public boolean hasLevelMap(String id) {
-                return (lookupLevelMap(id) != null);
-            }
-            public LevelMap lookupLevelMap(String id) {
-                return (LevelMap) lookupBase(id, levelMaps);
-            }
-
-            public boolean hasMeasureMap(String id) {
-                return (lookupMeasureMap(id) != null);
-            }
-            public MeasureMap lookupMeasureMap(String id) {
-                return (MeasureMap) lookupBase(id, measureMaps);
-            }
-
-            public boolean hasAggRule(String id) {
-                return (lookupAggRule(id) != null);
-            }
-            public AggRule lookupAggRule(String id) {
-                return (AggRule) lookupBase(id, aggRules);
-            }
-
-            private Base lookupBase(String tag, Base[] bases) {
-                for (int i = 0; i < bases.length; i++) {
-                    Base base = bases[i];
-                    if (base.isEnabled() && base.getTag().equals(tag)) {
-                        return base;
-                    }
-                }
-                return null;
-            }
-
-            public IgnoreMap[] getIgnoreMaps() {
-                return ignoreMaps;
-            }
-            public FactCountMatch[] getFactCountMatches() {
-                return factCountMatches;
-            }
-            public ForeignKeyMatch[] getForeignKeyMatches() {
-                return foreignKeyMatches;
-            }
-            public TableMatch[] getTableMatches() {
-                return tableMatches;
-            }
-            public LevelMap[] getLevelMaps() {
-                return levelMaps;
-            }
-            public MeasureMap[] getMeasureMaps() {
-                return measureMaps;
-            }
-            public AggRule[] getAggRules() {
-                return aggRules;
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * Base is the base class for all of the elements.
-	 * All elements can be enabled or not, have a tag, and
-	 * can be validated.
-	 */
-	public static abstract class Base extends org.eigenbase.xom.ElementDef
-	{
-		public Base()
-		{
-		}
-
-		public Base(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public Boolean enabled;  // attribute default: true
-
-
-		public String getName()
-		{
-			return "Base";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%Base;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("enabled", enabled)
-				);
-			_out.endTag("(%Base;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			Base _cother = (Base)_other;
-			_diff = _diff && displayAttributeDiff("enabled", enabled, _cother.enabled, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public boolean isEnabled() {
-                return enabled.booleanValue();
-            }
-            protected abstract String getTag();
-            public abstract void validate(final AggRules rules,
-                                          final mondrian.recorder.MessageRecorder msgRecorder);
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is a base class for all elements that can match strings
-	 * where the case of the string is important. In addition,
-	 * it has an id which services as its tag.
-	 */
-	public static abstract class CaseMatcher extends Base
-	{
-		public CaseMatcher()
-		{
-		}
-
-		public CaseMatcher(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String id;  // required attribute
-		/** Allowable values for {@link #charcase}. */
-		public static final String[] _charcase_values = {"ignore", "exact", "upper", "lower"};
-		public String charcase;  // attribute default: ignore
-
-
-		public String getName()
-		{
-			return "CaseMatcher";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%CaseMatcher;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("(%CaseMatcher;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			CaseMatcher _cother = (CaseMatcher)_other;
-			_diff = _diff && displayAttributeDiff("id", id, _cother.id, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("charcase", charcase, _cother.charcase, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                // empty
-            }
-            protected String getTag() {
-                return getId();
-            }
-            public String getId() {
-                return id;
-            }
-            public String getCharCase() {
-                return charcase;
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * A NameMatcher is a CaseMatcher that prepends and appends
-	 * regular expressions to a given string as part of creating
-	 * the matching regular expression. Both the pre/post
-	 * regular expression can be null in which case matches are
-	 * applied simply against the name (modulo case considerations).
-	 * The purpose of this class is to allow aggregate tables to
-	 * be identified when their table names are formed by placing
-	 * text before and/or after the base fact table name.
-	 */
-	public static abstract class NameMatcher extends CaseMatcher
-	{
-		public NameMatcher()
-		{
-		}
-
-		public NameMatcher(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				pretemplate = (String)_parser.getAttribute("pretemplate", "String", null, null, false);
-				posttemplate = (String)_parser.getAttribute("posttemplate", "String", null, null, false);
-				basename = (String)_parser.getAttribute("basename", "String", null, null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String pretemplate;  // optional attribute
-		public String posttemplate;  // optional attribute
-		public String basename;  // optional attribute
-
-
-		public String getName()
-		{
-			return "NameMatcher";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "pretemplate", pretemplate, _indent+1);
-			displayAttribute(_out, "posttemplate", posttemplate, _indent+1);
-			displayAttribute(_out, "basename", basename, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%NameMatcher;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("pretemplate", pretemplate)
-				.add("posttemplate", posttemplate)
-				.add("basename", basename)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("(%NameMatcher;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			NameMatcher _cother = (NameMatcher)_other;
-			_diff = _diff && displayAttributeDiff("pretemplate", pretemplate, _cother.pretemplate, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("posttemplate", posttemplate, _cother.posttemplate, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("basename", basename, _cother.basename, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-java.util.regex.Pattern baseNamePattern = null;
-            public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    super.validate(rules, msgRecorder);
-
-                    if (basename != null) {
-                        baseNamePattern =
-                            java.util.regex.Pattern.compile(basename);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-
-            /**
-             * Generates a regular expression string by prepending and
-             * appending regular expression to the parameter tableName.
-             *
-             * @param name Table name
-             * @return regular expression
-             */
-            public String getRegex(final String name) {
-                StringBuilder buf = new StringBuilder();
-                if (pretemplate != null) {
-                    buf.append(pretemplate);
-                }
-                if (name != null) {
-                    String n = name;
-                    if (baseNamePattern != null) {
-                        java.util.regex.Matcher matcher =
-                            baseNamePattern.matcher(name);
-                        if (matcher.matches() && matcher.groupCount() > 0) {
-                            n = matcher.group(1);
-
-                        } else {
-                            if (AggRules.getLogger().isDebugEnabled()) {
-                                StringBuilder bf = new StringBuilder(64);
-                                bf.append(getName());
-                                bf.append(".getRegex: for name \"");
-                                bf.append(name);
-                                bf.append("\" regex is null because basename \"");
-                                bf.append(basename);
-                                bf.append("\" is not matched.");
-
-                                String msg = bf.toString();
-                                AggRules.getLogger().debug(msg);
-                            }
-                            // If the table name does not match the basename
-                            // pattern, then return null for regex.
-                            return null;
-                        }
-                    }
-                    buf.append(n);
-                }
-                if (posttemplate != null) {
-                    buf.append(posttemplate);
-                }
-
-                String regex = buf.toString();
-
-                if (AggRules.getLogger().isDebugEnabled()) {
-                    StringBuilder bf = new StringBuilder(64);
-                    bf.append(getName());
-                    bf.append(".getRegex: for name \"");
-                    bf.append(name);
-                    bf.append("\" regex is \"");
-                    bf.append(regex);
-                    bf.append('"');
-
-                    String msg = bf.toString();
-                    AggRules.getLogger().debug(msg);
-                }
-                return regex;
-            }
-
-            protected Recognizer.Matcher getMatcher(String name) {
-
-                final String charcase = getCharCase();
-                final String regex;
-                int flag = 0;
-
-                if (charcase.equals("ignore")) {
-                    // the case of name does not matter
-                    // since the Pattern will be create to ignore case
-                    regex = getRegex(name);
-
-                    flag = java.util.regex.Pattern.CASE_INSENSITIVE;
-
-                } else if (charcase.equals("exact")) {
-                    // the case of name is not changed
-                    // since we are interested in exact case matching
-                    regex = getRegex(name);
-
-                } else if (charcase.equals("upper")) {
-                    // convert name to upper case
-                    regex = getRegex(name.toUpperCase());
-
-                } else {
-                    // lower
-                    // convert name to lower case
-                    regex = getRegex(name.toLowerCase());
-
-                }
-                // If regex is null, then return a matcher that matches nothing
-                if (regex == null) {
-                    return new Recognizer.Matcher() {
-                        public boolean matches(String name) {
-                            return false;
-                        }
-                    };
-                }
-
-                final java.util.regex.Pattern pattern =
-                        java.util.regex.Pattern.compile(regex, flag);
-
-                return new Recognizer.Matcher() {
-                    public boolean matches(String name) {
-                        boolean b = pattern.matcher(name).matches();
-                        if (AggRules.getLogger().isDebugEnabled()) {
-                            debug(name);
-                        }
-                        return b;
-                    }
-                    private void debug(String name) {
-                        StringBuilder bf = new StringBuilder(64);
-                        bf.append(NameMatcher.this.getName());
-                        bf.append(".Matcher.matches:");
-                        bf.append(" name \"");
-                        bf.append(name);
-                        bf.append("\" pattern \"");
-                        bf.append(pattern.pattern());
-                        bf.append("\"");
-                        if ((pattern.flags() &
-                            java.util.regex.Pattern.CASE_INSENSITIVE) != 0) {
-                            bf.append(" case_insensitive");
-                        }
-
-                        String msg = bf.toString();
-                        AggRules.getLogger().debug(msg);
-                    }
-                };
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is used to identify the "fact_count" column in an aggregate
-	 * table. It allows one to match using regular exprssions.
-	 * The default is that the name of the fact count colum is simply
-	 * the string "fact_count".
-	 */
-	public static class FactCountMatch extends NameMatcher
-	{
-		public FactCountMatch()
-		{
-		}
-
-		public FactCountMatch(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				factCountName = (String)_parser.getAttribute("factCountName", "String", "fact_count", null, true);
-				pretemplate = (String)_parser.getAttribute("pretemplate", "String", null, null, false);
-				posttemplate = (String)_parser.getAttribute("posttemplate", "String", null, null, false);
-				basename = (String)_parser.getAttribute("basename", "String", null, null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String factCountName;  // attribute default: fact_count
-
-
-		public String getName()
-		{
-			return "FactCountMatch";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "factCountName", factCountName, _indent+1);
-			displayAttribute(_out, "pretemplate", pretemplate, _indent+1);
-			displayAttribute(_out, "posttemplate", posttemplate, _indent+1);
-			displayAttribute(_out, "basename", basename, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("FactCountMatch", new org.eigenbase.xom.XMLAttrVector()
-				.add("factCountName", factCountName)
-				.add("pretemplate", pretemplate)
-				.add("posttemplate", posttemplate)
-				.add("basename", basename)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("FactCountMatch");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			FactCountMatch _cother = (FactCountMatch)_other;
-			_diff = _diff && displayAttributeDiff("factCountName", factCountName, _cother.factCountName, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    super.validate(rules, msgRecorder);
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            public Recognizer.Matcher getMatcher() {
-                return super.getMatcher(factCountName);
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is used to identify foreign key columns in a candidate
-	 * aggregate table given the name of a foreign key column of the
-	 * base fact table. This allows such foreign keys to be identified
-	 * by using a regular exprsssion. The default is to simply
-	 * match the base fact table's foreign key column name.
-	 */
-	public static class ForeignKeyMatch extends NameMatcher
-	{
-		public ForeignKeyMatch()
-		{
-		}
-
-		public ForeignKeyMatch(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				pretemplate = (String)_parser.getAttribute("pretemplate", "String", null, null, false);
-				posttemplate = (String)_parser.getAttribute("posttemplate", "String", null, null, false);
-				basename = (String)_parser.getAttribute("basename", "String", null, null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "ForeignKeyMatch";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "pretemplate", pretemplate, _indent+1);
-			displayAttribute(_out, "posttemplate", posttemplate, _indent+1);
-			displayAttribute(_out, "basename", basename, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("ForeignKeyMatch", new org.eigenbase.xom.XMLAttrVector()
-				.add("pretemplate", pretemplate)
-				.add("posttemplate", posttemplate)
-				.add("basename", basename)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("ForeignKeyMatch");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			ForeignKeyMatch _cother = (ForeignKeyMatch)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    super.validate(rules, msgRecorder);
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            public Recognizer.Matcher getMatcher(final String foreignKeyName) {
-                return super.getMatcher(foreignKeyName);
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is used to identify which tables in the database might
-	 * be aggregate table of a given fact table.
-	 * It is expected that aggregate table names will include the
-	 * base fact table name with additional text before and/or
-	 * after.
-	 * It is not allow for both the prepending and appending
-	 * regular expression text to be null (if it were, then only
-	 * aggregate tables who names were the same as (modulo case)
-	 * would match - which is surely not allowed).
-	 */
-	public static class TableMatch extends NameMatcher
-	{
-		public TableMatch()
-		{
-		}
-
-		public TableMatch(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				pretemplate = (String)_parser.getAttribute("pretemplate", "String", null, null, false);
-				posttemplate = (String)_parser.getAttribute("posttemplate", "String", null, null, false);
-				basename = (String)_parser.getAttribute("basename", "String", null, null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "TableMatch";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "pretemplate", pretemplate, _indent+1);
-			displayAttribute(_out, "posttemplate", posttemplate, _indent+1);
-			displayAttribute(_out, "basename", basename, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("TableMatch", new org.eigenbase.xom.XMLAttrVector()
-				.add("pretemplate", pretemplate)
-				.add("posttemplate", posttemplate)
-				.add("basename", basename)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("TableMatch");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			TableMatch _cother = (TableMatch)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if ((pretemplate == null) && (posttemplate == null)) {
-                        String msg = "Must have at least one template non-null";
-                        msgRecorder.reportError(msg);
-                    }
-                    super.validate(rules, msgRecorder);
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            public Recognizer.Matcher getMatcher(final String name) {
-                return super.getMatcher(name);
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This allows one to create an element that matches against a
-	 * single template, where the template is an attribute.
-	 * While much loved, this is currently not used.
-	 */
-	public static abstract class Mapper extends CaseMatcher
-	{
-		public Mapper()
-		{
-		}
-
-		public Mapper(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				template = (String)_parser.getAttribute("template", "String", null, null, true);
-				space = (String)_parser.getAttribute("space", "String", "_", null, false);
-				dot = (String)_parser.getAttribute("dot", "String", "_", null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String template;  // required attribute
-		public String space;  // attribute default: _
-		public String dot;  // attribute default: _
-
-
-		public String getName()
-		{
-			return "Mapper";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "template", template, _indent+1);
-			displayAttribute(_out, "space", space, _indent+1);
-			displayAttribute(_out, "dot", dot, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%Mapper;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("template", template)
-				.add("space", space)
-				.add("dot", dot)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.endTag("(%Mapper;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			Mapper _cother = (Mapper)_other;
-			_diff = _diff && displayAttributeDiff("template", template, _cother.template, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("space", space, _cother.space, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("dot", dot, _cother.dot, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public String getTemplate() {
-                return template;
-            }
-            public String getSpace() {
-                return space;
-            }
-            public String getDot() {
-                return dot;
-            }
-            protected static final int BAD_ID = -1;
-
-            protected String[] templateParts;
-            protected int[] templateNamePos;
-
-            /**
-             * It is hoped that no one will need to match more than 50 names
-             * in a template. Currently, this implementation, requires only 3.
-             */
-            private static final int MAX_SIZE = 50;
-
-            public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    super.validate(rules, msgRecorder);
-
-                    String[] ss = new String[MAX_SIZE+1];
-                    int[] poss = new int[MAX_SIZE];
-
-                    String template = getTemplate();
-                    int count = 0;
-
-                    int end = 0;
-                    int previousEnd = 0;
-                    int start = template.indexOf("${", end);
-                    while (count < MAX_SIZE) {
-                        if (start == -1) {
-                            if (count == 0) {
-                                // there are no ${} in template which
-                                // is an error
-                                String msg = "Bad template \"" +
-                                    template +
-                                    "\", no ${} entries";
-                                msgRecorder.reportError(msg);
-                                return;
-                            }
-                            // its OK, there are "count" ${}
-                            templateNamePos = new int[count];
-                            System.arraycopy(poss, 0, templateNamePos, 0, count);
-
-                            ss[count++] =
-                                template.substring(end, template.length());
-                            templateParts = new String[count];
-                            System.arraycopy(ss, 0, templateParts, 0, count);
-
-                            return;
-                        }
-
-                        previousEnd = end;
-                        end = template.indexOf('}', start);
-                        if (end == -1) {
-                            // there was a "${" but not '}' in template
-                            String msg = "Bad template \"" +
-                                template +
-                                "\", it had a \"${\", but no '}'";
-                            msgRecorder.reportError(msg);
-                            return;
-                        }
-
-                        String name = template.substring(start+2, end);
-                        int pos = convertNameToID(name, msgRecorder);
-                        if (pos == BAD_ID) {
-                            return;
-                        }
-
-                        poss[count] = pos;
-                        ss[count] = template.substring(previousEnd, start);
-
-                        start = template.indexOf("${", end);
-                        end++;
-
-                        count++;
-                    }
-
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-
-
-            protected abstract String[] getTemplateNames();
-
-            private int convertNameToID(final String name,
-                                        final mondrian.recorder.MessageRecorder msgRecorder) {
-
-                if (name == null) {
-                    String msg = "Template name is null";
-                    msgRecorder.reportError(msg);
-                    return BAD_ID;
-                }
-
-                String[] names = getTemplateNames();
-                for (int i = 0; i < names.length; i++) {
-                    if (names[i].equals(name)) {
-                        return i;
-                    }
-                }
-
-                String msg = "Bad template name \"" +
-                    name +
-                    "\"";
-                msgRecorder.reportError(msg);
-                return BAD_ID;
-            }
-
-            public String getRegex(final String[] names) {
-                final String space = getSpace();
-                final String dot = getDot();
-
-                final StringBuilder buf = new StringBuilder();
-
-                //
-                // Remember that:
-                //      templateParts.length == templateNamePos.length+1
-                //
-                buf.append(templateParts[0]);
-                for (int i = 0; i < templateNamePos.length; i++) {
-                    String n = names[templateNamePos[i]];
-
-                    if (space != null) {
-                        n = n.replaceAll(" ", space);
-                    }
-                    if (dot != null) {
-                        n = n.replaceAll("\\.", dot);
-                    }
-
-                    buf.append(n);
-                    buf.append(templateParts[i+1]);
-                }
-
-                String regex = buf.toString();
-
-                if (AggRules.getLogger().isDebugEnabled()) {
-                    StringBuilder bf = new StringBuilder(64);
-                    bf.append(getName());
-                    bf.append(".getRegex:");
-                    bf.append(" for names ");
-                    for (int i = 0; i < names.length; i++) {
-                        bf.append('"');
-                        bf.append(names[i]);
-                        bf.append('"');
-                        if (i+1 < names.length) {
-                            bf.append(", ");
-                        }
-                    }
-                    bf.append(" regex is \"");
-                    bf.append(regex);
-                    bf.append('"');
-
-                    String msg = bf.toString();
-                    AggRules.getLogger().debug(msg);
-                }
-                return regex;
-            }
-
-            protected Recognizer.Matcher getMatcher(final String[] names) {
-
-                final String charcase = getCharCase();
-                final String regex;
-                int flag = 0;
-
-                if (charcase.equals("ignore")) {
-                    // the case of name does not matter
-                    // since the Pattern will be create to ignore case
-                    regex = getRegex(names);
-
-                    flag = java.util.regex.Pattern.CASE_INSENSITIVE;
-
-                } else if (charcase.equals("exact")) {
-                    // the case of name is not changed
-                    // since we are interested in exact case matching
-                    regex = getRegex(names);
-
-                } else if (charcase.equals("upper")) {
-                    // convert name to upper case
-                    String[] ucNames = new String[names.length];
-                    for (int i = 0; i < names.length; i++) {
-                        ucNames[i] = names[i].toUpperCase();
-                    }
-
-                    regex = getRegex(ucNames);
-
-                } else {
-                    // lower
-                    // convert name to lower case
-                    String[] lcNames = new String[names.length];
-                    for (int i = 0; i < names.length; i++) {
-                        lcNames[i] = names[i].toLowerCase();
-                    }
-
-                    regex = getRegex(lcNames);
-
-                }
-                final java.util.regex.Pattern pattern =
-                    java.util.regex.Pattern.compile(regex, flag);
-
-                return new Recognizer.Matcher() {
-                    public boolean matches(String name) {
-                        boolean b = pattern.matcher(name).matches();
-                        if (AggRules.getLogger().isDebugEnabled()) {
-                            debug(name);
-                        }
-                        return b;
-                    }
-                    private void debug(String name) {
-                        StringBuilder bf = new StringBuilder(64);
-                        bf.append(Mapper.this.getName());
-                        bf.append(".Matcher.matches:");
-                        bf.append(" name \"");
-                        bf.append(name);
-                        bf.append("\" pattern \"");
-                        bf.append(pattern.pattern());
-                        bf.append("\"");
-                        if ((pattern.flags() &
-                            java.util.regex.Pattern.CASE_INSENSITIVE) != 0) {
-                            bf.append(" case_insensitive");
-                        }
-
-                        String msg = bf.toString();
-                        AggRules.getLogger().debug(msg);
-                    }
-                };
-
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This element is used in a vector of child elements when
-	 * one wishes to have one or more regular expressions associated
-	 * with matching a given string. The parent element must
-	 * initialize Regex object by calling its validate method
-	 * passing in an array of template names.
-	 * The cdata content is a regular expression with embedded
-	 * template names. Each name must be surrounded by "${" and "}".
-	 * Each time this is used for a new set of names, the names
-	 * replace the template names in the regular expression.
-	 * For example, if the charcase="lower", the attribute
-	 * dot="-" (the default dot value is "_"), the template names are:
-	 * "city", "state", and "country"
-	 * and the cdata is:
-	 * .*_${country}_.*_${city}
-	 * Then when the names:
-	 * "San Francisco", "California", and "U.S.A"
-	 * are passed in, the regular expression becomes:
-	 * .*_u-s-a_.*_san_francisco
-	 * Note that a given template name can only appear ONCE in the
-	 * template content, the cdata content. As an example, the
-	 * following cdata template is not supported:
-	 * .*_${country}_.*_${city}_${country}
-	 */
-	public static class Regex extends CaseMatcher
-	{
-		public Regex()
-		{
-		}
-
-		public Regex(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				space = (String)_parser.getAttribute("space", "String", "_", null, false);
-				dot = (String)_parser.getAttribute("dot", "String", "_", null, false);
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				charcase = (String)_parser.getAttribute("charcase", "String", "ignore", _charcase_values, false);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				cdata = _parser.getText();
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String space;  // attribute default: _
-		public String dot;  // attribute default: _
-
-		public String cdata;  // All text goes here
-		public String getName()
-		{
-			return "Regex";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "space", space, _indent+1);
-			displayAttribute(_out, "dot", dot, _indent+1);
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "charcase", charcase, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayString(_out, "cdata", cdata, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("Regex", new org.eigenbase.xom.XMLAttrVector()
-				.add("space", space)
-				.add("dot", dot)
-				.add("id", id)
-				.add("charcase", charcase)
-				.add("enabled", enabled)
-				);
-			_out.cdata(cdata);
-			_out.endTag("Regex");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			Regex _cother = (Regex)_other;
-			_diff = _diff && displayAttributeDiff("space", space, _cother.space, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("dot", dot, _cother.dot, _out, _indent+1);
-			_diff = _diff && displayStringDiff("cdata", cdata, _cother.cdata, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public String getSpace() {
-                return space;
-            }
-            public String getDot() {
-                return dot;
-            }
-            public String getTemplate() {
-                return cdata;
-            }
-
-            protected static final int BAD_ID = -1;
-
-            protected String[] templateParts;
-
-            /**
-             * This is a one-to-one mapping, each template name can appear
-             * at most once.
-             */
-            protected int[] templateNamePos;
-
-            /**
-             * It is hoped that no one will need to match more than 50 names
-             * in a template. Currently, this implementation, requires only 3.
-             */
-            private static final int MAX_SIZE = 50;
-
-            public void validate(final AggRules rules,
-                                 final String[] templateNames,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    super.validate(rules, msgRecorder);
-
-                    String[] ss = new String[MAX_SIZE+1];
-                    int[] poss = new int[MAX_SIZE];
-
-                    String template = getTemplate();
-                    int count = 0;
-
-                    int end = 0;
-                    int previousEnd = 0;
-                    int start = template.indexOf("${", end);
-                    // if no templateNames, then there better not be
-                    // any ${}s
-                    if (templateNames.length == 0) {
-                        if (start == -1) {
-                            // everything is ok
-                            templateParts = new String[1];
-                            templateParts[0] = template;
-                            templateNamePos = new int[0];
-                        } else {
-                            String msg = "Bad template \"" +
-                                template +
-                                "\", no ${} entries but there are "+
-                                "template names" ;
-                            msgRecorder.reportError(msg);
-                        }
-                        return;
-                    }
-                    while (count < MAX_SIZE) {
-                        if (start == -1) {
-                            if (count == 0) {
-                                // there are no ${} in template which
-                                // is an error
-                                String msg = "Bad template \"" +
-                                    template +
-                                    "\", no ${} entries";
-                                msgRecorder.reportError(msg);
-                                return;
-                            }
-                            // its OK, there are "count" ${}
-                            templateNamePos = new int[count];
-                            System.arraycopy(poss, 0, templateNamePos, 0, count);
-
-                            ss[count++] =
-                                template.substring(end, template.length());
-                            templateParts = new String[count];
-                            System.arraycopy(ss, 0, templateParts, 0, count);
-
-                            return;
-                        }
-
-                        previousEnd = end;
-                        end = template.indexOf('}', start);
-                        if (end == -1) {
-                            // there was a "${" but not '}' in template
-                            String msg = "Bad template \"" +
-                                template +
-                                "\", it had a \"${\", but no '}'";
-                            msgRecorder.reportError(msg);
-                            return;
-                        }
-
-                        String name = template.substring(start+2, end);
-                        int pos = convertNameToID(name,
-                                                  templateNames,
-                                                  msgRecorder);
-                        if (pos == BAD_ID) {
-                            return;
-                        }
-
-                        poss[count] = pos;
-                        ss[count] = template.substring(previousEnd, start);
-
-                        start = template.indexOf("${", end);
-                        end++;
-
-                        count++;
-                    }
-
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            private int convertNameToID(final String name,
-                                        final String[] templateNames,
-                                        final mondrian.recorder.MessageRecorder msgRecorder) {
-
-                if (name == null) {
-                    String msg = "Template name is null";
-                    msgRecorder.reportError(msg);
-                    return BAD_ID;
-                }
-
-                for (int i = 0; i < templateNames.length; i++) {
-                    if (templateNames[i].equals(name)) {
-                        return i;
-                    }
-                }
-
-                String msg = "Bad template name \"" +
-                    name +
-                    "\"";
-                msgRecorder.reportError(msg);
-                return BAD_ID;
-            }
-            public String getRegex(final String[] names) {
-                final String space = getSpace();
-                final String dot = getDot();
-
-                final StringBuilder buf = new StringBuilder();
-
-                //
-                // Remember that:
-                //      templateParts.length == templateNamePos.length+1
-                //
-                buf.append(templateParts[0]);
-                for (int i = 0; i < templateNamePos.length; i++) {
-                    String n = names[templateNamePos[i]];
-                    if (n == null) {
-                        // its ok for a name to be null, it just
-                        // eliminates the current regex from consideration
-                        return null;
-                    }
-
-                    if (space != null) {
-                        n = n.replaceAll(" ", space);
-                    }
-                    if (dot != null) {
-                        n = n.replaceAll("\\.", dot);
-                    }
-
-                    buf.append(n);
-                    buf.append(templateParts[i+1]);
-                }
-
-                String regex = buf.toString();
-
-                if (AggRules.getLogger().isDebugEnabled()) {
-                    StringBuilder bf = new StringBuilder(64);
-                    bf.append(getName());
-                    bf.append(".getRegex:");
-                    bf.append(" for names ");
-                    for (int i = 0; i < names.length; i++) {
-                        bf.append('"');
-                        bf.append(names[i]);
-                        bf.append('"');
-                        if (i+1 < names.length) {
-                            bf.append(", ");
-                        }
-                    }
-                    bf.append(" regex is \"");
-                    bf.append(regex);
-                    bf.append('"');
-
-                    String msg = bf.toString();
-                    AggRules.getLogger().debug(msg);
-                }
-
-                return regex;
-            }
-            protected java.util.regex.Pattern getPattern(final String[] names) {
-
-                final String charcase = getCharCase();
-
-                if (charcase.equals("ignore")) {
-                    // the case of name does not matter
-                    // since the Pattern will be create to ignore case
-                    final String regex = getRegex(names);
-                    if (regex == null) {
-                        return null;
-                    }
-
-                    final java.util.regex.Pattern pattern =
-                        java.util.regex.Pattern.compile(regex,
-                            java.util.regex.Pattern.CASE_INSENSITIVE);
-
-                    return pattern;
-
-                } else if (charcase.equals("exact")) {
-                    // the case of name is not changed
-                    // since we are interested in exact case matching
-                    final String regex = getRegex(names);
-                    if (regex == null) {
-                        return null;
-                    }
-
-                    final java.util.regex.Pattern pattern =
-                        java.util.regex.Pattern.compile(regex);
-
-                    return pattern;
-
-                } else if (charcase.equals("upper")) {
-                    // convert name to upper case
-                    String[] ucNames = new String[names.length];
-                    for (int i = 0; i < names.length; i++) {
-                        String name = names[i];
-                        ucNames[i] = (name == null)
-                            ? null: name.toUpperCase();
-                    }
-
-                    final String regex = getRegex(ucNames);
-                    if (regex == null) {
-                        return null;
-                    }
-
-                    final java.util.regex.Pattern pattern =
-                        java.util.regex.Pattern.compile(regex);
-
-                    return pattern;
-
-                } else {
-                    // lower
-                    // convert name to lower case
-                    String[] lcNames = new String[names.length];
-                    for (int i = 0; i < names.length; i++) {
-                        String name = names[i];
-                        lcNames[i] = (name == null)
-                            ? null: name.toLowerCase();
-                    }
-
-                    final String regex = getRegex(lcNames);
-                    if (regex == null) {
-                        return null;
-                    }
-
-                    final java.util.regex.Pattern pattern =
-                        java.util.regex.Pattern.compile(regex);
-
-                    return pattern;
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 */
-	public static abstract class RegexMapper extends Base
-	{
-		public RegexMapper()
-		{
-		}
-
-		public RegexMapper(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				org.eigenbase.xom.NodeDef[] _tempArray = null;
-				_tempArray = _tempArray;
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				_tempArray = _parser.getArray(Regex.class, 0, 0);
-				regexs = new Regex[_tempArray.length];
-				for(int _i=0; _i<regexs.length; _i++)
-					regexs[_i] = (Regex)_tempArray[_i];
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String id;  // required attribute
-
-		/**
-		 * This is an array of Regex. A match occurs if any one of
-		 * the Regex matches; it is the equivalent of or-ing the
-		 * regular expressions together. A candidate string is processed
-		 * sequentially by each Regex in their document order until
-		 * one matches. In none match, well, none match.
-		 */
-		public Regex[] regexs;  //optional array
-
-		public String getName()
-		{
-			return "RegexMapper";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayElementArray(_out, "regexs", regexs, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%RegexMapper;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("id", id)
-				.add("enabled", enabled)
-				);
-			displayXMLElementArray(_out, regexs);
-			_out.endTag("(%RegexMapper;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			RegexMapper _cother = (RegexMapper)_other;
-			_diff = _diff && displayAttributeDiff("id", id, _cother.id, _out, _indent+1);
-			_diff = _diff && displayElementArrayDiff("regexs", regexs, _cother.regexs, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-protected String getTag() {
-                return id;
-            }
-
-            public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-
-                    String[] templateNames = getTemplateNames();
-
-                    for (int i = 0; i < regexs.length; i++) {
-                        Regex regex = regexs[i];
-                        regex.validate(rules, templateNames, msgRecorder);
-                    }
-
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-
-
-            /**
-             * This must be defined in derived classes. It returns an array of
-             * symbolic names that are the symbolic names allowed to appear
-             * in the regular expression templates.
-             *
-             * @return array of symbol names
-             */
-            protected abstract String[] getTemplateNames();
-
-            protected Recognizer.Matcher getMatcher(final String[] names) {
-
-                final java.util.regex.Pattern[] patterns =
-                    new java.util.regex.Pattern[regexs.length];
-
-                for (int i = 0; i < regexs.length; i++) {
-                    Regex regex = regexs[i];
-                    patterns[i] = regex.getPattern(names);
-                }
-
-                return new Recognizer.Matcher() {
-                    public boolean matches(String name) {
-                        for (int i = 0; i < patterns.length; i++) {
-                            java.util.regex.Pattern pattern = patterns[i];
-                            if ((pattern != null) &&
-                                    pattern.matcher(name).matches()) {
-
-                                if (AggRules.getLogger().isDebugEnabled()) {
-                                    debug(name, pattern);
-                                }
-
-                                return true;
-                            }
-                        }
-                        return false;
-                    }
-                    private void debug(String name, java.util.regex.Pattern p) {
-                        StringBuilder bf = new StringBuilder(64);
-                        bf.append("DefaultDef.RegexMapper");
-                        bf.append(".Matcher.matches:");
-                        bf.append(" name \"");
-                        bf.append(name);
-                        bf.append("\" matches regex \"");
-                        bf.append(p.pattern());
-                        bf.append("\"");
-                        if ((p.flags() &
-                            java.util.regex.Pattern.CASE_INSENSITIVE) != 0) {
-                            bf.append(" case_insensitive");
-                        }
-
-                        String msg = bf.toString();
-                        AggRules.getLogger().debug(msg);
-                    }
-                };
-            }
-		// END pass-through code block ---
-	}
-
-	public static abstract class Ref extends Base
-	{
-		public Ref()
-		{
-		}
-
-		public Ref(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String refId;  // required attribute
-
-
-		public String getName()
-		{
-			return "Ref";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("(%Ref;)", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("(%Ref;)");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			Ref _cother = (Ref)_other;
-			_diff = _diff && displayAttributeDiff("refId", refId, _cother.refId, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-protected String getTag() {
-                return getRefId();
-            }
-            public String getRefId() {
-                return refId;
-            }
-		// END pass-through code block ---
-	}
-
-	public static class LevelMapRef extends Ref
-	{
-		public LevelMapRef()
-		{
-		}
-
-		public LevelMapRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "LevelMapRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("LevelMapRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("LevelMapRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			LevelMapRef _cother = (LevelMapRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasLevelMap(getRefId())) {
-                        String msg = "No LevelMap has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	public static class MeasureMapRef extends Ref
-	{
-		public MeasureMapRef()
-		{
-		}
-
-		public MeasureMapRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "MeasureMapRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("MeasureMapRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("MeasureMapRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			MeasureMapRef _cother = (MeasureMapRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasMeasureMap(getRefId())) {
-                        String msg = "No MeasureMap has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	public static class IgnoreMapRef extends Ref
-	{
-		public IgnoreMapRef()
-		{
-		}
-
-		public IgnoreMapRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "IgnoreMapRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("IgnoreMapRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("IgnoreMapRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			IgnoreMapRef _cother = (IgnoreMapRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasIgnoreMap(getRefId())) {
-                        String msg = "No IgnoreMap has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	public static class FactCountMatchRef extends Ref
-	{
-		public FactCountMatchRef()
-		{
-		}
-
-		public FactCountMatchRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "FactCountMatchRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("FactCountMatchRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("FactCountMatchRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			FactCountMatchRef _cother = (FactCountMatchRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasFactCountMatch(getRefId())) {
-                        String msg = "No FactCountMatch has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	public static class ForeignKeyMatchRef extends Ref
-	{
-		public ForeignKeyMatchRef()
-		{
-		}
-
-		public ForeignKeyMatchRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "ForeignKeyMatchRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("ForeignKeyMatchRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("ForeignKeyMatchRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			ForeignKeyMatchRef _cother = (ForeignKeyMatchRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasForeignKeyMatch(getRefId())) {
-                        String msg = "No ForeignKeyMatch has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	public static class TableMatchRef extends Ref
-	{
-		public TableMatchRef()
-		{
-		}
-
-		public TableMatchRef(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				refId = (String)_parser.getAttribute("refId", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "TableMatchRef";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "refId", refId, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("TableMatchRef", new org.eigenbase.xom.XMLAttrVector()
-				.add("refId", refId)
-				.add("enabled", enabled)
-				);
-			_out.endTag("TableMatchRef");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			TableMatchRef _cother = (TableMatchRef)_other;
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    if (! rules.hasTableMatch(getRefId())) {
-                        String msg = "No TableMatch has id equal to refid \"" +
-                            getRefId() +
-                            "\"";
-                        msgRecorder.reportError(msg);
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is the template that maps from a combination of level
-	 * usage_prefix
-	 * hierarchy_name
-	 * level_name
-	 * level_column_name
-	 */
-	public static class LevelMap extends RegexMapper
-	{
-		public LevelMap()
-		{
-		}
-
-		public LevelMap(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				org.eigenbase.xom.NodeDef[] _tempArray = null;
-				_tempArray = _tempArray;
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				_tempArray = _parser.getArray(Regex.class, 0, 0);
-				regexs = new Regex[_tempArray.length];
-				for(int _i=0; _i<regexs.length; _i++)
-					regexs[_i] = (Regex)_tempArray[_i];
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "LevelMap";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayElementArray(_out, "regexs", regexs, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("LevelMap", new org.eigenbase.xom.XMLAttrVector()
-				.add("id", id)
-				.add("enabled", enabled)
-				);
-			displayXMLElementArray(_out, regexs);
-			_out.endTag("LevelMap");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			LevelMap _cother = (LevelMap)_other;
-			_diff = _diff && displayElementArrayDiff("regexs", regexs, _cother.regexs, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-private static final String[] TEMPLATE_NAMES = new String[] {
-                "usage_prefix",
-                "hierarchy_name",
-                "level_name",
-                "level_column_name"
-            };
-            protected String[] getTemplateNames() {
-                return TEMPLATE_NAMES;
-            }
-
-            protected Recognizer.Matcher getMatcher(
-                                            final String usagePrefix,
-                                            final String hierarchyName,
-                                            final String levelName,
-                                            final String levelColumnName) {
-                return getMatcher(new String[] {
-                    usagePrefix,
-                    hierarchyName,
-                    levelName,
-                    levelColumnName
-                });
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is the template that maps from a combination of measure
-	 * measure_name,
-	 * measure_column_name, and
-	 * aggregate_name ("count", "sum", "avg", "min", "max",
-	 * "distinct-count").
-	 */
-	public static class MeasureMap extends RegexMapper
-	{
-		public MeasureMap()
-		{
-		}
-
-		public MeasureMap(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				org.eigenbase.xom.NodeDef[] _tempArray = null;
-				_tempArray = _tempArray;
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				_tempArray = _parser.getArray(Regex.class, 0, 0);
-				regexs = new Regex[_tempArray.length];
-				for(int _i=0; _i<regexs.length; _i++)
-					regexs[_i] = (Regex)_tempArray[_i];
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "MeasureMap";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayElementArray(_out, "regexs", regexs, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("MeasureMap", new org.eigenbase.xom.XMLAttrVector()
-				.add("id", id)
-				.add("enabled", enabled)
-				);
-			displayXMLElementArray(_out, regexs);
-			_out.endTag("MeasureMap");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			MeasureMap _cother = (MeasureMap)_other;
-			_diff = _diff && displayElementArrayDiff("regexs", regexs, _cother.regexs, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-private static final String[] TEMPLATE_NAMES = new String[] {
-                "measure_name",
-                "measure_column_name",
-                "aggregate_name"
-            };
-            protected String[] getTemplateNames() {
-                return TEMPLATE_NAMES;
-            }
-            protected Recognizer.Matcher getMatcher(
-                                            final String measureName,
-                                            final String measuerColumnName,
-                                            final String aggregateName) {
-                return getMatcher(new String[] {
-                    measureName,
-                    measuerColumnName,
-                    aggregateName
-                });
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * This is the template used to specify columns to be ignored.
-	 * There are NO template names. One simply uses a regular
-	 * expression.
-	 */
-	public static class IgnoreMap extends RegexMapper
-	{
-		public IgnoreMap()
-		{
-		}
-
-		public IgnoreMap(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				org.eigenbase.xom.NodeDef[] _tempArray = null;
-				_tempArray = _tempArray;
-				id = (String)_parser.getAttribute("id", "String", null, null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				_tempArray = _parser.getArray(Regex.class, 0, 0);
-				regexs = new Regex[_tempArray.length];
-				for(int _i=0; _i<regexs.length; _i++)
-					regexs[_i] = (Regex)_tempArray[_i];
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-
-
-		public String getName()
-		{
-			return "IgnoreMap";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "id", id, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayElementArray(_out, "regexs", regexs, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("IgnoreMap", new org.eigenbase.xom.XMLAttrVector()
-				.add("id", id)
-				.add("enabled", enabled)
-				);
-			displayXMLElementArray(_out, regexs);
-			_out.endTag("IgnoreMap");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			IgnoreMap _cother = (IgnoreMap)_other;
-			_diff = _diff && displayElementArrayDiff("regexs", regexs, _cother.regexs, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-private static final String[] TEMPLATE_NAMES = new String[] { };
-            protected String[] getTemplateNames() {
-                return TEMPLATE_NAMES;
-            }
-            protected Recognizer.Matcher getMatcher() {
-                return getMatcher(new String[]{});
-            }
-		// END pass-through code block ---
-	}
-
-	/**
-	 * A RolapConnection uses one AggRule. If no name is specified, then
-	 * the AggRule which is marked as default==true is used (validation
-	 * fails if one and only one AggRule is not marked as the default).
-	 * An AggRule has manditory child elements for matching the
-	 * aggregate table names, aggregate table fact count column,
-	 * foreign key columns, the measure columns, and the hierarchy level
-	 * columns. These child elements can be specified as direct children
-	 * of an AggRule element or by reference to elements defined as a
-	 * pier to the AggRule (using references allows reuse of the child
-	 * elements and with one quick edit the reference to use can be
-	 * changed by changing the refid attribute value).
-	 */
-	public static class AggRule extends Base
-	{
-		public AggRule()
-		{
-		}
-
-		public AggRule(org.eigenbase.xom.DOMWrapper _def)
-			throws org.eigenbase.xom.XOMException
-		{
-			try {
-				org.eigenbase.xom.DOMElementParser _parser = new org.eigenbase.xom.DOMElementParser(_def, "", DefaultDef.class);
-				_parser = _parser;
-				tag = (String)_parser.getAttribute("tag", "String", null, null, true);
-				countColumn = (String)_parser.getAttribute("countColumn", "String", "fact_count", null, true);
-				enabled = (Boolean)_parser.getAttribute("enabled", "Boolean", "true", null, false);
-				ignoreMap = (IgnoreMap)_parser.getElement(IgnoreMap.class, false);
-				ignoreMapRef = (IgnoreMapRef)_parser.getElement(IgnoreMapRef.class, false);
-				factCountMatch = (FactCountMatch)_parser.getElement(FactCountMatch.class, false);
-				factCountMatchRef = (FactCountMatchRef)_parser.getElement(FactCountMatchRef.class, false);
-				foreignKeyMatch = (ForeignKeyMatch)_parser.getElement(ForeignKeyMatch.class, false);
-				foreignKeyMatchRef = (ForeignKeyMatchRef)_parser.getElement(ForeignKeyMatchRef.class, false);
-				tableMatch = (TableMatch)_parser.getElement(TableMatch.class, false);
-				tableMatchRef = (TableMatchRef)_parser.getElement(TableMatchRef.class, false);
-				levelMap = (LevelMap)_parser.getElement(LevelMap.class, false);
-				levelMapRef = (LevelMapRef)_parser.getElement(LevelMapRef.class, false);
-				measureMap = (MeasureMap)_parser.getElement(MeasureMap.class, false);
-				measureMapRef = (MeasureMapRef)_parser.getElement(MeasureMapRef.class, false);
-			} catch(org.eigenbase.xom.XOMException _ex) {
-				throw new org.eigenbase.xom.XOMException("In " + getName() + ": " + _ex.getMessage());
-			}
-		}
-
-		public String tag;  // required attribute
-		public String countColumn;  // attribute default: fact_count
-
-		/**
-		 */
-		public IgnoreMap ignoreMap;  //optional element
-		/**
-		 */
-		public IgnoreMapRef ignoreMapRef;  //optional element
-		/**
-		 */
-		public FactCountMatch factCountMatch;  //optional element
-		/**
-		 */
-		public FactCountMatchRef factCountMatchRef;  //optional element
-		/**
-		 */
-		public ForeignKeyMatch foreignKeyMatch;  //optional element
-		/**
-		 */
-		public ForeignKeyMatchRef foreignKeyMatchRef;  //optional element
-		/**
-		 */
-		public TableMatch tableMatch;  //optional element
-		/**
-		 */
-		public TableMatchRef tableMatchRef;  //optional element
-		/**
-		 */
-		public LevelMap levelMap;  //optional element
-		/**
-		 */
-		public LevelMapRef levelMapRef;  //optional element
-		/**
-		 */
-		public MeasureMap measureMap;  //optional element
-		/**
-		 */
-		public MeasureMapRef measureMapRef;  //optional element
-
-		public String getName()
-		{
-			return "AggRule";
-		}
-
-		public void display(java.io.PrintWriter _out, int _indent)
-		{
-			_out.println(getName());
-			displayAttribute(_out, "tag", tag, _indent+1);
-			displayAttribute(_out, "countColumn", countColumn, _indent+1);
-			displayAttribute(_out, "enabled", enabled, _indent+1);
-			displayElement(_out, "ignoreMap", ignoreMap, _indent+1);
-			displayElement(_out, "ignoreMapRef", ignoreMapRef, _indent+1);
-			displayElement(_out, "factCountMatch", factCountMatch, _indent+1);
-			displayElement(_out, "factCountMatchRef", factCountMatchRef, _indent+1);
-			displayElement(_out, "foreignKeyMatch", foreignKeyMatch, _indent+1);
-			displayElement(_out, "foreignKeyMatchRef", foreignKeyMatchRef, _indent+1);
-			displayElement(_out, "tableMatch", tableMatch, _indent+1);
-			displayElement(_out, "tableMatchRef", tableMatchRef, _indent+1);
-			displayElement(_out, "levelMap", levelMap, _indent+1);
-			displayElement(_out, "levelMapRef", levelMapRef, _indent+1);
-			displayElement(_out, "measureMap", measureMap, _indent+1);
-			displayElement(_out, "measureMapRef", measureMapRef, _indent+1);
-		}
-		public void displayXML(org.eigenbase.xom.XMLOutput _out, int _indent)
-		{
-			_out.beginTag("AggRule", new org.eigenbase.xom.XMLAttrVector()
-				.add("tag", tag)
-				.add("countColumn", countColumn)
-				.add("enabled", enabled)
-				);
-			displayXMLElement(_out, ignoreMap);
-			displayXMLElement(_out, ignoreMapRef);
-			displayXMLElement(_out, factCountMatch);
-			displayXMLElement(_out, factCountMatchRef);
-			displayXMLElement(_out, foreignKeyMatch);
-			displayXMLElement(_out, foreignKeyMatchRef);
-			displayXMLElement(_out, tableMatch);
-			displayXMLElement(_out, tableMatchRef);
-			displayXMLElement(_out, levelMap);
-			displayXMLElement(_out, levelMapRef);
-			displayXMLElement(_out, measureMap);
-			displayXMLElement(_out, measureMapRef);
-			_out.endTag("AggRule");
-		}
-		public boolean displayDiff(org.eigenbase.xom.ElementDef _other, java.io.PrintWriter _out, int _indent)
-		{
-			boolean _diff = true;
-			AggRule _cother = (AggRule)_other;
-			_diff = _diff && displayAttributeDiff("tag", tag, _cother.tag, _out, _indent+1);
-			_diff = _diff && displayAttributeDiff("countColumn", countColumn, _cother.countColumn, _out, _indent+1);
-			_diff = _diff && displayElementDiff("ignoreMap", ignoreMap, _cother.ignoreMap, _out, _indent+1);
-			_diff = _diff && displayElementDiff("ignoreMapRef", ignoreMapRef, _cother.ignoreMapRef, _out, _indent+1);
-			_diff = _diff && displayElementDiff("factCountMatch", factCountMatch, _cother.factCountMatch, _out, _indent+1);
-			_diff = _diff && displayElementDiff("factCountMatchRef", factCountMatchRef, _cother.factCountMatchRef, _out, _indent+1);
-			_diff = _diff && displayElementDiff("foreignKeyMatch", foreignKeyMatch, _cother.foreignKeyMatch, _out, _indent+1);
-			_diff = _diff && displayElementDiff("foreignKeyMatchRef", foreignKeyMatchRef, _cother.foreignKeyMatchRef, _out, _indent+1);
-			_diff = _diff && displayElementDiff("tableMatch", tableMatch, _cother.tableMatch, _out, _indent+1);
-			_diff = _diff && displayElementDiff("tableMatchRef", tableMatchRef, _cother.tableMatchRef, _out, _indent+1);
-			_diff = _diff && displayElementDiff("levelMap", levelMap, _cother.levelMap, _out, _indent+1);
-			_diff = _diff && displayElementDiff("levelMapRef", levelMapRef, _cother.levelMapRef, _out, _indent+1);
-			_diff = _diff && displayElementDiff("measureMap", measureMap, _cother.measureMap, _out, _indent+1);
-			_diff = _diff && displayElementDiff("measureMapRef", measureMapRef, _cother.measureMapRef, _out, _indent+1);
-			return _diff;
-		}
-		// BEGIN pass-through code block ---
-private boolean isOk(final Base base) {
-                return ((base != null) && base.isEnabled());
-            }
-            private boolean isRef(final AggRules rules,
-                                  final mondrian.recorder.MessageRecorder msgRecorder,
-                                  final Base base,
-                                  final Base baseRef,
-                                  final String baseName) {
-                if (! isOk(base)) {
-                    if (isOk(baseRef)) {
-                        baseRef.validate(rules, msgRecorder);
-                        return true;
-                    } else {
-                        String msg = "Neither base " +
-                            baseName +
-                            " or baseref " +
-                            baseName +
-                            "Ref is ok";
-                        msgRecorder.reportError(msg);
-                        return false;
-                    }
-                } else if (isOk(baseRef)) {
-                    String msg = "Both base " +
-                        base.getName() +
-                        " and baseref " +
-                        baseRef.getName() +
-                        " are ok";
-                    msgRecorder.reportError(msg);
-                    return false;
-                } else {
-                    base.validate(rules, msgRecorder);
-                    return false;
-                }
-            }
-            // called after a constructor is called
-            public void validate(final AggRules rules,
-                                 final mondrian.recorder.MessageRecorder msgRecorder) {
-                msgRecorder.pushContextName(getName());
-                try {
-                    // IgnoreMap is optional
-                    if (ignoreMap != null) {
-                        ignoreMap.validate(rules, msgRecorder);
-                    } else if (ignoreMapRef != null) {
-                        ignoreMapRef.validate(rules, msgRecorder);
-                        ignoreMap =
-                            rules.lookupIgnoreMap(ignoreMapRef.getRefId());
-                    }
-                    if (isRef(rules, msgRecorder, factCountMatch,
-                            factCountMatchRef, "FactCountMatch")) {
-                        factCountMatch = rules.lookupFactCountMatch(
-                            factCountMatchRef.getRefId());
-                    }
-                    if (isRef(rules, msgRecorder, foreignKeyMatch,
-                            foreignKeyMatchRef, "ForeignKeyMatch")) {
-                        foreignKeyMatch = rules.lookupForeignKeyMatch(
-                            foreignKeyMatchRef.getRefId());
-                    }
-                    if (isRef(rules, msgRecorder, tableMatch,
-                            tableMatchRef, "TableMatch")) {
-                        tableMatch =
-                            rules.lookupTableMatch(tableMatchRef.getRefId());
-                    }
-                    if (isRef(rules, msgRecorder, levelMap,
-                            levelMapRef, "LevelMap")) {
-                        levelMap = rules.lookupLevelMap(levelMapRef.getRefId());
-                    }
-                    if (isRef(rules, msgRecorder, measureMap,
-                            measureMapRef, "MeasureMap")) {
-                        measureMap =
-                            rules.lookupMeasureMap(measureMapRef.getRefId());
-                    }
-                } finally {
-                    msgRecorder.popContextName();
-                }
-            }
-            public String getTag() {
-                return tag;
-            }
-            public String getCountColumn() {
-                return countColumn;
-            }
-            public FactCountMatch getFactCountMatch() {
-                return factCountMatch;
-            }
-            public ForeignKeyMatch getForeignKeyMatch() {
-                return foreignKeyMatch;
-            }
-            public TableMatch getTableMatch() {
-                return tableMatch;
-            }
-            public LevelMap getLevelMap() {
-                return levelMap;
-            }
-            public MeasureMap getMeasureMap() {
-                return measureMap;
-            }
-            public IgnoreMap getIgnoreMap() {
-                return ignoreMap;
-            }
-		// END pass-through code block ---
-	}
-
-
-}
Index: src/main/mondrian/rolap/CacheControlImpl.java
===================================================================
--- src/main/mondrian/rolap/CacheControlImpl.java	
+++ src/main/mondrian/rolap/CacheControlImpl.java	
@@ -109,11 +109,11 @@
 
     public CellRegion createMeasuresRegion(Cube cube) {
         final Dimension measuresDimension = cube.getDimensions()[0];
-        final Member[] measures =
+        final List<? extends Member> measures =
             cube.getSchemaReader(null).getLevelMembers(
                 measuresDimension.getHierarchy().getLevels()[0],
                 false);
-        return new MemberCellRegion(Arrays.asList(measures), false);
+        return new MemberCellRegion(measures, false);
     }
 
     public void flush(CellRegion region) {
@@ -376,11 +376,12 @@
      * @see MemberRangeCellRegion
      */
     static class MemberCellRegion implements CellRegionImpl {
-        private final List<Member> memberList;
+        private final List<? extends Member> memberList;
         private final Dimension dimension;
         private final boolean descendants;
 
-        MemberCellRegion(List<Member> memberList, boolean descendants) {
+        MemberCellRegion(final List<? extends Member> memberList, 
+                final boolean descendants) {
             assert memberList.size() > 0;
             this.memberList = memberList;
             this.dimension = (memberList.get(0)).getDimension();
@@ -408,7 +409,7 @@
             visitor.visit(this);
         }
 
-        public List<Member> getMemberList() {
+        public List<? extends Member> getMemberList() {
             return memberList;
         }
     }
Index: src/main/mondrian/rolap/Target.java
===================================================================
--- src/main/mondrian/rolap/Target.java	
+++ src/main/mondrian/rolap/Target.java	
@@ -0,0 +1,306 @@
+/*
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2004-2005 TONBELLER AG
+// Copyright (C) 2005-2007 Julian Hyde and others
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.rolap;
+
+import mondrian.calc.ResultStyle;
+import mondrian.olap.*;
+import mondrian.olap.fun.FunUtil;
+import mondrian.resource.MondrianResource;
+import mondrian.rolap.sql.MemberChildrenConstraint;
+import mondrian.rolap.sql.SqlQuery;
+import mondrian.rolap.sql.TupleConstraint;
+import mondrian.util.*;
+
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ * Extracted Target from original place.
+ * Unknown functonallity.
+ */
+public class Target {
+    private final HighCardSqlTupleReader sqlTupleReader;
+    private final RolapLevel level;
+    private final MemberCache cache;
+    private final TupleConstraint constraint;
+    private final TupleReader.MemberBuilder memberBuilder;
+    private final List<RolapMember> srcMembers;
+    
+    boolean parentChild;
+    private RolapLevel[] levels;
+    private RolapMember currMember;
+    private List<List<RolapMember>> siblings;
+    private List<RolapMember> members;
+    private int levelDepth;
+    private List<RolapMember> list;
+
+    public Target(final RolapLevel level, 
+            final TupleReader.MemberBuilder memberBuilder,
+            final List<RolapMember> srcMembers, 
+            final TupleConstraint constraint,
+            final HighCardSqlTupleReader sqlTupleReader) {
+        this.sqlTupleReader = sqlTupleReader;
+        this.level = level;
+        this.constraint = constraint;
+        this.cache = memberBuilder.getMemberCache();
+        this.memberBuilder = memberBuilder;
+        this.srcMembers = srcMembers;
+    }
+
+    public List<RolapMember> getSrcMembers() { return this.srcMembers; }
+    public RolapMember getCurrMember() { return this.currMember; }
+    public void removeCurrMember() { this.currMember = null; }
+    public void setCurrMember(final RolapMember m) { this.currMember = m; }
+    public void add(final RolapMember member) { this.list.add(member); }
+
+    public void open() {
+        levels = (RolapLevel[]) level.getHierarchy().getLevels();
+        list = new LinkedList<RolapMember>();
+        levelDepth = level.getDepth();
+        parentChild = level.isParentChild();
+        // members[i] is the current member of level#i, and siblings[i]
+        // is the current member of level#i plus its siblings
+        members = new ArrayList<RolapMember>();
+        for(int i=0; i<levels.length; i++) members.add(null);
+        siblings = new ArrayList<List<RolapMember>>();
+        for(int i=0; i<levels.length+1; i++) {
+            siblings.add(new ArrayList<RolapMember>());
+        }
+    }
+
+    /**
+     * Scans a row of the resultset and creates a member
+     * for the result.
+     *
+     * @param resultSet result set to retrieve rows from
+     * @param column the column index to start with
+     *
+     * @return index of the last column read + 1
+     * @throws SQLException
+     */
+    public int addRow(ResultSet resultSet, int column) throws SQLException {
+        synchronized (cache) {
+            return internalAddRow(resultSet, column);
+        }
+    }
+
+    private int internalAddRow(ResultSet resultSet, int column) 
+            throws SQLException {
+        RolapMember member = null;
+        if (currMember != null) {
+            member = currMember;
+        } else {
+            boolean checkCacheStatus = true;
+            for (int i = 0; i <= levelDepth; i++) {
+                RolapLevel childLevel = levels[i];
+                if (childLevel.isAll()) {
+                    member = level.getHierarchy().getAllMember();
+                    continue;
+                }
+                Object value = resultSet.getObject(++column);
+                if (value == null) {
+                    value = RolapUtil.sqlNullValue;
+                }
+                Object captionValue;
+                if (childLevel.hasCaptionColumn()) {
+                    captionValue = resultSet.getObject(++column);
+                } else {
+                    captionValue = null;
+                }
+                RolapMember parentMember = member;
+                Object key = cache.makeKey(parentMember, value);
+                member = cache.getMember(key, checkCacheStatus);
+                checkCacheStatus = false; /* Only check the first time */
+                if (member == null) {
+                    member = memberBuilder.makeMember(
+                        parentMember, childLevel, value, captionValue,
+                        parentChild, resultSet, key, column);
+                }
+
+                // Skip over the columns consumed by makeMember
+                if (!childLevel.getOrdinalExp().equals(
+                    childLevel.getKeyExp()))
+                {
+                    ++column;
+                }
+                column += childLevel.getProperties().length;
+            }
+            currMember = member;
+        }
+        ((List) list).add(member);
+        return column;
+    }
+
+    public List<RolapMember> close() {
+        final boolean asList = this.constraint.getEvaluator()!=null
+                && this.constraint.getEvaluator().getQuery().getResultStyle()
+                    == ResultStyle.LIST;
+        final int limit = MondrianProperties.instance().ResultLimit.get();
+
+        final List<RolapMember> l = new AbstractList<RolapMember>() {
+            private boolean moreRows = true;
+            private int offset = 0;
+            private RolapMember first = null;
+            private boolean firstMemberAssigned = false;
+
+            /**
+             * Performs a load of the whole result set.
+             */
+            public int size() {
+                while(this.moreRows) {
+                    this.moreRows = sqlTupleReader.readNextTuple();
+                    if(limit>0 && !asList && list.size()>limit) { 
+System.out.println("Target: 199, Ouch! Toooo big array..." + this.hashCode()); 
+                    }
+                }
+
+                return list.size();
+            }
+            public RolapMember get(final int idx) {
+                if(idx==0 && this.firstMemberAssigned) {
+                    return this.first;
+                } 
+                int index = idx - offset;
+                if(0<limit && index<0) {
+                    // Cannot send NoSuchElementException since its intercepted
+                    // by AbstractSequentialList to identify out of bounds.
+                    throw new RuntimeException("Element " + idx
+                            + " has been forgotten");
+                }
+
+                while(index>=list.size() && this.moreRows) {
+                    this.moreRows = sqlTupleReader.readNextTuple();
+                    if(!asList && limit>0 && list.size()>limit) {
+                        while(list.size()>limit) {
+                            index--;
+                            offset++;
+                            ((LinkedList) list).removeFirst();
+                        }
+                    }
+                }
+
+                if(idx==0) {
+                    this.firstMemberAssigned = true;
+                    this.first = list.get(index);
+                    return this.first;
+                } else return list.get(index);
+            }
+            public RolapMember set(final int i, final RolapMember e) {
+                if(asList) {
+                    final RolapMember old = this.get(i);
+                    list.set(i, e);
+                    return old;
+                } else throw new UnsupportedOperationException();
+            }
+            public boolean isEmpty() {
+                try {
+                    get(0);
+                    return false;
+                } catch(IndexOutOfBoundsException e) {
+                    return true;
+                }
+            }
+
+            public int hashCode() {
+                return Target.this.hashCode();
+            }
+
+
+            public Iterator<RolapMember> iterator() {
+                return new Iterator<RolapMember>() {
+                        private int cursor = 0;
+                        public boolean hasNext() {
+                            try {
+                                get(cursor);
+                                return true;
+                            } catch(IndexOutOfBoundsException ioobe) {
+                                return false;
+                            }
+                        }
+                        public RolapMember next() {
+                            return get(cursor++);
+                        }
+                        public void remove() {
+                            throw new UnsupportedOperationException();
+                        }
+                    };
+            }
+        };
+
+        if(asList) l.size();
+
+        return l;
+
+/*
+        synchronized (cache) {
+            return internalClose();
+        }
+*/
+    }
+
+
+    //
+    // Private Stuff --------------------------------------------------
+    //
+
+    /**
+     * Cleans up after all rows have been processed, and returns the list of
+     * members.
+     *
+     * @return list of members
+     */
+    private List<RolapMember> internalClose() {
+        for (int i = 0; i < members.size(); i++) {
+            RolapMember member = members.get(i);
+            final List<RolapMember> children = siblings.get(i + 1);
+            if (member != null && children != null) {
+                // If we are finding the members of a particular level, and
+                // we happen to find some of the children of an ancestor of
+                // that level, we can't be sure that we have found all of
+                // the children, so don't put them in the cache.
+                if (member.getDepth() < level.getDepth()) {
+                    continue;
+                }
+                MemberChildrenConstraint mcc =
+                    constraint.getMemberChildrenConstraint(member);
+                if (mcc != null) {
+                    cache.putChildren(member, mcc, children);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Adds <code>member</code> just before the first element in
+     * <code>list</code> which has the same parent.
+     */
+    private void addAsOldestSibling(final List<RolapMember> list, 
+            final RolapMember member) {
+        int i = list.size();
+        while (--i >= 0) {
+            RolapMember sibling = list.get(i);
+            if (sibling.getParentMember() != member.getParentMember()) {
+                break;
+            }
+        }
+        list.add(i + 1, member);
+    }
+
+    public RolapLevel getLevel() {
+        return level;
+    }
+
+    public String toString() {
+        return level.getUniqueName();
+    }
+}
Index: src/main/mondrian/rolap/ArrayMemberSource.java
===================================================================
--- src/main/mondrian/rolap/ArrayMemberSource.java	
+++ src/main/mondrian/rolap/ArrayMemberSource.java	
@@ -14,6 +14,7 @@
 package mondrian.rolap;
 
 import mondrian.olap.Id;
+import mondrian.olap.Member;
 import mondrian.olap.Util;
 import mondrian.resource.MondrianResource;
 
@@ -31,9 +32,10 @@
 abstract class ArrayMemberSource implements MemberSource {
 
     protected final RolapHierarchy hierarchy;
-    protected final RolapMember[] members;
+    protected final List<? extends Member> members;
 
-    ArrayMemberSource(RolapHierarchy hierarchy, RolapMember[] members) {
+    ArrayMemberSource(final RolapHierarchy hierarchy, 
+            final List<? extends Member> members) {
         this.hierarchy = hierarchy;
         this.members = members;
     }
@@ -43,27 +45,29 @@
     public boolean setCache(MemberCache cache) {
         return false; // we do not support cache writeback
     }
-    public RolapMember[] getMembers() {
+    public List<? extends Member> getMembers() {
         return members;
     }
     public int getMemberCount() {
-        return members.length;
+        return members.size();
     }
 
-    public List<RolapMember> getRootMembers() {
+    public List<? extends Member> getRootMembers() {
         return Collections.emptyList();
     }
 
-    public void getMemberChildren(RolapMember parentMember, List<RolapMember> children) {
+    public void getMemberChildren(final Member parentMember, 
+            final List<? extends Member> children) {
         // there are no children
     }
-    public void getMemberChildren(List<RolapMember> parentMembers, List<RolapMember> children) {
+    public void getMemberChildren(final List<? extends Member> parentMembers, 
+            final List<? extends Member> children) {
         // there are no children
     }
-    public RolapMember lookupMember(List<Id.Segment> uniqueNameParts,
-                                    boolean failIfNotFound) {
+    public Member lookupMember(final List<Id.Segment> uniqueNameParts, 
+            final boolean failIfNotFound) {
         String uniqueName = Util.implode(uniqueNameParts);
-        for (RolapMember member : members) {
+        for (Member member : members) {
             if (member.getUniqueName().equals(uniqueName)) {
                 return member;
             }
Index: src/main/mondrian/rolap/MemberReader.java
===================================================================
--- src/main/mondrian/rolap/MemberReader.java	
+++ src/main/mondrian/rolap/MemberReader.java	
@@ -16,6 +16,7 @@
 
 import mondrian.olap.Hierarchy;
 import mondrian.olap.Evaluator;
+import mondrian.olap.Member;
 import mondrian.rolap.TupleReader.MemberBuilder;
 import mondrian.rolap.sql.TupleConstraint;
 import mondrian.rolap.sql.MemberChildrenConstraint;
@@ -52,7 +53,8 @@
      *
      * @return {@link List} of {@link RolapMember}
      */
-    List<RolapMember> getMembersInLevel(RolapLevel level, int startOrdinal, int endOrdinal);
+    List<? extends Member> getMembersInLevel(final RolapLevel level, 
+            final int startOrdinal, final int endOrdinal);
 
     /**
      * Writes all members between <code>startMember</code> and
@@ -62,7 +64,7 @@
             RolapLevel level,
             RolapMember startMember,
             RolapMember endMember,
-            List<RolapMember> list);
+            List<? extends Member> list);
 
     /**
      * Compares two members according to their order in a prefix ordered
@@ -77,16 +79,16 @@
     int compare(RolapMember m1, RolapMember m2, boolean siblingsAreEqual);
 
     void getMemberChildren(
-            RolapMember member,
-            List<RolapMember> children,
+            Member member,
+            List<? extends Member> children,
             MemberChildrenConstraint constraint);
 
     void getMemberChildren(
-            List<RolapMember> parentMembers,
-            List<RolapMember> children,
+            List<? extends Member> parentMembers,
+            List<? extends Member> children,
             MemberChildrenConstraint constraint);
 
-    List<RolapMember> getMembersInLevel(
+    List<? extends Member> getMembersInLevel(
             RolapLevel level,
             int startOrdinal,
             int endOrdinal,
Index: src/main/mondrian/rolap/MemberCache.java
===================================================================
--- src/main/mondrian/rolap/MemberCache.java	
+++ src/main/mondrian/rolap/MemberCache.java	
@@ -15,6 +15,7 @@
 
 import java.util.List;
 
+import mondrian.olap.Member;
 import mondrian.rolap.sql.TupleConstraint;
 import mondrian.rolap.sql.MemberChildrenConstraint;
 
@@ -62,7 +63,7 @@
      * @param constraint the condition that was used when the members were
      *    fetched. May be null for all members (no constraint)
      */
-    List<RolapMember> getChildrenFromCache(
+    List<? extends Member> getChildrenFromCache(
         RolapMember parent,
         MemberChildrenConstraint constraint);
 
@@ -86,7 +87,7 @@
     void putChildren(
         RolapMember member,
         MemberChildrenConstraint constraint,
-        List<RolapMember> children);
+        List<? extends Member> children);
 }
 
 
Index: src/main/mondrian/rolap/SqlConstraintFactory.java
===================================================================
--- src/main/mondrian/rolap/SqlConstraintFactory.java	
+++ src/main/mondrian/rolap/SqlConstraintFactory.java	
@@ -13,6 +13,7 @@
 import mondrian.olap.Id;
 import mondrian.olap.Evaluator;
 import mondrian.olap.Level;
+import mondrian.olap.Member;
 import mondrian.olap.MondrianProperties;
 import mondrian.rolap.sql.MemberChildrenConstraint;
 import mondrian.rolap.sql.TupleConstraint;
@@ -24,10 +25,10 @@
  * @since Nov 21, 2005
  */
 public class SqlConstraintFactory {
-
     boolean enabled = MondrianProperties.instance().EnableNativeNonEmpty.get();
 
-    private static final SqlConstraintFactory instance = new SqlConstraintFactory();
+    private static final SqlConstraintFactory instance = 
+            new SqlConstraintFactory();
 
     /** singleton */
     private SqlConstraintFactory() {
@@ -37,7 +38,8 @@
         return instance;
     }
 
-    public MemberChildrenConstraint getMemberChildrenConstraint(Evaluator context) {
+    public MemberChildrenConstraint getMemberChildrenConstraint(
+            final Evaluator context) {
         if (!enabled || !SqlContextConstraint.isValidContext(context))
             return DefaultMemberChildrenConstraint.instance();
         return new SqlContextConstraint((RolapEvaluator) context, false);
@@ -47,22 +49,17 @@
         return getLevelMembersConstraint(context, null);
     }
 
-    public TupleConstraint getLevelMembersConstraint(
-        Evaluator context,
-        Level [] levels) {
+    public TupleConstraint getLevelMembersConstraint(final Evaluator context,
+            final Level [] levels) {
         if (!enabled ||
-            !SqlContextConstraint.isValidContext(context, false, levels))
-        {
+            !SqlContextConstraint.isValidContext(context, false, levels)) {
             return DefaultTupleConstraint.instance();
         }
         return new SqlContextConstraint((RolapEvaluator) context, false);
     }
 
     public MemberChildrenConstraint getChildByNameConstraint(
-        RolapMember parent,
-        Id.Segment childName)
-    {
-        // ragged hierarchies span multiple levels, so SQL WHERE does not work there
+            final RolapMember parent, final Id.Segment childName) {
         if (!enabled || parent.getHierarchy().isRagged()) {
             return DefaultMemberChildrenConstraint.instance();
         }
@@ -75,9 +72,8 @@
      * for parent/child hierarchies.
      */
     public TupleConstraint getDescendantsConstraint(
-        List<RolapMember> parentMembers,
-        MemberChildrenConstraint mcc)
-    {
+            final List<? extends Member> parentMembers,
+            final MemberChildrenConstraint mcc) {
         return new DescendantsConstraint(parentMembers, mcc);
     }
 }
Index: src/main/mondrian/rolap/RolapDependencyTestingEvaluator.java
===================================================================
--- src/main/mondrian/rolap/RolapDependencyTestingEvaluator.java	
+++ src/main/mondrian/rolap/RolapDependencyTestingEvaluator.java	
@@ -111,13 +111,13 @@
                     ", result=" + otherResult);
         }
         if (!equals(otherResult, result)) {
-            final Member[] members = getMembers();
+            final List<Member> members = getMembers();
             final StringBuilder buf = new StringBuilder();
-            for (int j = 0; j < members.length; j++) {
+            for (int j = 0; j < members.size(); j++) {
                 if (j > 0) {
                     buf.append(", ");
                 }
-                buf.append(members[j].getUniqueName());
+                buf.append(members.get(j).getUniqueName());
             }
             throw Util.newInternal(
                     "Expression '" + mdxString +
@@ -237,16 +237,16 @@
                 final int levelDepth = random.nextInt(levels.length) + 1;
                 Member member = null;
                 for (int i = 0; i < levelDepth; i++) {
-                    Member[] members;
+                    List<? extends Member> members;
                     if (i == 0) {
-                        members = schemaReader.getLevelMembers(levels[i], false);
+                        members = schemaReader.getLevelMembers(levels[i],false);
                     } else {
                         members = schemaReader.getMemberChildren(member);
                     }
-                    if (members.length == 0) {
+                    if (members.size() == 0) {
                         break;
                     }
-                    member = members[random.nextInt(members.length)];
+                    member = members.get(random.nextInt(members.size()));
                 }
                 // If the member chosen happens to be the same as the original
                 // member, try again. Give up after 100 attempts (in case the
Index: src/main/mondrian/rolap/RolapConnection.java
===================================================================
--- src/main/mondrian/rolap/RolapConnection.java	
+++ src/main/mondrian/rolap/RolapConnection.java	
@@ -13,9 +13,7 @@
 package mondrian.rolap;
 
 import mondrian.olap.*;
-import mondrian.util.MemoryMonitor;
-import mondrian.util.MemoryMonitorFactory;
-import mondrian.util.Pair;
+import mondrian.util.*;
 import mondrian.rolap.agg.AggregationManager;
 import org.apache.commons.dbcp.ConnectionFactory;
 import org.apache.commons.dbcp.DataSourceConnectionFactory;
@@ -263,7 +261,6 @@
             }
 
         } else {
-
             final String dataSourceName =
                 connectInfo.get(RolapConnectionProperties.DataSource.name());
             if (dataSourceName == null) {
@@ -539,27 +536,44 @@
         /** workspace. Synchronized access only. */
         private final int[] pos;
 
-        NonEmptyResult(Result result, Query query, int axis) {
+        NonEmptyResult(final Result result, final Query query, final int axis) {
             super(query, result.getAxes().clone());
 
             this.underlying = result;
             this.axis = axis;
             this.map = new HashMap<Integer, Integer>();
-            int axisCount = underlying.getAxes().length;
+            final int axisCount = underlying.getAxes().length;
             this.pos = new int[axisCount];
             this.slicerAxis = underlying.getSlicerAxis();
-            List<Position> positions = underlying.getAxes()[axis].getPositions();
+            List<Position> positions = underlying.getAxes()[axis]
+                    .getPositions();
 
-            List<Position> positionsList = new ArrayList<Position>();
-            int i = 0;
-            for (Position position: positions) {
-                if (! isEmpty(i, axis)) {
-                    map.put(positionsList.size(), i);
-                    positionsList.add(position);
+            final List<Position> positionsList;
+            try {
+                if(positions.get(0).get(0).getDimension().isHighCardinality()) {
+                    positionsList=new FilteredIterableList<Position>(positions,
+                            new FilteredIterableList.Filter<Position>() {
+                                public boolean accept(final Position p) {
+                                    return p.get(0)!=null;
+                                }
+                            });
+                } else {
+                    positionsList = new ArrayList<Position>();
+                    int i = 0;
+                    for (Position position: positions) {
+                        if (! isEmpty(i, axis)) {
+                            map.put(positionsList.size(), i);
+                            positionsList.add(position);
+                        }
+                        i++;
+                    }
                 }
-                i++;
+                this.axes[axis] = new RolapAxis.PositionList(positionsList);
+            } catch(IndexOutOfBoundsException ioobe) {
+                // No elements.
+                this.axes[axis] = new RolapAxis.PositionList(
+                        new ArrayList<Position>());
             }
-            this.axes[axis] = new RolapAxis.PositionList(positionsList);
         }
 
         protected Logger getLogger() {
@@ -602,11 +616,17 @@
 
         // synchronized because we use 'pos'
         public synchronized Cell getCell(int[] externalPos) {
-            System.arraycopy(externalPos, 0, this.pos, 0, externalPos.length);
-            int offset = externalPos[axis];
-            int mappedOffset = mapOffsetToUnderlying(offset);
-            this.pos[axis] = mappedOffset;
-            return underlying.getCell(this.pos);
+            try {
+                System.arraycopy(externalPos, 0, this.pos, 0, externalPos.length);
+                int offset = externalPos[axis];
+                int mappedOffset = mapOffsetToUnderlying(offset);
+                this.pos[axis] = mappedOffset;
+                return underlying.getCell(this.pos);
+            } catch(NullPointerException npe) {
+                System.out.println("RolapConnection:619 please, review for "
+                        + "high cardinality...");
+                return underlying.getCell(externalPos);
+            }
         }
 
         private int mapOffsetToUnderlying(int offset) {
Index: src/main/mondrian/util/TraversalList.java
===================================================================
--- src/main/mondrian/util/TraversalList.java	
+++ src/main/mondrian/util/TraversalList.java	
@@ -0,0 +1,130 @@
+/*
+// $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2006-2007 Julian Hyde
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.util;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link java.util.List} for transposing an array of
+ * lists.
+ *
+ * @author Luis F. Canals
+ * @version $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+ * @since Dec, 2007
+ */
+public class TraversalList<T> extends UnsupportedList<List<? extends T>> {
+    private boolean asInternalArray = false;
+    private List<? extends T>[] internalArray = null;
+    private final List<? extends T>[] lists;
+
+    public TraversalList(final List<? extends T> lists[]) {
+        this.lists = lists;
+    }
+
+    public List<? extends T> get(int index) {
+        if(this.asInternalArray) {
+            return internalArray[index];
+        } else {
+            final List<? extends T> tuples = new ArrayList<T>();
+            for (int i = 0; i < lists.length; i++) {
+                ((List) tuples).add(lists[i].get(index));
+            }
+            return tuples;
+        }
+    }
+
+    public Iterator<List<? extends T>> iterator() {
+        return new Iterator<List<? extends T>>() {
+            private int currentIndex = 0;
+            private List<? extends T> precalculated;
+            public List<? extends T> next() {
+                if(precalculated!=null) {
+                    final List<? extends T> t = precalculated;
+                    precalculated = null;
+                    currentIndex++;
+                    return t;
+                } else return get(currentIndex++);
+            }
+            public boolean hasNext() {
+                try {
+                    precalculated = get(currentIndex);
+                    return true;
+                } catch(IndexOutOfBoundsException e) {
+                    return false;
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    // Used by Collections.sort
+    public ListIterator<List<? extends T>> listIterator(final int index) {
+        return new ListItr(index) {
+            public void set(final List<? extends T> l) {
+                TraversalList.this.set(cursor-1, l);
+            }
+        };
+    }
+
+    // Used by Collections.sort
+    public ListIterator<List<? extends T>> listIterator() {
+        return new ListItr(0) {
+            public void set(final List<? extends T> l) {
+                TraversalList.this.set(cursor-1, l);
+            }
+        };
+    }
+
+    public int size() {
+        return lists[0].size();
+    }
+
+    public List<List<? extends T>> subList(final int first, final int last) {
+        return new AbstractList<List<? extends T>>() {
+            public List<? extends T> get(int index) {
+                return TraversalList.this.get(index+first);
+            }
+            public int size() {
+                return last-first;
+            }
+        };
+    }
+
+    // Used by Collections.sort
+    public List<? extends T>[] toArray(final List<? extends T>[] dummy) {
+if(this.size()>1000) {
+System.out.println("TraversalList.toArray for a size " + this.size()
++ " greater than 1000!");
+}
+        final List<? extends T> array[] = new List[this.size()];
+        for(int i=0; i<this.size(); i++) {
+            array[i] = this.get(i);
+        }
+        this.asInternalArray = true;
+        this.internalArray = array;
+        return array;
+    }
+
+    public Object[] toArray() {
+        return toArray(null);
+    }
+
+    // Used by Collections.sort
+    public List<? extends T> set(final int index, final List<? extends T> l) {
+        if(this.asInternalArray) {
+            final List<? extends T> previous = this.internalArray[index];
+            this.internalArray[index] = l;
+            return previous;
+        } else throw new UnsupportedOperationException();
+    }
+}
Index: src/main/mondrian/util/CacheMap.java
===================================================================
--- src/main/mondrian/util/CacheMap.java	
+++ src/main/mondrian/util/CacheMap.java	
@@ -0,0 +1,234 @@
+/*
+ * (c) 2007 Tasecurity Group S.L, Spain
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package mondrian.util;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * Map with limited size to be used as cache.
+ *
+ * @author lcanals, www.tasecurity.net
+ */
+public class CacheMap<S, T> implements Map<S, T> {
+    private LinkedNode head;
+    private LinkedNode tail;
+    private final Map<S, Pair<S,T>> map;
+    private final int maxSize;
+
+    /**
+     * Creates an empty map with limited size.
+     *
+     * @param size Maximum number of mapped elements.
+     */
+    public CacheMap(final int size) {
+        this.head = new LinkedNode(null, null);
+        this.tail = new LinkedNode(head, null);
+        this.map = new WeakHashMap<S,Pair<S,T>>(size);
+        this.maxSize = size;
+    }
+
+    public void clear() {
+        this.head = new LinkedNode(null, null);
+        this.tail = new LinkedNode(head, null);
+        map.clear();
+    }
+
+    public boolean containsKey(final Object key) {
+        return map.containsKey(key);
+    }
+
+    public boolean containsValue(final Object value) {
+        return this.values().contains(value);
+    }
+
+    public Set entrySet() {
+        final Set<Map.Entry<S,T>> set = new HashSet<Map.Entry<S,T>>();
+        for(final Map.Entry<S, Pair<S,T>> entry : this.map.entrySet()) {
+            set.add(new Map.Entry<S,T>() {
+                        public boolean equals(Object s) {
+                            if(s instanceof Map.Entry) {
+                                return ((Map.Entry) s).getKey().equals(
+                                                entry.getKey()) 
+                                        && ((Map.Entry) s).getValue().equals(
+                                                entry.getValue().value);
+                            } else return false;
+                        }
+                        public S getKey() { return entry.getKey(); }
+                        public T getValue() { return entry.getValue().value; }
+                        public int hashCode() { return entry.hashCode(); }
+                        public T setValue(final T x) {
+                            return entry.setValue(new Pair<S,T>(
+                                    x, new LinkedNode(head, entry.getKey())))
+                                    .value;
+                        }
+                    });
+        }
+        return set;
+    }
+
+    public T get(final Object key) {
+        final Pair<S,T> pair = map.get(key);
+        if(pair!=null) {
+            final LinkedNode<S> node = pair.getNode();
+            if(node==null) {
+                map.remove(key);
+                return null;
+            }
+            node.moveTo(head);
+            return pair.value;
+        } else return null;
+    }
+
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    public Set<S> keySet() {
+        return map.keySet();
+    }
+
+    public T put(final S key, final T value) {
+        final Pair<S, T> pair = new Pair<S,T>(value, new LinkedNode(head, key));
+        final Pair<S, T> obj = map.put(key, pair);
+        if(map.size() > maxSize) {
+            tail.getPrevious().remove();
+            map.remove(key);
+        }
+        if(obj!=null) return obj.value;
+        else return null;
+    }
+
+    public void putAll(final Map t) {
+        throw new UnsupportedOperationException();
+    }
+
+    public T remove(final Object key) {
+        final Pair<S,T> pair = map.get(key);
+        if(pair==null) return null;
+        pair.getNode().remove();
+        return map.remove(key).value;
+    }
+
+    public int size() {
+        return map.size();
+    }
+
+    public Collection<T> values() {
+        final List<T> vals = new ArrayList<T>();
+        for(final Pair<S,T> pair : map.values()) {
+            vals.add(pair.value);
+        }
+        return vals;
+    }
+
+    public int hashCode() {
+        return map.hashCode();
+    }
+
+    public String toString() {
+        return "Ordered keys: " + head.toString() + "\n" 
+                + "Map:" + map.toString();
+    }
+
+    public boolean equals(Object o) {
+        CacheMap c = (CacheMap) o;
+        return map.equals(c.map);
+    }
+
+    //
+    // PRIVATE STUFF ------------------
+    //
+
+    /**
+     * Pair of linked key - value
+     */
+    private final class Pair<S, T> implements java.io.Serializable {
+        private final T value;
+        private final WeakReference<LinkedNode<S>> node;
+        private Pair(final T value, final LinkedNode<S> node) {
+            this.node = new WeakReference<LinkedNode<S>>(node);
+            this.value = value;
+        }
+        private LinkedNode<S> getNode() { 
+            return node.get();
+        }
+        public boolean equals(final Object o) {
+            return o!=null && o.equals(this.value);
+        }
+    }
+
+
+    /**
+     * Represents a node in a linked list.
+     */
+    private class LinkedNode<S> implements java.io.Serializable {
+        private LinkedNode<S> next, prev;
+        private S key;
+
+        public LinkedNode(final LinkedNode<S> prev, final S key) {
+            this.key = key;
+            insertAfter(prev);
+        }
+
+        public void remove() {
+            if(this.prev!=null) this.prev.next = this.next;
+            if(this.next!=null) this.next.prev = this.prev;
+        }
+
+        public void moveTo(final LinkedNode<S> prev) {
+            remove();
+            insertAfter(prev);
+        }
+
+        public LinkedNode<S> getPrevious() {
+            return this.prev;
+        }
+
+        public String toString() {
+            if(this.next!=null) {
+                if(key!=null) {
+                    return key.toString() + ", " + this.next.toString();
+                } else {
+                    return "<null>, " + this.next.toString();
+                }
+            } else {
+                if(key!=null) return key.toString();
+                else return "<null>";
+            }
+        }
+
+        private void insertAfter(final LinkedNode<S> prev) {
+            if(prev!=null) this.next = prev.next;
+            else this.prev = null;
+            this.prev = prev;
+
+            if(prev!=null) {
+                if(prev.next!=null) prev.next.prev = this;
+                prev.next = this;
+            }
+        }
+    }
+}
+
Index: src/main/mondrian/util/FilteredIterableList.java
===================================================================
--- src/main/mondrian/util/FilteredIterableList.java	
+++ src/main/mondrian/util/FilteredIterableList.java	
@@ -0,0 +1,204 @@
+/*
+// $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2006-2007 Julian Hyde
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.util;
+
+import java.util.*;
+
+/**
+ * Iterable list which filters undesirable elements.
+ * To be used instead of removing elements from an iterable list.
+ *
+ * @author Luis F. Canals
+ * @version $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+ * @since december, 2007
+ */
+public class FilteredIterableList<T> extends AbstractSequentialList<T> {
+    private List<T> plainList;
+    private int size;
+    private boolean isEmpty;
+    private int lastIndex = 0;
+    private int lastGetIndex = -1;
+    private T lastGet = null;
+    private ListIterator<T> lastListIterator;
+
+    private final List<? extends T> internal;
+    private final Filter filter;
+
+    private final Map<Integer, T> cached;
+
+    public FilteredIterableList(final List<? extends T> list, 
+            final Filter filter) {
+        super();
+        this.plainList = null;
+        this.filter = filter;
+        this.internal = list;
+        this.isEmpty = ! this.listIterator(0).hasNext();
+        this.size = -1;
+        this.cached = new CacheMap<Integer, T>(4);
+    }
+
+    public T get(final int index) {
+        if(index==0) return super.get(index);
+
+        final T t = cached.get(index);
+        if(t!=null) {
+            // Está entre los cacheados => no queremos que vaya a super.get
+            return cached.get(index);
+        } else {
+            if(index!=this.lastGetIndex || index<0) {
+                this.lastGet = super.get(index);
+                if(this.lastGet==null) throw new IndexOutOfBoundsException();
+                this.lastGetIndex = index;
+            }
+            cached.put(index, this.lastGet);
+            return this.lastGet;
+        }
+    }
+
+    public ListIterator<T> listIterator(final int index) {
+        if(this.plainList==null) {
+            if(index==this.lastIndex+1 && this.lastListIterator!=null) {
+                if(this.lastListIterator.hasNext()) {
+                    this.lastIndex = index;
+                    return this.lastListIterator;
+                } else {
+                    throw new IndexOutOfBoundsException();
+                }
+            } else {
+                final Iterator<? extends T> it = internal.iterator();
+                T nextTmp = null;
+                while(it.hasNext()) {
+                    final T n = it.next();
+                    if(filter.accept(n)) {
+                        nextTmp = n;
+                        break;
+                    }
+                }
+                final T first = nextTmp;
+                final ListIterator<T> li = new ListIterator<T>() {
+                    private int idx = 0;
+                    private T nxt = first;
+                    private void postNext() {
+                        while(it.hasNext()) {
+                            final T n = it.next();
+                            if(filter.accept(n)) {
+                                nxt = n;
+                                return;
+                            }
+                        }
+                        nxt = null;
+                    }
+                    public boolean hasNext() {
+                        return nxt != null;
+                    }
+                    public T next() {
+                        idx++;
+                        final T n = nxt;
+                        postNext();
+                        return n;
+                    }
+                    public int nextIndex() {
+                        return idx;
+                    }
+                    public void add(final T t) {
+                        throw new UnsupportedOperationException();
+                    }
+                    public void set(final T t) {
+                        throw new UnsupportedOperationException();
+                    }
+                    public boolean hasPrevious() {
+                        throw new UnsupportedOperationException();
+                    }
+                    public T previous() {
+                        throw new UnsupportedOperationException();
+                    }
+                    public int previousIndex() {
+                        throw new UnsupportedOperationException();
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+                this.lastListIterator = li;
+                this.lastIndex = 0;
+            }
+
+            for(int i=this.lastIndex; i<index; i++) { 
+                if(!this.lastListIterator.hasNext()) {
+                    throw new IndexOutOfBoundsException();
+                } 
+                this.lastListIterator.next();
+            }
+            this.lastIndex = index;
+            return this.lastListIterator;
+        } else {
+            return plainList.listIterator(index);
+        }
+    }
+
+    public boolean isEmpty() {
+        return this.isEmpty;
+    }
+
+    public int size() {
+        if(this.size==-1) {
+            int s = this.lastIndex + 1;
+            try {
+                for(final Iterator it = this.listIterator(this.lastIndex+1); 
+                        it.hasNext(); ) {
+                    s++;
+                    it.next();
+                }
+            } catch(IndexOutOfBoundsException ioobe) {
+                // Subyacent list is no more present...
+            }
+            this.size = s;
+        }
+        return this.size;
+    }
+
+    public Object[] toArray() {
+        if(this.plainList==null) {
+            final List<T> tmpPlainList = new ArrayList<T>();
+            int size = 0;
+            for(final Iterator<T> it = this.listIterator(0); it.hasNext(); ) {
+                tmpPlainList.add(it.next());
+                size++;
+            }
+            this.plainList = tmpPlainList;
+        }
+        return this.plainList.toArray();
+    }
+
+/*
+    public List<T> subList(final int start, final int end) {
+        return new AbstractList<T>() {
+            public T get(final int index) {
+                return FilteredIterableList.this.get(index-start);
+            }
+            public int size() {
+                return FilteredIterableList.this.size() - start;
+            }
+        };
+    }
+*/
+
+
+    //
+    // Inner classes ---------------------------------
+    //
+
+    /**
+     * Filter to determine which elements should be shown.
+     */
+    public static interface Filter<T> {
+        public boolean accept(final T element);
+    }
+}
Index: src/main/mondrian/util/ConcatenableList.java
===================================================================
--- src/main/mondrian/util/ConcatenableList.java	
+++ src/main/mondrian/util/ConcatenableList.java	
@@ -0,0 +1,162 @@
+/*
+// $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+// This software is subject to the terms of the Common Public License
+// Agreement, available at the following URL:
+// http://www.opensource.org/licenses/cpl.html.
+// Copyright (C) 2006-2007 Julian Hyde
+// All Rights Reserved.
+// You must accept the terms of that agreement to use this software.
+*/
+package mondrian.util;
+
+import java.util.*;
+
+/**
+ * @author Luis F. Canals
+ * @version $Id: //open/mondrian/src/main/mondrian/util/UnsupportedList.java#2 $
+ * @since december, 2007
+ */
+public class ConcatenableList<T> extends AbstractList<T> {
+    private static int nextHashCode=1000;
+    private final List<List<T>> lists;
+    private List<T> plainList;
+    private final int hashCode = nextHashCode++;
+
+    public ConcatenableList() {
+        this.lists = new ArrayList<List<T>>();
+        this.plainList = null;
+    }
+
+
+    /**
+     * Performs a load of all elements into memory, removing sequential
+     * access advantages.
+     */
+    public Object[] toArray() {
+        if(this.plainList==null) {
+            this.plainList = new ArrayList<T>();
+            for(final List<T> list : lists) {
+                for(final T t : list) {
+                    this.plainList.add(t);
+                }
+            }
+        }
+        return this.plainList.toArray();
+    }
+    
+    public boolean addAll(final Collection<? extends T> collection) {
+        if(this.plainList==null) {
+            final List<T> list = (List<T>) collection;
+            return this.lists.add(list);
+        } else {
+            for(final T e : collection) this.plainList.add(e);
+            return true;
+        }
+    }
+
+    public T get(final int index) {
+        if(this.plainList==null) {
+            int idx = index;
+            for(final Iterator<List<T>> it=this.lists.iterator(); 
+                    it.hasNext(); ) {
+                final List<T> list = it.next();
+                try {
+                    return list.get(idx);
+                } catch(IndexOutOfBoundsException iooe) {
+                    idx -= list.size();
+                    if(idx<0) break;
+                }
+            }
+            throw new IndexOutOfBoundsException("Index " + index 
+                    + " out of concatenable list range");
+        } else {
+            return this.plainList.get(index);
+        }
+    }
+
+
+    /**
+     * Adds elements at the end of the list.
+     */
+    public boolean add(final T t) {
+        if(this.plainList==null) {
+            return this.addAll(Collections.singletonList(t));
+        } else {
+            return this.plainList.add(t);
+        }
+    }
+
+    /**
+     * Adds elements at the middle of the list.
+     */
+    public void add(final int index, final T t) {
+        if(this.plainList==null) {
+            throw new UnsupportedOperationException();
+        } else {
+            this.plainList.add(index, t);
+        }
+    }
+
+
+
+    /**
+     * Burnt method!
+     */
+    public T set(final int index, final T t) { 
+        if(this.plainList==null) {
+            throw new UnsupportedOperationException();
+        } else {
+            return this.plainList.set(index, t); 
+        }
+    }
+
+    public int size() {
+        if(this.plainList==null) {
+            int size = 0;
+            for(final List<T> list : lists) size+=list.size();
+            return size;
+        } else return this.plainList.size();
+    }
+
+    public Iterator<T> iterator() {
+        if(this.plainList==null) {
+            return new Iterator<T>() {
+                private T nextObject = null;
+                private int index = 0;
+                public boolean hasNext() {
+                    try {
+                        nextObject = get(index);
+                        return true;
+                    } catch(IndexOutOfBoundsException iooe) {
+                        return false;
+                    }
+                }
+                public T next() {
+                    index++;
+                    return nextObject;
+                }
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        } else {
+            return this.plainList.iterator();
+        }
+    }
+
+    public boolean isEmpty() {
+        if(this.plainList!=null) return this.plainList.isEmpty();
+        if(this.lists.isEmpty()) return true;
+        else {
+            for(final List<T> l : lists) if(!l.isEmpty()) return false;
+            return true;
+        }
+    }
+
+    public void clear() {
+        this.plainList = null;
+        this.lists.clear();
+    }
+
+    public int hashCode() { return this.hashCode; }
+}
Index: src/main/mondrian/util/UnsupportedList.java
===================================================================
--- src/main/mondrian/util/UnsupportedList.java	
+++ src/main/mondrian/util/UnsupportedList.java	
@@ -52,7 +52,8 @@
     }
 
     public Object[] toArray() {
-        throw new UnsupportedOperationException(getClass().getName()+".toArray");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".toArray");
     }
 
     public void add(int index, T element) {
@@ -62,19 +63,24 @@
         throw new UnsupportedOperationException(getClass().getName()+".remove");
     }
     public int indexOf(Object o) {
-        throw new UnsupportedOperationException(getClass().getName()+".indexOf");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".indexOf");
     }
     public int lastIndexOf(Object o) {
-        throw new UnsupportedOperationException(getClass().getName()+".lastIndexOf");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".lastIndexOf");
     }
     public List<T> subList(int fromIndex, int toIndex) {
-        throw new UnsupportedOperationException(getClass().getName()+".subList");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".subList");
     }
     public boolean contains(Object o) {
-        throw new UnsupportedOperationException(getClass().getName()+".contains");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".contains");
     }
     public <T> T[] toArray(T[] a) {
-        throw new UnsupportedOperationException(getClass().getName()+".toArray");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".toArray");
     }
     public boolean add(T o) {
         throw new UnsupportedOperationException(getClass().getName()+".add");
@@ -83,7 +89,8 @@
         throw new UnsupportedOperationException(getClass().getName()+".remove");
     }
     public boolean containsAll(Collection<?> c) {
-        throw new UnsupportedOperationException(getClass().getName()+".containsAll");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".containsAll");
     }
     public boolean addAll(Collection<? extends T> c) {
         throw new UnsupportedOperationException(getClass().getName()+".addAll");
@@ -92,10 +99,12 @@
         throw new UnsupportedOperationException(getClass().getName()+".addAll");
     }
     public boolean removeAll(Collection<?> c) {
-        throw new UnsupportedOperationException(getClass().getName()+".removeAll");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".removeAll");
     }
     public boolean retainAll(Collection<?> c) {
-        throw new UnsupportedOperationException(getClass().getName()+".retainAll");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".retainAll");
     }
     public void clear() {
         throw new UnsupportedOperationException(getClass().getName()+".clear");
@@ -104,16 +113,20 @@
         throw new UnsupportedOperationException(getClass().getName()+".equals");
     }
     public int hashCode() {
-        throw new UnsupportedOperationException(getClass().getName()+".hashCode");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".hashCode");
     }
     public ListIterator<T> listIterator() {
-        throw new UnsupportedOperationException(getClass().getName()+".listIterator");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".listIterator");
     }
     public ListIterator<T> listIterator(int index) {
-        throw new UnsupportedOperationException(getClass().getName()+".listIterator");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".listIterator");
     }
     public Iterator<T> iterator() {
-        throw new UnsupportedOperationException(getClass().getName()+".iterator");
+        throw new UnsupportedOperationException(
+                getClass().getName()+".iterator");
     }
 
     protected class Itr implements Iterator<T> {
@@ -140,7 +153,8 @@
             }
         }
         public void remove() {
-            throw new UnsupportedOperationException(getClass().getName()+".remove");
+            throw new UnsupportedOperationException(
+                    getClass().getName()+".remove");
         }
     }
 
@@ -172,20 +186,30 @@
         }
 
         public void set(T o) {
-/*
-            if (lastRet == -1)
-                throw new IllegalStateException();
-            try {
-                MemberList.this.set(lastRet, o);
-            } catch(IndexOutOfBoundsException e) {
-                throw new ConcurrentModificationException();
-            }
-*/
-            throw new UnsupportedOperationException(getClass().getName()+".set");
+            throw new UnsupportedOperationException(
+                    getClass().getName()+".set");
         }
 
         public void add(T o) {
-            throw new UnsupportedOperationException(getClass().getName()+".add");
+            throw new UnsupportedOperationException(
+                    getClass().getName()+".add");
         }
     }
+
+    
+    /**
+     * Iterator for arrays of a priori unknown size.
+     */
+    protected class ItrUnknownSize extends Itr {
+        public ItrUnknownSize() { super(); }
+
+        public boolean hasNext() {
+            try {
+                get(cursor);
+                return true;
+            } catch(IndexOutOfBoundsException e) {
+                return false;
+            }
+        }
+    }
 }
Index: mondrian.properties
===================================================================
--- mondrian.properties	
+++ mondrian.properties	
@@ -14,9 +14,9 @@
 # Used by the webapp
 mondrian.webapp.connectString=\
 Provider=mondrian;\
-Jdbc=jdbc:odbc:MondrianFoodMart;\
+Jdbc=jdbc:mysql://localhost:3306/foodmart
 Catalog=/WEB-INF/queries/FoodMart.xml;\
-JdbcDrivers=sun.jdbc.odbc.JdbcOdbcDriver;\
+JdbcDrivers=com.mysql.jdbc.Driver
 RoleXX='California manager';
 
 # Where the mondrian.war will be deployed to
@@ -69,11 +69,11 @@
 #driver.classpath=xx
 
 # MySQL: needs user and password set in JDBC URL
-#mondrian.foodmart.jdbcURL=jdbc:mysql://localhost/foodmart?user=foodmart&password=foodmart
-#mondrian.foodmart.jdbcURL=jdbc:mysql://localhost/foodmart
-#mondrian.foodmart.jdbcUser=foodmart
-#mondrian.foodmart.jdbcPassword=foodmart
-#mondrian.jdbcDrivers=com.mysql.jdbc.Driver
+mondrian.foodmart.jdbcURL=jdbc:mysql://localhost/foodmart?user=foodmart&password=foodmart
+mondrian.foodmart.jdbcURL=jdbc:mysql://localhost/foodmart
+mondrian.foodmart.jdbcUser=foodmart
+mondrian.foodmart.jdbcPassword=foodmart
+mondrian.jdbcDrivers=com.mysql.jdbc.Driver
 #driver.classpath=D:/mysql-connector-3.1.12
 
 # Ingres
@@ -114,9 +114,11 @@
 # "public [static] junit.framework.Test suite()".
 # 
 # Example:
-#   mondrian.test.Class=mondrian.test.FoodMartTestCase
-#mondrian.test.Class=
+#mondrian.test.Class=mondrian.rolap.HighDimensionsTest
+mondrian.result.limit=1000000
+mondrian.result.highCardChunkSize=30
 
+
 ###############################################################################
 # Property which determines which tests are run.
 # This is a regular expression as defined by java.util.regex.Pattern.
@@ -142,7 +144,7 @@
 
 # Set mondrian logging information if not provided by containing application.
 # Replace LOG4J_PROPERTIES_LOCATION with path to log4j.properties file.
-#log4j.configuration=file://LOG4J_PROPERTIES_LOCATION/log4j.xml
+log4j.configuration=log4j.properties
 
 ###############################################################################
 # Property which controls the amount of tracing displayed.
@@ -161,7 +163,7 @@
 # Property which determines when a dimension is considered "large".
 # If a dimension has more than this number of members, Mondrian uses a
 # smart member reader (mondrian.rolap.SmartMemberReader).
-#mondrian.rolap.LargeDimensionThreshold=100
+mondrian.rolap.LargeDimensionThreshold=2000000
 
 ###############################################################################
 # Maximum number of simultaneous queries the system will allow.
Index: log4j.properties
===================================================================
--- log4j.properties	
+++ log4j.properties	
@@ -0,0 +1,9 @@
+log4j.rootCategory=WARN
+log4j.logger.mondrian.olap=FATAL,CONSOLE
+log4j.logger.mondrian.rolap=FATAL,CONSOLE
+# Esto es imprescindible para que funcione el test NonEmptyTest
+log4j.logger.mondrian.rolap.RolapUtil=DEBUG
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Threshold=FATAL
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n