KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > xmla > RowsetDefinition


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/xmla/RowsetDefinition.java#46 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2003-2007 Julian Hyde
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 */

10 package mondrian.xmla;
11
12 import mondrian.olap.*;
13 import mondrian.olap.Category;
14 import mondrian.olap.FunTable;
15 import mondrian.olap.fun.FunInfo;
16 import mondrian.rolap.RolapCube;
17 import mondrian.rolap.RolapLevel;
18 import mondrian.rolap.RolapSchema;
19 import mondrian.rolap.RolapAggregator;
20 import mondrian.rolap.RolapMember;
21
22 import java.lang.reflect.Field JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.util.*;
26 import java.text.SimpleDateFormat JavaDoc;
27 import java.text.Format JavaDoc;
28
29 /**
30  * <code>RowsetDefinition</code> defines a rowset, including the columns it
31  * should contain.
32  *
33  * <p>See "XML for Analysis Rowsets", page 38 of the XML for Analysis
34  * Specification, version 1.1.
35  *
36  * @author jhyde
37  * @version $Id: //open/mondrian/src/main/mondrian/xmla/RowsetDefinition.java#46 $
38  */

39 enum RowsetDefinition {
40     /**
41      * Returns a list of XML for Analysis data sources
42      * available on the server or Web Service. (For an
43      * example of how these may be published, see
44      * "XML for Analysis Implementation Walkthrough"
45      * in the XML for Analysis specification.)
46      *
47      * http://msdn2.microsoft.com/en-us/library/ms126129(SQL.90).aspx
48      *
49      *
50      * restrictions
51      *
52      * Not supported
53      */

54     DISCOVER_DATASOURCES(
55         "DISCOVER_DATASOURCES", 0,
56         "Returns a list of XML for Analysis data sources available on the server or Web Service.",
57         new Column[] {
58             DiscoverDatasourcesRowset.DataSourceName,
59             DiscoverDatasourcesRowset.DataSourceDescription,
60             DiscoverDatasourcesRowset.URL,
61             DiscoverDatasourcesRowset.DataSourceInfo,
62             DiscoverDatasourcesRowset.ProviderName,
63             DiscoverDatasourcesRowset.ProviderType,
64             DiscoverDatasourcesRowset.AuthenticationMode,
65         },
66         null /* not sorted */) {
67         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
68             return new DiscoverDatasourcesRowset(request, handler);
69         }
70     },
71
72     /**
73      * Note that SQL Server also returns the data-mining columns.
74      *
75      *
76      * restrictions
77      *
78      * Not supported
79      */

80     DISCOVER_SCHEMA_ROWSETS(
81         "DISCOVER_SCHEMA_ROWSETS", 2,
82         "Returns the names, values, and other information of all supported RequestType enumeration values.",
83         new Column[] {
84             DiscoverSchemaRowsetsRowset.SchemaName,
85             DiscoverSchemaRowsetsRowset.SchemaGuid,
86             DiscoverSchemaRowsetsRowset.Restrictions,
87             DiscoverSchemaRowsetsRowset.Description,
88         },
89         null /* not sorted */) {
90         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
91             return new DiscoverSchemaRowsetsRowset(request, handler);
92         }
93         protected void writeRowsetXmlSchemaRowDef(SaxWriter writer) {
94             writer.startElement("xsd:complexType", new String JavaDoc[] {
95                 "name", "row"
96             });
97             writer.startElement("xsd:sequence");
98             for (Column column : columnDefinitions) {
99                 final String JavaDoc name = XmlaUtil.encodeElementName(column.name);
100
101                 if (column == DiscoverSchemaRowsetsRowset.Restrictions) {
102                     writer.startElement("xsd:element", new String JavaDoc[]{
103                         "sql:field", column.name,
104                         "name", name,
105                         "minOccurs", "0",
106                         "maxOccurs", "unbounded"
107                     });
108                     writer.startElement("xsd:complexType");
109                     writer.startElement("xsd:sequence");
110                     writer.element("xsd:element", new String JavaDoc[]{
111                         "name", "Name",
112                         "type", "xsd:string",
113                         "sql:field", "Name"
114                     });
115                     writer.element("xsd:element", new String JavaDoc[]{
116                         "name", "Type",
117                         "type", "xsd:string",
118                         "sql:field", "Type"
119                     });
120
121                     writer.endElement(); // xsd:sequence
122
writer.endElement(); // xsd:complexType
123
writer.endElement(); // xsd:element
124

125                 } else {
126                     final String JavaDoc xsdType = column.type.columnType;
127
128                     String JavaDoc[] attrs;
129                     if (column.nullable) {
130                         if (column.unbounded) {
131                             attrs = new String JavaDoc[]{
132                                 "sql:field", column.name,
133                                 "name", name,
134                                 "type", xsdType,
135                                 "minOccurs", "0",
136                                 "maxOccurs", "unbounded"
137                             };
138                         } else {
139                             attrs = new String JavaDoc[]{
140                                 "sql:field", column.name,
141                                 "name", name,
142                                 "type", xsdType,
143                                 "minOccurs", "0"
144                             };
145                         }
146                     } else {
147                         if (column.unbounded) {
148                             attrs = new String JavaDoc[]{
149                                 "sql:field", column.name,
150                                 "name", name,
151                                 "type", xsdType,
152                                 "maxOccurs", "unbounded"
153                             };
154                         } else {
155                             attrs = new String JavaDoc[]{
156                                 "sql:field", column.name,
157                                 "name", name,
158                                 "type", xsdType
159                             };
160                         }
161                     }
162                     writer.element("xsd:element", attrs);
163                 }
164             }
165             writer.endElement(); // xsd:sequence
166
writer.endElement(); // xsd:complexType
167
}
168     },
169
170     /**
171      *
172      *
173      *
174      * restrictions
175      *
176      * Not supported
177      */

178     DISCOVER_ENUMERATORS(
179         "DISCOVER_ENUMERATORS", 3,
180         "Returns a list of names, data types, and enumeration values for enumerators supported by the provider of a specific data source.",
181         new Column[] {
182             DiscoverEnumeratorsRowset.EnumName,
183             DiscoverEnumeratorsRowset.EnumDescription,
184             DiscoverEnumeratorsRowset.EnumType,
185             DiscoverEnumeratorsRowset.ElementName,
186             DiscoverEnumeratorsRowset.ElementDescription,
187             DiscoverEnumeratorsRowset.ElementValue,
188         },
189         null /* not sorted */) {
190         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
191             return new DiscoverEnumeratorsRowset(request, handler);
192         }
193     },
194
195     /**
196      *
197      *
198      *
199      * restrictions
200      *
201      * Not supported
202      */

203     DISCOVER_PROPERTIES(
204         "DISCOVER_PROPERTIES", 1,
205         "Returns a list of information and values about the requested properties that are supported by the specified data source provider.",
206         new Column[] {
207             DiscoverPropertiesRowset.PropertyName,
208             DiscoverPropertiesRowset.PropertyDescription,
209             DiscoverPropertiesRowset.PropertyType,
210             DiscoverPropertiesRowset.PropertyAccessType,
211             DiscoverPropertiesRowset.IsRequired,
212             DiscoverPropertiesRowset.Value,
213         },
214         null /* not sorted */) {
215         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
216             return new DiscoverPropertiesRowset(request, handler);
217         }
218     },
219
220     /**
221      *
222      *
223      *
224      * restrictions
225      *
226      * Not supported
227      */

228     DISCOVER_KEYWORDS(
229         "DISCOVER_KEYWORDS", 4,
230         "Returns an XML list of keywords reserved by the provider.",
231         new Column[] {
232             DiscoverKeywordsRowset.Keyword,
233         },
234         null /* not sorted */) {
235         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
236             return new DiscoverKeywordsRowset(request, handler);
237         }
238     },
239
240     /**
241      *
242      *
243      *
244      * restrictions
245      *
246      * Not supported
247      */

248     DISCOVER_LITERALS(
249         "DISCOVER_LITERALS", 5,
250         "Returns information about literals supported by the provider.",
251         new Column[] {
252             DiscoverLiteralsRowset.LiteralName,
253             DiscoverLiteralsRowset.LiteralValue,
254             DiscoverLiteralsRowset.LiteralInvalidChars,
255             DiscoverLiteralsRowset.LiteralInvalidStartingChars,
256             DiscoverLiteralsRowset.LiteralMaxLength,
257         },
258         null /* not sorted */) {
259         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
260             return new DiscoverLiteralsRowset(request, handler);
261         }
262     },
263
264     /**
265      *
266      *
267      *
268      * restrictions
269      *
270      * Not supported
271      */

272     DBSCHEMA_CATALOGS(
273         "DBSCHEMA_CATALOGS", 6,
274         "Returns information about literals supported by the provider.",
275         new Column[] {
276             DbschemaCatalogsRowset.CatalogName,
277             DbschemaCatalogsRowset.Description,
278             DbschemaCatalogsRowset.Roles,
279             DbschemaCatalogsRowset.DateModified,
280         },
281         new Column[] {
282             DbschemaCatalogsRowset.CatalogName,
283         }) {
284         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
285             return new DbschemaCatalogsRowset(request, handler);
286         }
287     },
288
289     /**
290      *
291      *
292      *
293      * restrictions
294      *
295      * Not supported
296      * COLUMN_OLAP_TYPE
297      */

298     DBSCHEMA_COLUMNS(
299         "DBSCHEMA_COLUMNS", 7, null,
300         new Column[] {
301             DbschemaColumnsRowset.TableCatalog,
302             DbschemaColumnsRowset.TableSchema,
303             DbschemaColumnsRowset.TableName,
304             DbschemaColumnsRowset.ColumnName,
305             DbschemaColumnsRowset.OrdinalPosition,
306             DbschemaColumnsRowset.ColumnHasDefault,
307             DbschemaColumnsRowset.ColumnFlags,
308             DbschemaColumnsRowset.IsNullable,
309             DbschemaColumnsRowset.DataType,
310             DbschemaColumnsRowset.CharacterMaximumLength,
311             DbschemaColumnsRowset.CharacterOctetLength,
312             DbschemaColumnsRowset.NumericPrecision,
313             DbschemaColumnsRowset.NumericScale,
314         },
315         new Column[] {
316             DbschemaColumnsRowset.TableCatalog,
317             DbschemaColumnsRowset.TableSchema,
318             DbschemaColumnsRowset.TableName,
319         }) {
320         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
321             return new DbschemaColumnsRowset(request, handler);
322         }
323     },
324
325     /**
326      *
327      *
328      *
329      * restrictions
330      *
331      * Not supported
332      */

333     DBSCHEMA_PROVIDER_TYPES(
334         "DBSCHEMA_PROVIDER_TYPES", 8, null,
335         new Column[] {
336             DbschemaProviderTypesRowset.TypeName,
337             DbschemaProviderTypesRowset.DataType,
338             DbschemaProviderTypesRowset.ColumnSize,
339             DbschemaProviderTypesRowset.LiteralPrefix,
340             DbschemaProviderTypesRowset.LiteralSuffix,
341             DbschemaProviderTypesRowset.IsNullable,
342             DbschemaProviderTypesRowset.CaseSensitive,
343             DbschemaProviderTypesRowset.Searchable,
344             DbschemaProviderTypesRowset.UnsignedAttribute,
345             DbschemaProviderTypesRowset.FixedPrecScale,
346             DbschemaProviderTypesRowset.AutoUniqueValue,
347             DbschemaProviderTypesRowset.IsLong,
348             DbschemaProviderTypesRowset.BestMatch,
349         },
350         new Column[] {
351             DbschemaProviderTypesRowset.DataType,
352         }) {
353         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
354             return new DbschemaProviderTypesRowset(request, handler);
355         }
356     },
357
358     /**
359      * http://msdn2.microsoft.com/en-us/library/ms126299(SQL.90).aspx
360      *
361      * restrictions:
362      * TABLE_CATALOG Optional
363      * TABLE_SCHEMA Optional
364      * TABLE_NAME Optional
365      * TABLE_TYPE Optional
366      * TABLE_OLAP_TYPE Optional
367      *
368      * Not supported
369      */

370     DBSCHEMA_TABLES(
371         "DBSCHEMA_TABLES", 9, null,
372         new Column[] {
373             DbschemaTablesRowset.TableCatalog,
374             DbschemaTablesRowset.TableSchema,
375             DbschemaTablesRowset.TableName,
376             DbschemaTablesRowset.TableType,
377             DbschemaTablesRowset.TableGuid,
378             DbschemaTablesRowset.Description,
379             DbschemaTablesRowset.TablePropId,
380             DbschemaTablesRowset.DateCreated,
381             DbschemaTablesRowset.DateModified,
382             //TableOlapType,
383
},
384         new Column[] {
385             DbschemaTablesRowset.TableType,
386             DbschemaTablesRowset.TableCatalog,
387             DbschemaTablesRowset.TableSchema,
388             DbschemaTablesRowset.TableName,
389         }) {
390         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
391             return new DbschemaTablesRowset(request, handler);
392         }
393     },
394
395     /**
396      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtables_info_rowset.asp
397      *
398      *
399      * restrictions
400      *
401      * Not supported
402      */

403     DBSCHEMA_TABLES_INFO(
404         "DBSCHEMA_TABLES_INFO", 10, null,
405         new Column[] {
406             DbschemaTablesInfoRowset.TableCatalog,
407             DbschemaTablesInfoRowset.TableSchema,
408             DbschemaTablesInfoRowset.TableName,
409             DbschemaTablesInfoRowset.TableType,
410             DbschemaTablesInfoRowset.TableGuid,
411             DbschemaTablesInfoRowset.Bookmarks,
412             DbschemaTablesInfoRowset.BookmarkType,
413             DbschemaTablesInfoRowset.BookmarkDataType,
414             DbschemaTablesInfoRowset.BookmarkMaximumLength,
415             DbschemaTablesInfoRowset.BookmarkInformation,
416             DbschemaTablesInfoRowset.TableVersion,
417             DbschemaTablesInfoRowset.Cardinality,
418             DbschemaTablesInfoRowset.Description,
419             DbschemaTablesInfoRowset.TablePropId,
420         },
421         null /* cannot find doc -- presume unsorted */) {
422         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
423             return new DbschemaTablesInfoRowset(request, handler);
424         }
425     },
426
427     /**
428      * http://msdn2.microsoft.com/en-us/library/ms126032(SQL.90).aspx
429      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapactions_rowset.asp
430      *
431      * restrictions
432      * CATALOG_NAME Optional
433      * SCHEMA_NAME Optional
434      * CUBE_NAME Mandatory
435      * ACTION_NAME Optional
436      * ACTION_TYPE Optional
437      * COORDINATE Mandatory
438      * COORDINATE_TYPE Mandatory
439      * INVOCATION
440      * (Optional) The INVOCATION restriction column defaults to the
441      * value of MDACTION_INVOCATION_INTERACTIVE. To retrieve all
442      * actions, use the MDACTION_INVOCATION_ALL value in the
443      * INVOCATION restriction column.
444      * CUBE_SOURCE
445      * (Optional) A bitmap with one of the following valid values:
446      *
447      * 1 CUBE
448      * 2 DIMENSION
449      *
450      * Default restriction is a value of 1.
451      *
452      * Not supported
453      */

454     MDSCHEMA_ACTIONS(
455         "MDSCHEMA_ACTIONS", 11, null, new Column[] {
456         MdschemaActionsRowset.CubeName,
457         MdschemaActionsRowset.Coordinate,
458         MdschemaActionsRowset.CoordinateType,
459     }, new Column[] {
460         // Spec says sort on CATALOG_NAME, SCHEMA_NAME, CUBE_NAME,
461
// ACTION_NAME.
462
MdschemaActionsRowset.CubeName,
463     }) {
464         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
465             return new MdschemaActionsRowset(request, handler);
466         }
467     },
468
469     /**
470      * http://msdn2.microsoft.com/en-us/library/ms126271(SQL.90).aspx
471      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp
472      *
473      * restrictions
474      * CATALOG_NAME Optional.
475      * SCHEMA_NAME Optional.
476      * CUBE_NAME Optional.
477      * CUBE_TYPE
478      * (Optional) A bitmap with one of these valid values:
479      * 1 CUBE
480      * 2 DIMENSION
481      * Default restriction is a value of 1.
482      * BASE_CUBE_NAME Optional.
483      *
484      * Not supported
485      * CREATED_ON
486      * LAST_SCHEMA_UPDATE
487      * SCHEMA_UPDATED_BY
488      * LAST_DATA_UPDATE
489      * DATA_UPDATED_BY
490      * ANNOTATIONS
491      */

492     MDSCHEMA_CUBES(
493         "MDSCHEMA_CUBES", 12, null,
494         new Column[] {
495             MdschemaCubesRowset.CatalogName,
496             MdschemaCubesRowset.SchemaName,
497             MdschemaCubesRowset.CubeName,
498             MdschemaCubesRowset.CubeType,
499             MdschemaCubesRowset.CubeGuid,
500             MdschemaCubesRowset.CreatedOn,
501             MdschemaCubesRowset.LastSchemaUpdate,
502             MdschemaCubesRowset.SchemaUpdatedBy,
503             MdschemaCubesRowset.LastDataUpdate,
504             MdschemaCubesRowset.DataUpdatedBy,
505             MdschemaCubesRowset.IsDrillthroughEnabled,
506             MdschemaCubesRowset.IsWriteEnabled,
507             MdschemaCubesRowset.IsLinkable,
508             MdschemaCubesRowset.IsSqlEnabled,
509             MdschemaCubesRowset.Description
510         },
511         new Column[] {
512             MdschemaCubesRowset.CatalogName,
513             MdschemaCubesRowset.SchemaName,
514             MdschemaCubesRowset.CubeName,
515         }) {
516         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
517             return new MdschemaCubesRowset(request, handler);
518         }
519     },
520
521     /**
522      * http://msdn2.microsoft.com/en-us/library/ms126180(SQL.90).aspx
523      * http://msdn2.microsoft.com/en-us/library/ms126180.aspx
524      *
525      * restrictions
526      * CATALOG_NAME Optional.
527      * SCHEMA_NAME Optional.
528      * CUBE_NAME Optional.
529      * DIMENSION_NAME Optional.
530      * DIMENSION_UNIQUE_NAME Optional.
531      * CUBE_SOURCE (Optional) A bitmap with one of the following valid values:
532      * 1 CUBE
533      * 2 DIMENSION
534      * Default restriction is a value of 1.
535      *
536      * DIMENSION_VISIBILITY (Optional) A bitmap with one of the following valid values:
537      * 1 Visible
538      * 2 Not visible
539      * Default restriction is a value of 1.
540      */

541     MDSCHEMA_DIMENSIONS(
542         "MDSCHEMA_DIMENSIONS", 13, null,
543         new Column[] {
544             MdschemaDimensionsRowset.CatalogName,
545             MdschemaDimensionsRowset.SchemaName,
546             MdschemaDimensionsRowset.CubeName,
547             MdschemaDimensionsRowset.DimensionName,
548             MdschemaDimensionsRowset.DimensionUniqueName,
549             MdschemaDimensionsRowset.DimensionGuid,
550             MdschemaDimensionsRowset.DimensionCaption,
551             MdschemaDimensionsRowset.DimensionOrdinal,
552             MdschemaDimensionsRowset.DimensionType,
553             MdschemaDimensionsRowset.DimensionCardinality,
554             MdschemaDimensionsRowset.DefaultHierarchy,
555             MdschemaDimensionsRowset.Description,
556             MdschemaDimensionsRowset.IsVirtual,
557             MdschemaDimensionsRowset.IsReadWrite,
558             MdschemaDimensionsRowset.DimensionUniqueSettings,
559             MdschemaDimensionsRowset.DimensionMasterUniqueName,
560             MdschemaDimensionsRowset.DimensionIsVisible,
561         },
562         new Column[] {
563             MdschemaDimensionsRowset.CatalogName,
564             MdschemaDimensionsRowset.SchemaName,
565             MdschemaDimensionsRowset.CubeName,
566             MdschemaDimensionsRowset.DimensionName,
567         }) {
568         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
569             return new MdschemaDimensionsRowset(request, handler);
570         }
571     },
572
573     /**
574      * http://msdn2.microsoft.com/en-us/library/ms126257(SQL.90).aspx
575      * http://msdn.microsoft.com/library/en-us/oledb/htm/olapfunctions_rowset.asp
576      *
577      * restrictions
578      * LIBRARY_NAME Optional.
579      * INTERFACE_NAME Optional.
580      * FUNCTION_NAME Optional.
581      * ORIGIN Optional.
582      *
583      * Not supported
584      * DLL_NAME
585      * Optional
586      * HELP_FILE
587      * Optional
588      * HELP_CONTEXT
589      * Optional
590      * - SQL Server xml schema says that this must be present
591      * OBJECT
592      * Optional
593      * CAPTION The display caption for the function.
594      */

595     MDSCHEMA_FUNCTIONS(
596         "MDSCHEMA_FUNCTIONS", 14, null,
597         new Column[] {
598             MdschemaFunctionsRowset.FunctionName,
599             MdschemaFunctionsRowset.Description,
600             MdschemaFunctionsRowset.ParameterList,
601             MdschemaFunctionsRowset.ReturnType,
602             MdschemaFunctionsRowset.Origin,
603             MdschemaFunctionsRowset.InterfaceName,
604             MdschemaFunctionsRowset.LibraryName,
605             MdschemaFunctionsRowset.Caption,
606         },
607         new Column[] {
608             MdschemaFunctionsRowset.LibraryName,
609             MdschemaFunctionsRowset.InterfaceName,
610             MdschemaFunctionsRowset.FunctionName,
611             MdschemaFunctionsRowset.Origin,
612         }) {
613         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
614             return new MdschemaFunctionsRowset(request, handler);
615         }
616     },
617
618     /**
619      * http://msdn2.microsoft.com/en-us/library/ms126062(SQL.90).aspx
620      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp
621      *
622      * restrictions
623      * CATALOG_NAME Optional.
624      * SCHEMA_NAME Optional.
625      * CUBE_NAME Optional.
626      * DIMENSION_UNIQUE_NAME Optional.
627      * HIERARCHY_NAME Optional.
628      * HIERARCHY_UNIQUE_NAME Optional.
629      * HIERARCHY_ORIGIN
630      * (Optional) A default restriction is in effect
631      * on MD_USER_DEFINED and MD_SYSTEM_ENABLED.
632      * CUBE_SOURCE
633      * (Optional) A bitmap with one of the following valid values:
634      * 1 CUBE
635      * 2 DIMENSION
636      * Default restriction is a value of 1.
637      * HIERARCHY_VISIBILITY
638      * (Optional) A bitmap with one of the following valid values:
639      * 1 Visible
640      * 2 Not visible
641      * Default restriction is a value of 1.
642      *
643      * Not supported
644      * HIERARCHY_IS_VISIBLE
645      * HIERARCHY_ORIGIN
646      * HIERARCHY_DISPLAY_FOLDER
647      * INSTANCE_SELECTION
648      */

649     MDSCHEMA_HIERARCHIES(
650         "MDSCHEMA_HIERARCHIES", 15, null,
651         new Column[] {
652             MdschemaHierarchiesRowset.CatalogName,
653             MdschemaHierarchiesRowset.SchemaName,
654             MdschemaHierarchiesRowset.CubeName,
655             MdschemaHierarchiesRowset.DimensionUniqueName,
656             MdschemaHierarchiesRowset.HierarchyName,
657             MdschemaHierarchiesRowset.HierarchyUniqueName,
658             MdschemaHierarchiesRowset.HierarchyGuid,
659             MdschemaHierarchiesRowset.HierarchyCaption,
660             MdschemaHierarchiesRowset.DimensionType,
661             MdschemaHierarchiesRowset.HierarchyCardinality,
662             MdschemaHierarchiesRowset.DefaultMember,
663             MdschemaHierarchiesRowset.AllMember,
664             MdschemaHierarchiesRowset.Description,
665             MdschemaHierarchiesRowset.Structure,
666             MdschemaHierarchiesRowset.IsVirtual,
667             MdschemaHierarchiesRowset.IsReadWrite,
668             MdschemaHierarchiesRowset.DimensionUniqueSettings,
669             MdschemaHierarchiesRowset.DimensionIsVisible,
670             MdschemaHierarchiesRowset.HierarchyOrdinal,
671             MdschemaHierarchiesRowset.DimensionIsShared,
672             MdschemaHierarchiesRowset.ParentChild,
673         },
674         new Column[] {
675             MdschemaHierarchiesRowset.CatalogName,
676             MdschemaHierarchiesRowset.SchemaName,
677             MdschemaHierarchiesRowset.CubeName,
678             MdschemaHierarchiesRowset.DimensionUniqueName,
679             MdschemaHierarchiesRowset.HierarchyName,
680         }) {
681         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
682             return new MdschemaHierarchiesRowset(request, handler);
683         }
684     },
685
686     /**
687      * http://msdn2.microsoft.com/en-us/library/ms126038(SQL.90).aspx
688      * http://msdn.microsoft.com/library/en-us/oledb/htm/olaplevels_rowset.asp
689      *
690      * restriction
691      * CATALOG_NAME Optional.
692      * SCHEMA_NAME Optional.
693      * CUBE_NAME Optional.
694      * DIMENSION_UNIQUE_NAME Optional.
695      * HIERARCHY_UNIQUE_NAME Optional.
696      * LEVEL_NAME Optional.
697      * LEVEL_UNIQUE_NAME Optional.
698      * LEVEL_ORIGIN
699      * (Optional) A default restriction is in effect
700      * on MD_USER_DEFINED and MD_SYSTEM_ENABLED
701      * CUBE_SOURCE
702      * (Optional) A bitmap with one of the following valid values:
703      * 1 CUBE
704      * 2 DIMENSION
705      * Default restriction is a value of 1.
706      * LEVEL_VISIBILITY
707      * (Optional) A bitmap with one of the following values:
708      * 1 Visible
709      * 2 Not visible
710      * Default restriction is a value of 1.
711      *
712      * Not supported
713      * CUSTOM_ROLLUP_SETTINGS
714      * LEVEL_UNIQUE_SETTINGS
715      * LEVEL_ORDERING_PROPERTY
716      * LEVEL_DBTYPE
717      * LEVEL_MASTER_UNIQUE_NAME
718      * LEVEL_NAME_SQL_COLUMN_NAME Customers:(All)!NAME
719      * LEVEL_KEY_SQL_COLUMN_NAME Customers:(All)!KEY
720      * LEVEL_UNIQUE_NAME_SQL_COLUMN_NAME Customers:(All)!UNIQUE_NAME
721      * LEVEL_ATTRIBUTE_HIERARCHY_NAME
722      * LEVEL_KEY_CARDINALITY
723      * LEVEL_ORIGIN
724      *
725      */

726     MDSCHEMA_LEVELS(
727         "MDSCHEMA_LEVELS", 16, null,
728         new Column[] {
729             MdschemaLevelsRowset.CatalogName,
730             MdschemaLevelsRowset.SchemaName,
731             MdschemaLevelsRowset.CubeName,
732             MdschemaLevelsRowset.DimensionUniqueName,
733             MdschemaLevelsRowset.HierarchyUniqueName,
734             MdschemaLevelsRowset.LevelName,
735             MdschemaLevelsRowset.LevelUniqueName,
736             MdschemaLevelsRowset.LevelGuid,
737             MdschemaLevelsRowset.LevelCaption,
738             MdschemaLevelsRowset.LevelNumber,
739             MdschemaLevelsRowset.LevelCardinality,
740             MdschemaLevelsRowset.LevelType,
741             MdschemaLevelsRowset.CustomRollupSettings,
742             MdschemaLevelsRowset.LevelUniqueSettings,
743             MdschemaLevelsRowset.LevelIsVisible,
744             MdschemaLevelsRowset.Description,
745         },
746         new Column[] {
747             MdschemaLevelsRowset.CatalogName,
748             MdschemaLevelsRowset.SchemaName,
749             MdschemaLevelsRowset.CubeName,
750             MdschemaLevelsRowset.DimensionUniqueName,
751             MdschemaLevelsRowset.HierarchyUniqueName,
752             MdschemaLevelsRowset.LevelNumber,
753         }) {
754         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
755             return new MdschemaLevelsRowset(request, handler);
756         }
757     },
758
759     /**
760      * http://msdn2.microsoft.com/en-us/library/ms126250(SQL.90).aspx
761      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapmeasures_rowset.asp
762      *
763      * restrictions
764      * CATALOG_NAME Optional.
765      * SCHEMA_NAME Optional.
766      * CUBE_NAME Optional.
767      * MEASURE_NAME Optional.
768      * MEASURE_UNIQUE_NAME Optional.
769      * CUBE_SOURCE
770      * (Optional) A bitmap with one of the following valid values:
771      * 1 CUBE
772      * 2 DIMENSION
773      * Default restriction is a value of 1.
774      * MEASURE_VISIBILITY
775      * (Optional) A bitmap with one of the following valid values:
776      * 1 Visible
777      * 2 Not Visible
778      * Default restriction is a value of 1.
779      *
780      * Not supported
781      * MEASURE_GUID
782      * NUMERIC_PRECISION
783      * NUMERIC_SCALE
784      * MEASURE_UNITS
785      * EXPRESSION
786      * MEASURE_NAME_SQL_COLUMN_NAME
787      * MEASURE_UNQUALIFIED_CAPTION
788      * MEASUREGROUP_NAME
789      * MEASURE_DISPLAY_FOLDER
790      * DEFAULT_FORMAT_STRING
791      */

792     MDSCHEMA_MEASURES(
793         "MDSCHEMA_MEASURES", 17, null,
794         new Column[] {
795             MdschemaMeasuresRowset.CatalogName,
796             MdschemaMeasuresRowset.SchemaName,
797             MdschemaMeasuresRowset.CubeName,
798             MdschemaMeasuresRowset.MeasureName,
799             MdschemaMeasuresRowset.MeasureUniqueName,
800             MdschemaMeasuresRowset.MeasureCaption,
801             MdschemaMeasuresRowset.MeasureGuid,
802             MdschemaMeasuresRowset.MeasureAggregator,
803             MdschemaMeasuresRowset.DataType,
804             MdschemaMeasuresRowset.MeasureIsVisible,
805             MdschemaMeasuresRowset.LevelsList,
806             MdschemaMeasuresRowset.Description,
807         },
808         new Column[] {
809             MdschemaMeasuresRowset.CatalogName,
810             MdschemaMeasuresRowset.SchemaName,
811             MdschemaMeasuresRowset.CubeName,
812             MdschemaMeasuresRowset.MeasureName,
813         }) {
814         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
815             return new MdschemaMeasuresRowset(request, handler);
816         }
817     },
818
819     /**
820      *
821      * http://msdn2.microsoft.com/es-es/library/ms126046.aspx
822      *
823      *
824      * restrictions
825      * CATALOG_NAME Optional.
826      * SCHEMA_NAME Optional.
827      * CUBE_NAME Optional.
828      * DIMENSION_UNIQUE_NAME Optional.
829      * HIERARCHY_UNIQUE_NAME Optional.
830      * LEVEL_UNIQUE_NAME Optional.
831      * LEVEL_NUMBER Optional.
832      * MEMBER_NAME Optional.
833      * MEMBER_UNIQUE_NAME Optional.
834      * MEMBER_CAPTION Optional.
835      * MEMBER_TYPE Optional.
836      * TREE_OP (Optional) Only applies to a single member:
837      * MDTREEOP_ANCESTORS (0x20) returns all of the ancestors.
838      * MDTREEOP_CHILDREN (0x01) returns only the immediate children.
839      * MDTREEOP_SIBLINGS (0x02) returns members on the same level.
840      * MDTREEOP_PARENT (0x04) returns only the immediate parent.
841      * MDTREEOP_SELF (0x08) returns itself in the list of
842      * returned rows.
843      * MDTREEOP_DESCENDANTS (0x10) returns all of the descendants.
844      * CUBE_SOURCE (Optional) A bitmap with one of the
845      * following valid values:
846      * 1 CUBE
847      * 2 DIMENSION
848      * Default restriction is a value of 1.
849      *
850      * Not supported
851      */

852     MDSCHEMA_MEMBERS(
853         "MDSCHEMA_MEMBERS", 18, null,
854         new Column[] {
855             MdschemaMembersRowset.CatalogName,
856             MdschemaMembersRowset.SchemaName,
857             MdschemaMembersRowset.CubeName,
858             MdschemaMembersRowset.DimensionUniqueName,
859             MdschemaMembersRowset.HierarchyUniqueName,
860             MdschemaMembersRowset.LevelUniqueName,
861             MdschemaMembersRowset.LevelNumber,
862             MdschemaMembersRowset.MemberOrdinal,
863             MdschemaMembersRowset.MemberName,
864             MdschemaMembersRowset.MemberUniqueName,
865             MdschemaMembersRowset.MemberType,
866             MdschemaMembersRowset.MemberGuid,
867             MdschemaMembersRowset.MemberCaption,
868             MdschemaMembersRowset.ChildrenCardinality,
869             MdschemaMembersRowset.ParentLevel,
870             MdschemaMembersRowset.ParentUniqueName,
871             MdschemaMembersRowset.ParentCount,
872             MdschemaMembersRowset.TreeOp,
873             MdschemaMembersRowset.Depth,
874         },
875         new Column[] {
876             MdschemaMembersRowset.CatalogName,
877             MdschemaMembersRowset.SchemaName,
878             MdschemaMembersRowset.CubeName,
879             MdschemaMembersRowset.DimensionUniqueName,
880             MdschemaMembersRowset.HierarchyUniqueName,
881             MdschemaMembersRowset.LevelUniqueName,
882             MdschemaMembersRowset.LevelNumber,
883             MdschemaMembersRowset.MemberOrdinal,
884         }) {
885         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
886             return new MdschemaMembersRowset(request, handler);
887         }
888     },
889
890     /**
891      * http://msdn2.microsoft.com/en-us/library/ms126309(SQL.90).aspx
892      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp
893      *
894      * restrictions
895      * CATALOG_NAME Mandatory
896      * SCHEMA_NAME Optional
897      * CUBE_NAME Optional
898      * DIMENSION_UNIQUE_NAME Optional
899      * HIERARCHY_UNIQUE_NAME Optional
900      * LEVEL_UNIQUE_NAME Optional
901      *
902      * MEMBER_UNIQUE_NAME Optional
903      * PROPERTY_NAME Optional
904      * PROPERTY_TYPE Optional
905      * PROPERTY_CONTENT_TYPE
906      * (Optional) A default restriction is in place on MDPROP_MEMBER
907      * OR MDPROP_CELL.
908      * PROPERTY_ORIGIN
909      * (Optional) A default restriction is in place on MD_USER_DEFINED
910      * OR MD_SYSTEM_ENABLED
911      * CUBE_SOURCE
912      * (Optional) A bitmap with one of the following valid values:
913      * 1 CUBE
914      * 2 DIMENSION
915      * Default restriction is a value of 1.
916      * PROPERTY_VISIBILITY
917      * (Optional) A bitmap with one of the following valid values:
918      * 1 Visible
919      * 2 Not visible
920      * Default restriction is a value of 1.
921      *
922      * Not supported
923      * PROPERTY_ORIGIN
924      * CUBE_SOURCE
925      * PROPERTY_VISIBILITY
926      * CHARACTER_MAXIMUM_LENGTH
927      * CHARACTER_OCTET_LENGTH
928      * NUMERIC_PRECISION
929      * NUMERIC_SCALE
930      * DESCRIPTION
931      * SQL_COLUMN_NAME
932      * LANGUAGE
933      * PROPERTY_ATTRIBUTE_HIERARCHY_NAME
934      * PROPERTY_CARDINALITY
935      * MIME_TYPE
936      * PROPERTY_IS_VISIBLE
937      */

938     MDSCHEMA_PROPERTIES(
939         "MDSCHEMA_PROPERTIES", 19, null,
940         new Column[] {
941             MdschemaPropertiesRowset.CatalogName,
942             MdschemaPropertiesRowset.SchemaName,
943             MdschemaPropertiesRowset.CubeName,
944             MdschemaPropertiesRowset.DimensionUniqueName,
945             MdschemaPropertiesRowset.HierarchyUniqueName,
946             MdschemaPropertiesRowset.LevelUniqueName,
947             MdschemaPropertiesRowset.MemberUniqueName,
948             MdschemaPropertiesRowset.PropertyName,
949             MdschemaPropertiesRowset.PropertyCaption,
950             MdschemaPropertiesRowset.PropertyType,
951             MdschemaPropertiesRowset.DataType,
952             MdschemaPropertiesRowset.PropertyContentType,
953             MdschemaPropertiesRowset.Description
954         },
955         null /* not sorted */) {
956         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
957             return new MdschemaPropertiesRowset(request, handler);
958         }
959     },
960
961     /**
962      * http://msdn2.microsoft.com/en-us/library/ms126290(SQL.90).aspx
963      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp
964      *
965      * restrictions
966      * CATALOG_NAME Optional.
967      * SCHEMA_NAME Optional.
968      * CUBE_NAME Optional.
969      * SET_NAME Optional.
970      * SCOPE Optional.
971      * HIERARCHY_UNIQUE_NAME Optional.
972      * CUBE_SOURCE Optional.
973      * Note: Only one hierarchy can be included, and only those named
974      * sets whose hierarchies exactly match the restriction are
975      * returned.
976      *
977      * Not supported
978      * EXPRESSION
979      * DIMENSIONS
980      * SET_DISPLAY_FOLDER
981      */

982     MDSCHEMA_SETS(
983         "MDSCHEMA_SETS", 20, null,
984         new Column[] {
985             MdschemaSetsRowset.CatalogName,
986             MdschemaSetsRowset.SchemaName,
987             MdschemaSetsRowset.CubeName,
988             MdschemaSetsRowset.SetName,
989             MdschemaSetsRowset.Scope,
990         },
991         new Column[] {
992             MdschemaSetsRowset.CatalogName,
993             MdschemaSetsRowset.SchemaName,
994             MdschemaSetsRowset.CubeName,
995         }) {
996         public Rowset getRowset(XmlaRequest request, XmlaHandler handler) {
997             return new MdschemaSetsRowset(request, handler);
998         }
999     };
1000
1001    final Column[] columnDefinitions;
1002    final Column[] sortColumnDefinitions;
1003
1004    /**
1005     * Date the schema was last modified.
1006     *
1007     * <p>TODO: currently schema grammar does not support modify date
1008     * so we return just some date for now.
1009     */

1010    private static final String JavaDoc dateModified = "2005-01-25T17:35:32";
1011    private final String JavaDoc description;
1012
1013    /**
1014     * Creates a rowset definition.
1015     *
1016     * @param name
1017     * @param ordinal
1018     * @param description
1019     * @param columnDefinitions List of column definitions
1020     * @param sortColumnDefinitions List of column definitions to sort on,
1021     * or null if the rowset is not sorted
1022     */

1023    RowsetDefinition(
1024        String JavaDoc name,
1025        int ordinal,
1026        String JavaDoc description,
1027        Column[] columnDefinitions,
1028        Column[] sortColumnDefinitions)
1029    {
1030        this.columnDefinitions = columnDefinitions;
1031        this.sortColumnDefinitions = sortColumnDefinitions;
1032        this.description = description;
1033    }
1034
1035    public abstract Rowset getRowset(XmlaRequest request, XmlaHandler handler);
1036
1037    public Column lookupColumn(String JavaDoc name) {
1038        for (Column columnDefinition : columnDefinitions) {
1039            if (columnDefinition.name.equals(name)) {
1040                return columnDefinition;
1041            }
1042        }
1043        return null;
1044    }
1045
1046    /**
1047     * Returns a comparator with which to sort rows of this rowset definition.
1048     * The sort order is defined by the {@link #sortColumnDefinitions} field.
1049     * If the rowset is not sorted, returns null.
1050     */

1051    Comparator<Rowset.Row> getComparator() {
1052        if (sortColumnDefinitions == null) {
1053            return null;
1054        }
1055        return new Comparator<Rowset.Row>() {
1056            public int compare(Rowset.Row row1, Rowset.Row row2) {
1057                // A faster implementation is welcome.
1058
for (Column sortColumn : sortColumnDefinitions) {
1059                    Comparable JavaDoc val1 = (Comparable JavaDoc) row1.get(sortColumn.name);
1060                    Comparable JavaDoc val2 = (Comparable JavaDoc) row2.get(sortColumn.name);
1061                    if ((val1 == null) && (val2 == null)) {
1062                        // columns can be optional, compare next column
1063
continue;
1064                    } else if (val1 == null) {
1065                        return -1;
1066                    } else if (val2 == null) {
1067                        return 1;
1068                    } else if (val1 instanceof String JavaDoc &&
1069                        val2 instanceof String JavaDoc) {
1070                        int v =
1071                            ((String JavaDoc) val1).compareToIgnoreCase((String JavaDoc) val2);
1072                        // if equal (= 0), compare next column
1073
if (v != 0) {
1074                            return v;
1075                        }
1076                    } else {
1077                        int v = val1.compareTo(val2);
1078                        // if equal (= 0), compare next column
1079
if (v != 0) {
1080                            return v;
1081                        }
1082                    }
1083                }
1084                return 0;
1085            }
1086        };
1087    }
1088
1089    /**
1090     * Generates an XML schema description to the writer.
1091     * This is broken into top, Row definition and bottom so that on a
1092     * case by case basis a RowsetDefinition can redefine the Row
1093     * definition output. The default assumes a flat set of elements, but
1094     * for example, SchemaRowsets has a element with child elements.
1095     *
1096     * @param writer SAX writer
1097     * @see XmlaHandler#writeDatasetXmlSchema(SaxWriter, int)
1098     */

1099    void writeRowsetXmlSchema(SaxWriter writer) {
1100        writeRowsetXmlSchemaTop(writer);
1101        writeRowsetXmlSchemaRowDef(writer);
1102        writeRowsetXmlSchemaBottom(writer);
1103    }
1104    protected void writeRowsetXmlSchemaTop(SaxWriter writer) {
1105        writer.startElement("xsd:schema", new String JavaDoc[] {
1106            "xmlns:xsd", XmlaConstants.NS_XSD,
1107            "xmlns", XmlaConstants.NS_XMLA_ROWSET,
1108            "xmlns:xsi", XmlaConstants.NS_XSI,
1109            "xmlns:sql", "urn:schemas-microsoft-com:xml-sql",
1110            "targetNamespace", XmlaConstants.NS_XMLA_ROWSET,
1111            "elementFormDefault", "qualified"
1112        });
1113
1114        writer.startElement("xsd:element", new String JavaDoc[] {
1115            "name", "root"
1116        });
1117        writer.startElement("xsd:complexType");
1118        writer.startElement("xsd:sequence");
1119        writer.element("xsd:element", new String JavaDoc[] {
1120            "name", "row",
1121            "type", "row",
1122            "minOccurs", "0",
1123            "maxOccurs", "unbounded"
1124        });
1125        writer.endElement(); // xsd:sequence
1126
writer.endElement(); // xsd:complexType
1127
writer.endElement(); // xsd:element
1128

1129        // MS SQL includes this in its schema section even thought
1130
// its not need for most queries.
1131
writer.startElement("xsd:simpleType", new String JavaDoc[] {
1132            "name", "uuid"
1133        });
1134        writer.startElement("xsd:restriction", new String JavaDoc[] {
1135            "base", "xsd:string"
1136        });
1137        writer.element("xsd:pattern", new String JavaDoc[] {
1138            "value", "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
1139        });
1140
1141        writer.endElement(); // xsd:restriction
1142
writer.endElement(); // xsd:simpleType
1143

1144    }
1145    protected void writeRowsetXmlSchemaRowDef(SaxWriter writer) {
1146        writer.startElement("xsd:complexType", new String JavaDoc[] {
1147            "name", "row"
1148        });
1149        writer.startElement("xsd:sequence");
1150        for (Column column : columnDefinitions) {
1151            final String JavaDoc name = XmlaUtil.encodeElementName(column.name);
1152            final String JavaDoc xsdType = column.type.columnType;
1153
1154            String JavaDoc[] attrs;
1155            if (column.nullable) {
1156                if (column.unbounded) {
1157                    attrs = new String JavaDoc[]{
1158                        "sql:field", column.name,
1159                        "name", name,
1160                        "type", xsdType,
1161                        "minOccurs", "0",
1162                        "maxOccurs", "unbounded"
1163                    };
1164                } else {
1165                    attrs = new String JavaDoc[]{
1166                        "sql:field", column.name,
1167                        "name", name,
1168                        "type", xsdType,
1169                        "minOccurs", "0"
1170                    };
1171                }
1172            } else {
1173                if (column.unbounded) {
1174                    attrs = new String JavaDoc[]{
1175                        "sql:field", column.name,
1176                        "name", name,
1177                        "type", xsdType,
1178                        "maxOccurs", "unbounded"
1179                    };
1180                } else {
1181                    attrs = new String JavaDoc[]{
1182                        "sql:field", column.name,
1183                        "name", name,
1184                        "type", xsdType
1185                    };
1186                }
1187            }
1188            writer.element("xsd:element", attrs);
1189        }
1190        writer.endElement(); // xsd:sequence
1191
writer.endElement(); // xsd:complexType
1192
}
1193    protected void writeRowsetXmlSchemaBottom(SaxWriter writer) {
1194        writer.endElement(); // xsd:schema
1195
}
1196
1197    enum Type {
1198        String("xsd:string"),
1199        StringArray("xsd:string"),
1200        Array("xsd:string"),
1201        Enumeration("xsd:string"),
1202        EnumerationArray("xsd:string"),
1203        EnumString("xsd:string"),
1204        Boolean("xsd:boolean"),
1205        StringSometimesArray("xsd:string"),
1206        Integer("xsd:int"),
1207        UnsignedInteger("xsd:unsignedInt"),
1208        DateTime("xsd:dateTime"),
1209        Short("xsd:short"),
1210        UUID("uuid"),
1211        UnsignedShort("xsd:unsignedShort"),
1212        Long("xsd:long"),
1213        UnsignedLong("xsd:unsignedLong");
1214
1215        public final String JavaDoc columnType;
1216
1217        Type(String JavaDoc columnType) {
1218            this.columnType = columnType;
1219        }
1220
1221        boolean isEnum() {
1222            return this == Enumeration ||
1223                this == EnumerationArray ||
1224                this == EnumString;
1225        }
1226
1227        String JavaDoc getName() {
1228            return this == String ? "string" : name();
1229        }
1230    }
1231
1232    private static DBType getDBTypeFromProperty(Property prop) {
1233        switch (prop.getType()) {
1234        case TYPE_STRING:
1235            return DBType.WSTR;
1236        case TYPE_NUMERIC:
1237            return DBType.R8;
1238        case TYPE_BOOLEAN:
1239            return DBType.BOOL;
1240        case TYPE_OTHER:
1241        default:
1242            // TODO: what type is it really, its not a string
1243
return DBType.WSTR;
1244        }
1245    }
1246
1247    /**
1248     * The only OLE DB Types Indicators returned by SQL Server are thoses coded
1249     * below.
1250     * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtype_indicators.asp
1251     */

1252
1253    enum DBType {
1254        /*
1255        * The following values exactly match VARENUM
1256        * in Automation and may be used in VARIANT.
1257        */

1258        I4("INTEGER", 3, "DBTYPE_I4", "A four-byte, signed integer: INTEGER"),
1259
1260        R8("DOUBLE", 5,
1261            "DBTYPE_R8", "A double-precision floating-point value: Double"),
1262
1263        CY("CURRENCY", 6, "DBTYPE_CY", "A currency value: LARGE_INTEGER, Currency is a fixed-point number with four digits to the right of the decimal point. It is stored in an eight-byte signed integer, scaled by 10,000."),
1264
1265        BOOL("BOOLEAN", 11, "DBTYPE_BOOL", "A Boolean value stored in the same way as in Automation: VARIANT_BOOL; 0 means false and ~0 (bitwise, the value is not 0; that is, all bits are set to 1) means true."),
1266
1267        /**
1268         * Used by SQL Server for value.
1269         */

1270        VARIANT("VARIANT", 12, "DBTYPE_VARIANT", "An Automation VARIANT"),
1271
1272        /**
1273         * Used by SQL Server for font size.
1274         */

1275        UI2("UNSIGNED_SHORT", 18, "DBTYPE_UI2", "A two-byte, unsigned integer"),
1276
1277        /**
1278         * Used by SQL Server for colors, font flags and cell ordinal.
1279         */

1280        UI4("UNSIGNED_INTEGER", 19, "DBTYPE_UI4", "A four-byte, unsigned integer"),
1281
1282        /*
1283        * The following values exactly match VARENUM
1284        * in Automation but cannot be used in VARIANT.
1285        */

1286        I8("LARGE_INTEGER", 20, "DBTYPE_I8", "An eight-byte, signed integer: LARGE_INTEGER"),
1287
1288        /*
1289        * The following values are not in VARENUM in OLE.
1290        */

1291        WSTR("STRING", 130, "DBTYPE_WSTR", "A null-terminated Unicode character string: wchar_t[length]; If DBTYPE_WSTR is used by itself, the number of bytes allocated for the string, including the null-termination character, is specified by cbMaxLen in the DBBINDING structure. If DBTYPE_WSTR is combined with DBTYPE_BYREF, the number of bytes allocated for the string, including the null-termination character, is at least the length of the string plus two. In either case, the actual length of the string is determined from the bound length value. The maximum length of the string is the number of allocated bytes divided by sizeof(wchar_t) and truncated to the nearest integer.");
1292
1293
1294        /**
1295         * The length of a non-numeric column or parameter that refers to either
1296         * the maximum or the length defined for this type by the provider. For
1297         * character data, this is the maximum or defined length in characters.
1298         * For DateTime data types, this is the length of the string
1299         * representation (assuming the maximum allowed precision of the
1300         * fractional seconds component).
1301         *
1302         * If the data type is numeric, this is the upper bound on the maximum
1303         * precision of the data type.
1304         int columnSize;
1305         */

1306
1307        private final String JavaDoc userName;
1308        private final int userOrdinal;
1309        private final String JavaDoc description;
1310        /**
1311         * A Boolean that indicates whether the data type is nullable.
1312         * VARIANT_TRUE indicates that the data type is nullable.
1313         * VARIANT_FALSE indicates that the data type is not nullable.
1314         * NULL-- indicates that it is not known whether the data type is
1315         * nullable.
1316         boolean isNullable;
1317         */

1318
1319        String JavaDoc dbTypeIndicator;
1320
1321        DBType(
1322            String JavaDoc userName,
1323            int userOrdinal,
1324            String JavaDoc dbTypeIndicator,
1325            String JavaDoc description)
1326        {
1327            this.userName = userName;
1328            this.userOrdinal = userOrdinal;
1329            this.description = description;
1330            this.dbTypeIndicator = dbTypeIndicator;
1331        }
1332
1333    }
1334
1335    static class Column {
1336
1337        /**
1338         * This is used as the true value for the restriction parameter.
1339         */

1340        static final boolean RESTRICTION = true;
1341        /**
1342         * This is used as the false value for the restriction parameter.
1343         */

1344        static final boolean NOT_RESTRICTION = false;
1345
1346        /**
1347         * This is used as the false value for the nullable parameter.
1348         */

1349        static final boolean REQUIRED = false;
1350        /**
1351         * This is used as the true value for the nullable parameter.
1352         */

1353        static final boolean OPTIONAL = true;
1354
1355        /**
1356         * This is used as the false value for the unbounded parameter.
1357         */

1358        static final boolean ONE_MAX = false;
1359        /**
1360         * This is used as the true value for the unbounded parameter.
1361         */

1362        static final boolean UNBOUNDED = true;
1363
1364        final String JavaDoc name;
1365        final Type type;
1366        final Enumeration enumeration;
1367        final String JavaDoc description;
1368        final boolean restriction;
1369        final boolean nullable;
1370        final boolean unbounded;
1371
1372        /**
1373         * Creates a column.
1374         *
1375         * @param name Name of column
1376         * @param type A {@link mondrian.xmla.RowsetDefinition.Type} value
1377         * @param enumeratedType Must be specified for enumeration or array
1378         * of enumerations
1379         * @param description Description of column
1380         * @param restriction Whether column can be used as a filter on its
1381         * rowset
1382         * @param nullable Whether column can contain null values
1383         * @pre type != null
1384         * @pre (type == Type.Enumeration || type == Type.EnumerationArray || type == Type.EnumString) == (enumeratedType != null)
1385         * @pre description == null || description.indexOf('\r') == -1
1386         */

1387        Column(
1388            String JavaDoc name,
1389            Type type,
1390            Enumeration enumeratedType,
1391            boolean restriction,
1392            boolean nullable,
1393            String JavaDoc description)
1394        {
1395            this(
1396                name, type, enumeratedType,
1397                restriction, nullable, ONE_MAX, description);
1398        }
1399
1400        Column(
1401            String JavaDoc name,
1402            Type type,
1403            Enumeration enumeratedType,
1404            boolean restriction,
1405            boolean nullable,
1406            boolean unbounded,
1407            String JavaDoc description)
1408        {
1409            assert type != null;
1410            assert (type == Type.Enumeration ||
1411                type == Type.EnumerationArray ||
1412                type == Type.EnumString) ==
1413                (enumeratedType != null);
1414            // Line endings must be UNIX style (LF) not Windows style (LF+CR).
1415
// Thus the client will receive the same XML, regardless
1416
// of the server O/S.
1417
assert description == null || description.indexOf('\r') == -1;
1418            this.name = name;
1419            this.type = type;
1420            this.enumeration = enumeratedType;
1421            this.description = description;
1422            this.restriction = restriction;
1423            this.nullable = nullable;
1424            this.unbounded = unbounded;
1425        }
1426
1427        /**
1428         * Retrieves a value of this column from a row. The base implementation
1429         * uses reflection to call an accessor method; a derived class may
1430         * provide a different implementation.
1431         */

1432        protected Object JavaDoc get(Object JavaDoc row) {
1433            return getFromAccessor(row);
1434        }
1435
1436        /**
1437         * Retrieves the value of this column "MyColumn" from a field called
1438         * "myColumn".
1439         *
1440         * @param row Current row
1441         * @return Value of given this property of the given row
1442         */

1443        protected final Object JavaDoc getFromField(Object JavaDoc row) {
1444            try {
1445                String JavaDoc javaFieldName = name.substring(0, 1).toLowerCase() +
1446                    name.substring(1);
1447                Field JavaDoc field = row.getClass().getField(javaFieldName);
1448                return field.get(row);
1449            } catch (NoSuchFieldException JavaDoc e) {
1450                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1451            } catch (SecurityException JavaDoc e) {
1452                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1453            } catch (IllegalAccessException JavaDoc e) {
1454                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1455            }
1456        }
1457
1458        /**
1459         * Retrieves the value of this column "MyColumn" by calling a method
1460         * called "getMyColumn()".
1461         *
1462         * @param row Current row
1463         * @return Value of given this property of the given row
1464         */

1465        protected final Object JavaDoc getFromAccessor(Object JavaDoc row) {
1466            try {
1467                String JavaDoc javaMethodName = "get" + name;
1468                Method JavaDoc method = row.getClass().getMethod(javaMethodName);
1469                return method.invoke(row);
1470            } catch (SecurityException JavaDoc e) {
1471                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1472            } catch (IllegalAccessException JavaDoc e) {
1473                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1474            } catch (NoSuchMethodException JavaDoc e) {
1475                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1476            } catch (InvocationTargetException JavaDoc e) {
1477                throw Util.newInternal(e, "Error while accessing rowset column " + name);
1478            }
1479        }
1480
1481        public String JavaDoc getColumnType() {
1482            if (type.isEnum()) {
1483                return enumeration.type.columnType;
1484            }
1485            return type.columnType;
1486        }
1487    }
1488
1489    // -------------------------------------------------------------------------
1490
// From this point on, just rowset classess.
1491

1492    static class DiscoverDatasourcesRowset extends Rowset {
1493        private static final Column DataSourceName =
1494            new Column(
1495                "DataSourceName",
1496                Type.String,
1497                null,
1498                Column.RESTRICTION,
1499                Column.REQUIRED,
1500                "The name of the data source, such as FoodMart 2000.");
1501        private static final Column DataSourceDescription =
1502            new Column(
1503                "DataSourceDescription",
1504                Type.String,
1505                null,
1506                Column.NOT_RESTRICTION,
1507                Column.OPTIONAL,
1508                "A description of the data source, as entered by the publisher.");
1509        private static final Column URL =
1510            new Column(
1511                "URL",
1512                Type.String,
1513                null,
1514                Column.RESTRICTION,
1515                Column.OPTIONAL,
1516                "The unique path that shows where to invoke the XML for Analysis methods for that data source.");
1517        private static final Column DataSourceInfo =
1518            new Column(
1519                "DataSourceInfo",
1520                Type.String,
1521                null,
1522                Column.NOT_RESTRICTION,
1523                Column.OPTIONAL,
1524                "A string containing any additional information required to connect to the data source. This can include the Initial Catalog property or other information for the provider.\n" +
1525                    "Example: \"Provider=MSOLAP;Data Source=Local;\"");
1526        private static final Column ProviderName =
1527            new Column(
1528                "ProviderName",
1529                Type.String,
1530                null,
1531                Column.RESTRICTION,
1532                Column.OPTIONAL,
1533                "The name of the provider behind the data source. \n" +
1534                    "Example: \"MSDASQL\"");
1535        private static final Column ProviderType =
1536            new Column(
1537                "ProviderType",
1538                Type.EnumerationArray,
1539                Enumeration.ProviderType.enumeration,
1540                Column.RESTRICTION,
1541                Column.REQUIRED,
1542                Column.UNBOUNDED,
1543                "The types of data supported by the provider. May include one or more of the following types. Example follows this table.\n" +
1544                    "TDP: tabular data provider.\n" +
1545                    "MDP: multidimensional data provider.\n" +
1546                    "DMP: data mining provider. A DMP provider implements the OLE DB for Data Mining specification.");
1547        private static final Column AuthenticationMode =
1548            new Column(
1549                "AuthenticationMode",
1550                Type.EnumString,
1551                Enumeration.AuthenticationMode.enumeration,
1552                Column.RESTRICTION,
1553                Column.REQUIRED,
1554                "Specification of what type of security mode the data source uses. Values can be one of the following:\n" +
1555                    "Unauthenticated: no user ID or password needs to be sent.\n" +
1556                    "Authenticated: User ID and Password must be included in the information required for the connection.\n" +
1557                    "Integrated: the data source uses the underlying security to determine authorization, such as Integrated Security provided by Microsoft Internet Information Services (IIS).");
1558
1559        public DiscoverDatasourcesRowset(XmlaRequest request, XmlaHandler handler) {
1560            super(DISCOVER_DATASOURCES, request, handler);
1561        }
1562
1563        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
1564            for (DataSourcesConfig.DataSource ds : handler
1565                .getDataSourceEntries().values()) {
1566                Row row = new Row();
1567                row.set(DataSourceName.name, ds.getDataSourceName());
1568                row.set(DataSourceDescription.name,
1569                    ds.getDataSourceDescription());
1570                row.set(URL.name, ds.getURL());
1571                row.set(DataSourceInfo.name, ds.getDataSourceName());
1572                row.set(ProviderName.name, ds.getProviderName());
1573                row.set(ProviderType.name, ds.getProviderType());
1574                row.set(AuthenticationMode.name, ds.getAuthenticationMode());
1575                addRow(row, rows);
1576            }
1577        }
1578        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
1579            switch (propertyDef) {
1580            case Content:
1581                break;
1582            default:
1583                super.setProperty(propertyDef, value);
1584            }
1585        }
1586    }
1587
1588    static class DiscoverSchemaRowsetsRowset extends Rowset {
1589        private static final Column SchemaName =
1590            new Column(
1591                "SchemaName",
1592                Type.StringArray,
1593                null,
1594                Column.RESTRICTION,
1595                Column.REQUIRED,
1596                "The name of the schema/request. This returns the values in the RequestTypes enumeration, plus any additional types supported by the provider. The provider defines rowset structures for the additional types");
1597        private static final Column SchemaGuid =
1598            new Column(
1599                "SchemaGuid",
1600                Type.UUID,
1601                null,
1602                Column.NOT_RESTRICTION,
1603                Column.OPTIONAL,
1604                "The GUID of the schema.");
1605        private static final Column Restrictions =
1606            new Column(
1607                "Restrictions",
1608                Type.Array,
1609                null,
1610                Column.NOT_RESTRICTION,
1611                Column.REQUIRED,
1612                "An array of the restrictions suppoted by provider. An example follows this table.");
1613        private static final Column Description =
1614            new Column(
1615                "Description",
1616                Type.String,
1617                null,
1618                Column.NOT_RESTRICTION,
1619                Column.REQUIRED,
1620                "A localizable description of the schema");
1621
1622        public DiscoverSchemaRowsetsRowset(XmlaRequest request, XmlaHandler handler) {
1623            super(DISCOVER_SCHEMA_ROWSETS, request, handler);
1624        }
1625
1626        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
1627            RowsetDefinition[] rowsetDefinitions =
1628                RowsetDefinition.class.getEnumConstants().clone();
1629            Arrays.sort(
1630                rowsetDefinitions,
1631                new Comparator<Enum JavaDoc>() {
1632                    public int compare(Enum JavaDoc o1, Enum JavaDoc o2) {
1633                        return o1.name().compareTo(o2.name());
1634                    }
1635                });
1636            for (RowsetDefinition rowsetDefinition : rowsetDefinitions) {
1637                Row row = new Row();
1638                row.set(SchemaName.name, rowsetDefinition.name());
1639
1640                // TODO: If we have a SchemaGuid output here
1641
//row.set(SchemaGuid.name, "");
1642

1643                row.set(Restrictions.name, getRestrictions(rowsetDefinition));
1644
1645                String JavaDoc desc = rowsetDefinition.getDescription();
1646                row.set(Description.name, (desc == null) ? "" : desc);
1647                addRow(row, rows);
1648            }
1649        }
1650
1651        private List<XmlElement> getRestrictions(RowsetDefinition rowsetDefinition) {
1652            List<XmlElement> restrictionList = new ArrayList<XmlElement>();
1653            final Column[] columns = rowsetDefinition.columnDefinitions;
1654            for (Column column : columns) {
1655                if (column.restriction) {
1656                    restrictionList.add(
1657                        new XmlElement(Restrictions.name,
1658                            null,
1659                            new XmlElement[]{
1660                                new XmlElement("Name", null, column.name),
1661                                new XmlElement("Type",
1662                                    null,
1663                                    column.getColumnType())
1664                            }));
1665                }
1666            }
1667            return restrictionList;
1668        }
1669
1670        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
1671            switch (propertyDef) {
1672            case Content:
1673                break;
1674            default:
1675                super.setProperty(propertyDef, value);
1676            }
1677        }
1678    }
1679
1680    public String JavaDoc getDescription() {
1681        return description;
1682    }
1683
1684    static class DiscoverPropertiesRowset extends Rowset {
1685        private final RestrictionTest propertyNameRT;
1686        DiscoverPropertiesRowset(XmlaRequest request, XmlaHandler handler) {
1687            super(DISCOVER_PROPERTIES, request, handler);
1688            propertyNameRT = getRestrictionTest(PropertyName);
1689        }
1690
1691        private static final Column PropertyName =
1692            new Column(
1693                "PropertyName",
1694                Type.StringSometimesArray,
1695                null,
1696                Column.RESTRICTION,
1697                Column.REQUIRED,
1698                "The name of the property.");
1699        private static final Column PropertyDescription =
1700            new Column(
1701                "PropertyDescription",
1702                Type.String,
1703                null,
1704                Column.NOT_RESTRICTION,
1705                Column.REQUIRED,
1706                "A localizable text description of the property.");
1707        private static final Column PropertyType =
1708            new Column(
1709                "PropertyType",
1710                Type.String,
1711                null,
1712                Column.NOT_RESTRICTION,
1713                Column.REQUIRED,
1714                "The XML data type of the property.");
1715        private static final Column PropertyAccessType =
1716            new Column(
1717                "PropertyAccessType",
1718                Type.EnumString,
1719                Enumeration.Access.enumeration,
1720                Column.NOT_RESTRICTION,
1721                Column.REQUIRED,
1722                "Access for the property. The value can be Read, Write, or ReadWrite.");
1723        private static final Column IsRequired =
1724            new Column(
1725                "IsRequired",
1726                Type.Boolean,
1727                null,
1728                Column.NOT_RESTRICTION,
1729                Column.REQUIRED,
1730                "True if a property is required, false if it is not required.");
1731        private static final Column Value =
1732            new Column(
1733                "Value",
1734                Type.String,
1735                null,
1736                Column.NOT_RESTRICTION,
1737                Column.REQUIRED,
1738                "The current value of the property.");
1739
1740        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
1741            for (PropertyDefinition propertyDefinition : PropertyDefinition.class
1742                .getEnumConstants()) {
1743                if (!propertyNameRT.passes(propertyDefinition.name())) {
1744                    continue;
1745                }
1746                Row row = new Row();
1747                row.set(PropertyName.name, propertyDefinition.name());
1748                row.set(PropertyDescription.name, propertyDefinition.description);
1749                row.set(PropertyType.name, propertyDefinition.type.getName());
1750                row.set(PropertyAccessType.name, propertyDefinition.access);
1751                row.set(IsRequired.name, false);
1752                row.set(Value.name, propertyDefinition.value);
1753                addRow(row, rows);
1754            }
1755        }
1756        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
1757            switch (propertyDef) {
1758            case Content:
1759                break;
1760            default:
1761                super.setProperty(propertyDef, value);
1762            }
1763        }
1764    }
1765
1766    static class DiscoverEnumeratorsRowset extends Rowset {
1767        DiscoverEnumeratorsRowset(XmlaRequest request, XmlaHandler handler) {
1768            super(DISCOVER_ENUMERATORS, request, handler);
1769        }
1770
1771        private static final Column EnumName =
1772            new Column(
1773                "EnumName",
1774                Type.StringArray,
1775                null,
1776                Column.RESTRICTION,
1777                Column.REQUIRED,
1778                "The name of the enumerator that contains a set of values.");
1779        private static final Column EnumDescription =
1780            new Column(
1781                "EnumDescription",
1782                Type.String,
1783                null,
1784                Column.NOT_RESTRICTION,
1785                Column.OPTIONAL,
1786                "A localizable description of the enumerator.");
1787        private static final Column EnumType =
1788            new Column(
1789                "EnumType",
1790                Type.String,
1791                null,
1792                Column.NOT_RESTRICTION,
1793                Column.REQUIRED,
1794                "The data type of the Enum values.");
1795        private static final Column ElementName =
1796            new Column(
1797                "ElementName",
1798                Type.String,
1799                null,
1800                Column.NOT_RESTRICTION,
1801                Column.REQUIRED,
1802                "The name of one of the value elements in the enumerator set.\n" + "Example: TDP");
1803        private static final Column ElementDescription =
1804            new Column(
1805                "ElementDescription",
1806                Type.String,
1807                null,
1808                Column.NOT_RESTRICTION,
1809                Column.OPTIONAL,
1810                "A localizable description of the element (optional).");
1811        private static final Column ElementValue =
1812            new Column(
1813                "ElementValue",
1814                Type.String,
1815                null,
1816                Column.NOT_RESTRICTION,
1817                Column.OPTIONAL,
1818                "The value of the element.\n" + "Example: 01");
1819
1820        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
1821            List<Enumeration> enumerators = getEnumerators();
1822            for (Enumeration enumerator : enumerators) {
1823                final String JavaDoc[] valueNames = enumerator.getNames();
1824                for (String JavaDoc valueName : valueNames) {
1825                    final Enum JavaDoc<?> value = enumerator.getValue(valueName, true);
1826                    Row row = new Row();
1827                    row.set(EnumName.name, enumerator.name);
1828                    row.set(EnumDescription.name, enumerator.description);
1829
1830                    // Note: SQL Server always has EnumType string
1831
// Need type of element of array, not the array
1832
// it self.
1833
row.set(EnumType.name, "string");
1834
1835                    String JavaDoc name =
1836                        value instanceof Enumeration.EnumWithName ?
1837                            ((Enumeration.EnumWithName) value).userName() :
1838                            value.name();
1839                    row.set(ElementName.name, name);
1840
1841                    if (value instanceof Enumeration.EnumWithDesc) {
1842                        String JavaDoc description =
1843                            ((Enumeration.EnumWithDesc) value).getDescription();
1844                        row.set(ElementDescription.name, description);
1845                    }
1846
1847                    switch (enumerator.type) {
1848                    case String:
1849                    case StringArray:
1850                        // these don't have ordinals
1851
break;
1852                    default:
1853                        int ordinal =
1854                            value instanceof Enumeration.EnumWithOrdinal ?
1855                                ((Enumeration.EnumWithOrdinal) value).userOrdinal() :
1856                                value.ordinal();
1857                        row.set(ElementValue.name, ordinal);
1858                        break;
1859                    }
1860                    addRow(row, rows);
1861                }
1862            }
1863        }
1864
1865        private static List<Enumeration> getEnumerators() {
1866            SortedSet<Enumeration> enumeratorSet = new TreeSet<Enumeration>(
1867                new Comparator<Enumeration>() {
1868                    public int compare(Enumeration o1, Enumeration o2) {
1869                        return o1.name.compareTo(o2.name);
1870                    }
1871                }
1872            );
1873            for (RowsetDefinition rowsetDefinition : RowsetDefinition.class.getEnumConstants()) {
1874                for (Column column : rowsetDefinition.columnDefinitions) {
1875                    if (column.enumeration != null) {
1876                        enumeratorSet.add(column.enumeration);
1877                    }
1878                }
1879            }
1880            return new ArrayList<Enumeration>(enumeratorSet);
1881        }
1882
1883        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
1884            switch (propertyDef) {
1885            case Content:
1886                break;
1887            default:
1888                super.setProperty(propertyDef, value);
1889            }
1890        }
1891    }
1892
1893    static class DiscoverKeywordsRowset extends Rowset {
1894        DiscoverKeywordsRowset(XmlaRequest request, XmlaHandler handler) {
1895            super(DISCOVER_KEYWORDS, request, handler);
1896        }
1897
1898        private static final Column Keyword =
1899            new Column(
1900                "Keyword",
1901                Type.StringSometimesArray,
1902                null,
1903                Column.RESTRICTION,
1904                Column.REQUIRED,
1905                "A list of all the keywords reserved by a provider.\n" +
1906                    "Example: AND");
1907
1908        private static final String JavaDoc[] keywords = new String JavaDoc[] {
1909            "$AdjustedProbability", "$Distance", "$Probability",
1910            "$ProbabilityStDev", "$ProbabilityStdDeV", "$ProbabilityVariance",
1911            "$StDev", "$StdDeV", "$Support", "$Variance",
1912            "AddCalculatedMembers", "Action", "After", "Aggregate", "All",
1913            "Alter", "Ancestor", "And", "Append", "As", "ASC", "Axis",
1914            "Automatic", "Back_Color", "BASC", "BDESC", "Before",
1915            "Before_And_After", "Before_And_Self", "Before_Self_After",
1916            "BottomCount", "BottomPercent", "BottomSum", "Break", "Boolean",
1917            "Cache", "Calculated", "Call", "Case", "Catalog_Name", "Cell",
1918            "Cell_Ordinal", "Cells", "Chapters", "Children",
1919            "Children_Cardinality", "ClosingPeriod", "Cluster",
1920            "ClusterDistance", "ClusterProbability", "Clusters",
1921            "CoalesceEmpty", "Column_Values", "Columns", "Content",
1922            "Contingent", "Continuous", "Correlation", "Cousin", "Covariance",
1923            "CovarianceN", "Create", "CreatePropertySet", "CrossJoin", "Cube",
1924            "Cube_Name", "CurrentMember", "CurrentCube", "Custom", "Cyclical",
1925            "DefaultMember", "Default_Member", "DESC", "Descendents",
1926            "Description", "Dimension", "Dimension_Unique_Name", "Dimensions",
1927            "Discrete", "Discretized", "DrillDownLevel",
1928            "DrillDownLevelBottom", "DrillDownLevelTop", "DrillDownMember",
1929            "DrillDownMemberBottom", "DrillDownMemberTop", "DrillTrough",
1930            "DrillUpLevel", "DrillUpMember", "Drop", "Else", "Empty", "End",
1931            "Equal_Areas", "Exclude_Null", "ExcludeEmpty", "Exclusive",
1932            "Expression", "Filter", "FirstChild", "FirstRowset",
1933            "FirstSibling", "Flattened", "Font_Flags", "Font_Name",
1934            "Font_size", "Fore_Color", "Format_String", "Formatted_Value",
1935            "Formula", "From", "Generate", "Global", "Head", "Hierarchize",
1936            "Hierarchy", "Hierary_Unique_name", "IIF", "IsEmpty",
1937            "Include_Null", "Include_Statistics", "Inclusive", "Input_Only",
1938            "IsDescendant", "Item", "Lag", "LastChild", "LastPeriods",
1939            "LastSibling", "Lead", "Level", "Level_Unique_Name", "Levels",
1940            "LinRegIntercept", "LinRegR2", "LinRegPoint", "LinRegSlope",
1941            "LinRegVariance", "Long", "MaxRows", "Median", "Member",
1942            "Member_Caption", "Member_Guid", "Member_Name", "Member_Ordinal",
1943            "Member_Type", "Member_Unique_Name", "Members",
1944            "Microsoft_Clustering", "Microsoft_Decision_Trees", "Mining",
1945            "Model", "Model_Existence_Only", "Models", "Move", "MTD", "Name",
1946            "Nest", "NextMember", "Non", "Normal", "Not", "Ntext", "Nvarchar",
1947            "OLAP", "On", "OpeningPeriod", "OpenQuery", "Or", "Ordered",
1948            "Ordinal", "Pages", "Pages", "ParallelPeriod", "Parent",
1949            "Parent_Level", "Parent_Unique_Name", "PeriodsToDate", "PMML",
1950            "Predict", "Predict_Only", "PredictAdjustedProbability",
1951            "PredictHistogram", "Prediction", "PredictionScore",
1952            "PredictProbability", "PredictProbabilityStDev",
1953            "PredictProbabilityVariance", "PredictStDev", "PredictSupport",
1954            "PredictVariance", "PrevMember", "Probability",
1955            "Probability_StDev", "Probability_StdDev", "Probability_Variance",
1956            "Properties", "Property", "QTD", "RangeMax", "RangeMid",
1957            "RangeMin", "Rank", "Recursive", "Refresh", "Related", "Rename",
1958            "Rollup", "Rows", "Schema_Name", "Sections", "Select", "Self",
1959            "Self_And_After", "Sequence_Time", "Server", "Session", "Set",
1960            "SetToArray", "SetToStr", "Shape", "Skip", "Solve_Order", "Sort",
1961            "StdDev", "Stdev", "StripCalculatedMembers", "StrToSet",
1962            "StrToTuple", "SubSet", "Support", "Tail", "Text", "Thresholds",
1963            "ToggleDrillState", "TopCount", "TopPercent", "TopSum",
1964            "TupleToStr", "Under", "Uniform", "UniqueName", "Use", "Value",
1965            "Value", "Var", "Variance", "VarP", "VarianceP", "VisualTotals",
1966            "When", "Where", "With", "WTD", "Xor",
1967        };
1968
1969        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
1970            for (String JavaDoc keyword : keywords) {
1971                Row row = new Row();
1972                row.set(Keyword.name, keyword);
1973                addRow(row, rows);
1974            }
1975        }
1976        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
1977            switch (propertyDef) {
1978            case Content:
1979                break;
1980            default:
1981                super.setProperty(propertyDef, value);
1982            }
1983        }
1984    }
1985
1986    static class DiscoverLiteralsRowset extends Rowset {
1987        DiscoverLiteralsRowset(XmlaRequest request, XmlaHandler handler) {
1988            super(DISCOVER_LITERALS, request, handler);
1989        }
1990
1991        private static final Column LiteralName = new Column(
1992            "LiteralName",
1993            Type.StringSometimesArray,
1994            null,
1995            Column.RESTRICTION,
1996            Column.REQUIRED,
1997            "The name of the literal described in the row.\n" + "Example: DBLITERAL_LIKE_PERCENT");
1998
1999        private static final Column LiteralValue = new Column(
2000            "LiteralValue",
2001            Type.String,
2002            null,
2003            Column.NOT_RESTRICTION,
2004            Column.REQUIRED,
2005            "Contains the actual literal value.\n" + "Example, if LiteralName is DBLITERAL_LIKE_PERCENT and the percent character (%) is used to match zero or more characters in a LIKE clause, this column's value would be \"%\".");
2006
2007        private static final Column LiteralInvalidChars = new Column(
2008            "LiteralInvalidChars",
2009            Type.String,
2010            null,
2011            Column.NOT_RESTRICTION,
2012            Column.REQUIRED,
2013            "The characters, in the literal, that are not valid.\n" + "For example, if table names can contain anything other than a numeric character, this string would be \"0123456789\".");
2014
2015        private static final Column LiteralInvalidStartingChars = new Column(
2016            "LiteralInvalidStartingChars",
2017            Type.String,
2018            null,
2019            Column.NOT_RESTRICTION,
2020            Column.REQUIRED,
2021            "The characters that are not valid as the first character of the literal. If the literal can start with any valid character, this is null.");
2022
2023        private static final Column LiteralMaxLength = new Column(
2024            "LiteralMaxLength",
2025            Type.Integer,
2026            null,
2027            Column.NOT_RESTRICTION,
2028            Column.REQUIRED,
2029            "The maximum number of characters in the literal. If there is no maximum or the maximum is unknown, the value is ?1.");
2030
2031        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
2032            emit(Enumeration.Literal.class, response);
2033        }
2034        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
2035            switch (propertyDef) {
2036            case Content:
2037                break;
2038            default:
2039                super.setProperty(propertyDef, value);
2040            }
2041        }
2042
2043    }
2044
2045    static class DbschemaCatalogsRowset extends Rowset {
2046        private final RestrictionTest catalogNameRT;
2047        DbschemaCatalogsRowset(XmlaRequest request, XmlaHandler handler) {
2048            super(DBSCHEMA_CATALOGS, request, handler);
2049            catalogNameRT = getRestrictionTest(CatalogName);
2050        }
2051
2052        private static final Column CatalogName =
2053            new Column(
2054                "CATALOG_NAME",
2055                Type.String,
2056                null,
2057                Column.RESTRICTION,
2058                Column.REQUIRED,
2059                "Catalog name. Cannot be NULL.");
2060        private static final Column Description =
2061            new Column(
2062                "DESCRIPTION",
2063                Type.String,
2064                null,
2065                Column.NOT_RESTRICTION,
2066                Column.REQUIRED,
2067                "Human-readable description of the catalog.");
2068        private static final Column Roles =
2069            new Column(
2070                "ROLES",
2071                Type.String,
2072                null,
2073                Column.NOT_RESTRICTION,
2074                Column.REQUIRED,
2075                "A comma delimited list of roles to which the current user belongs. An asterisk (*) is included as a role if the current user is a server or database administrator. Username is appended to ROLES if one of the roles uses dynamic security.");
2076        private static final Column DateModified =
2077            new Column(
2078                "DATE_MODIFIED",
2079                Type.DateTime,
2080                null,
2081                Column.NOT_RESTRICTION,
2082                Column.OPTIONAL,
2083                "The date that the catalog was last modified.");
2084
2085        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
2086            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
2087            DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs;
2088            String JavaDoc role = request.getRole();
2089            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
2090                if (dsCatalog == null || dsCatalog.definition == null) {
2091                    continue;
2092                }
2093                Connection connection = handler.getConnection(dsCatalog, role);
2094                if (connection == null) {
2095                    continue;
2096                }
2097                if (!catalogNameRT.passes(dsCatalog.name)) {
2098                    continue;
2099                }
2100                final RolapSchema schema = (RolapSchema) connection.getSchema();
2101
2102                Row row = new Row();
2103                row.set(CatalogName.name, dsCatalog.name);
2104
2105                // TODO: currently schema grammar does not support a description
2106
row.set(Description.name, "No description available");
2107
2108                // get Role names
2109
// TODO: this returns ALL roles, no the current user's roles
2110
StringBuilder JavaDoc buf = new StringBuilder JavaDoc(100);
2111                serialize(buf, schema.roleNames());
2112                row.set(Roles.name, buf.toString());
2113
2114                // TODO: currently schema grammar does not support modify date
2115
// so we return just some date for now.
2116
if (false) {
2117                    row.set(DateModified.name, dateModified);
2118                }
2119                addRow(row, rows);
2120            }
2121        }
2122
2123        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
2124            switch (propertyDef) {
2125            case Content:
2126                break;
2127            default:
2128                super.setProperty(propertyDef, value);
2129            }
2130        }
2131    }
2132
2133    static class DbschemaColumnsRowset extends Rowset {
2134        private final RestrictionTest tableCatalogRT;
2135        private final RestrictionTest tableNameRT;
2136        private final RestrictionTest columnNameRT;
2137        DbschemaColumnsRowset(XmlaRequest request, XmlaHandler handler) {
2138            super(DBSCHEMA_COLUMNS, request, handler);
2139            tableCatalogRT = getRestrictionTest(TableCatalog);
2140            tableNameRT = getRestrictionTest(TableName);
2141            columnNameRT = getRestrictionTest(ColumnName);
2142        }
2143
2144        private static final Column TableCatalog =
2145            new Column(
2146                "TABLE_CATALOG",
2147                Type.String,
2148                null,
2149                Column.RESTRICTION,
2150                Column.REQUIRED,
2151                "The name of the Database.");
2152        private static final Column TableSchema =
2153            new Column(
2154                "TABLE_SCHEMA",
2155                Type.String,
2156                null,
2157                Column.RESTRICTION,
2158                Column.OPTIONAL,
2159                null);
2160        private static final Column TableName =
2161            new Column(
2162                "TABLE_NAME",
2163                Type.String,
2164                null,
2165                Column.RESTRICTION,
2166                Column.REQUIRED,
2167                "The name of the cube.");
2168        private static final Column ColumnName =
2169            new Column(
2170                "COLUMN_NAME",
2171                Type.String,
2172                null,
2173                Column.RESTRICTION,
2174                Column.REQUIRED,
2175                "The name of the attribute hierarchy or measure.");
2176        private static final Column OrdinalPosition =
2177            new Column(
2178                "ORDINAL_POSITION",
2179                Type.UnsignedInteger,
2180                null,
2181                Column.NOT_RESTRICTION,
2182                Column.REQUIRED,
2183                "The position of the column, beginning with 1.");
2184        private static final Column ColumnHasDefault =
2185            new Column(
2186                "COLUMN_HAS_DEFAULT",
2187                Type.Boolean,
2188                null,
2189                Column.NOT_RESTRICTION,
2190                Column.OPTIONAL,
2191                "Not supported.");
2192        /*
2193         * A bitmask indicating the information stored in
2194         * DBCOLUMNFLAGS in OLE DB.
2195         * 1 = Bookmark
2196         * 2 = Fixed length
2197         * 4 = Nullable
2198         * 8 = Row versioning
2199         * 16 = Updateable column
2200         *
2201         * And, of course, MS SQL Server sometimes has the value of 80!!
2202        */

2203        private static final Column ColumnFlags =
2204            new Column(
2205                "COLUMN_FLAGS",
2206                Type.UnsignedInteger,
2207                null,
2208                Column.NOT_RESTRICTION,
2209                Column.REQUIRED,
2210                "A DBCOLUMNFLAGS bitmask indicating column properties.");
2211        private static final Column IsNullable =
2212            new Column(
2213                "IS_NULLABLE",
2214                Type.Boolean,
2215                null,
2216                Column.NOT_RESTRICTION,
2217                Column.REQUIRED,
2218                "Always returns false.");
2219        private static final Column DataType =
2220            new Column(
2221                "DATA_TYPE",
2222                Type.UnsignedShort,
2223                null,
2224                Column.NOT_RESTRICTION,
2225                Column.REQUIRED,
2226                "The data type of the column. Returns a string for dimension columns and a variant for measures.");
2227        private static final Column CharacterMaximumLength =
2228            new Column(
2229                "CHARACTER_MAXIMUM_LENGTH",
2230                Type.UnsignedInteger,
2231                null,
2232                Column.NOT_RESTRICTION,
2233                Column.OPTIONAL,
2234                "The maximum possible length of a value within the column.");
2235        private static final Column CharacterOctetLength =
2236            new Column(
2237                "CHARACTER_OCTET_LENGTH",
2238                Type.UnsignedInteger,
2239                null,
2240                Column.NOT_RESTRICTION,
2241                Column.OPTIONAL,
2242                "The maximum possible length of a value within the column, in bytes, for character or binary columns.");
2243        private static final Column NumericPrecision =
2244            new Column(
2245                "NUMERIC_PRECISION",
2246                Type.UnsignedShort,
2247                null,
2248                Column.NOT_RESTRICTION,
2249                Column.OPTIONAL,
2250                "The maximum precision of the column for numeric data types other than DBTYPE_VARNUMERIC.");
2251        private static final Column NumericScale =
2252            new Column(
2253                "NUMERIC_SCALE",
2254                Type.Short,
2255                null,
2256                Column.NOT_RESTRICTION,
2257                Column.OPTIONAL,
2258                "The number of digits to the right of the decimal point for DBTYPE_DECIMAL, DBTYPE_NUMERIC, DBTYPE_VARNUMERIC. Otherwise, this is NULL.");
2259
2260        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
2261            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
2262            DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs;
2263            String JavaDoc roleStr = request.getRole();
2264            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
2265                if (dsCatalog == null || dsCatalog.definition == null) {
2266                    continue;
2267                }
2268                Connection connection =
2269                    handler.getConnection(dsCatalog, roleStr);
2270                if (connection == null) {
2271                    continue;
2272                }
2273                Role role = connection.getSchema().lookupRole(roleStr);
2274                final RolapSchema schema = (RolapSchema) connection.getSchema();
2275                String JavaDoc catalogName = dsCatalog.name;
2276                if (!tableCatalogRT.passes(catalogName)) {
2277                    continue;
2278                }
2279                //final String schemaName = schema.getName();
2280

2281                int ordinalPosition = 1;
2282                Row row;
2283
2284                for (Cube cube1 : sortedCubes(schema)) {
2285                    RolapCube cube = (RolapCube) cube1;
2286                    SchemaReader schemaReader = cube.getSchemaReader(role);
2287                    String JavaDoc cubeName = cube.getName();
2288                    if (!tableNameRT.passes(cubeName)) {
2289                        continue;
2290                    }
2291                    for (Dimension dimension : cube.getDimensions()) {
2292                        Hierarchy[] hierarchies = dimension.getHierarchies();
2293                        for (Hierarchy hierarchy1 : hierarchies) {
2294                            HierarchyBase hierarchy =
2295                                (HierarchyBase) hierarchy1;
2296                            ordinalPosition = populateHierarchy(
2297                                schemaReader, cube, hierarchy,
2298                                ordinalPosition, rows);
2299                        }
2300                    }
2301
2302                    RolapMember[] rms = cube.getMeasuresMembers();
2303                    for (int k = 1; k < rms.length; k++) {
2304                        RolapMember member = rms[k];
2305
2306                        // null == true for regular cubes
2307
// virtual cubes do not set the visible property
2308
// on its measures so it might be null.
2309
Boolean JavaDoc isVisible = (Boolean JavaDoc)
2310                            member.getPropertyValue(Property.VISIBLE.name);
2311                        if (isVisible != null && !isVisible) {
2312                            continue;
2313                        }
2314
2315                        String JavaDoc memberName = member.getName();
2316                        if (!columnNameRT.passes("Measures:" + memberName)) {
2317                            continue;
2318                        }
2319
2320                        row = new Row();
2321                        row.set(TableCatalog.name, catalogName);
2322                        row.set(TableName.name, cubeName);
2323                        row.set(ColumnName.name, "Measures:" + memberName);
2324                        row.set(OrdinalPosition.name, ordinalPosition++);
2325                        row.set(ColumnHasDefault.name, false);
2326                        row.set(ColumnFlags.name, 0);
2327                        row.set(IsNullable.name, false);
2328                        // TODO: here is where one tries to determine the
2329
// type of the column - since these are all
2330
// Measures, aggregate Measures??, maybe they
2331
// are all numeric? (or currency)
2332
row.set(DataType.name, DBType.R8.userOrdinal);
2333                        // TODO: 16/255 seems to be what MS SQL Server
2334
// always returns.
2335
row.set(NumericPrecision.name, 16);
2336                        row.set(NumericScale.name, 255);
2337                        addRow(row, rows);
2338                    }
2339                }
2340            }
2341        }
2342
2343        private int populateHierarchy(
2344            SchemaReader schemaReader,
2345            RolapCube cube,
2346            HierarchyBase hierarchy,
2347            int ordinalPosition,
2348            List<Row> rows) {
2349
2350            // Access control
2351
if (!canAccess(schemaReader, hierarchy)) {
2352                return ordinalPosition;
2353            }
2354            String JavaDoc schemaName = cube.getSchema().getName();
2355            String JavaDoc cubeName = cube.getName();
2356            String JavaDoc hierarchyName = hierarchy.getName();
2357
2358            if (hierarchy.hasAll()) {
2359                Row row = new Row();
2360                row.set(TableCatalog.name, schemaName);
2361                row.set(TableName.name, cubeName);
2362                row.set(ColumnName.name, hierarchyName + ":(All)!NAME");
2363                row.set(OrdinalPosition.name, ordinalPosition++);
2364                row.set(ColumnHasDefault.name, false);
2365                row.set(ColumnFlags.name, 0);
2366                row.set(IsNullable.name, false);
2367                // names are always WSTR
2368
row.set(DataType.name, DBType.WSTR.userOrdinal);
2369                row.set(CharacterMaximumLength.name, 0);
2370                row.set(CharacterOctetLength.name, 0);
2371                addRow(row, rows);
2372
2373                row = new Row();
2374                row.set(TableCatalog.name, schemaName);
2375                row.set(TableName.name, cubeName);
2376                row.set(ColumnName.name, hierarchyName + ":(All)!UNIQUE_NAME");
2377                row.set(OrdinalPosition.name, ordinalPosition++);
2378                row.set(ColumnHasDefault.name, false);
2379                row.set(ColumnFlags.name, 0);
2380                row.set(IsNullable.name, false);
2381                // names are always WSTR
2382
row.set(DataType.name, DBType.WSTR.userOrdinal);
2383                row.set(CharacterMaximumLength.name, 0);
2384                row.set(CharacterOctetLength.name, 0);
2385                addRow(row, rows);
2386
2387                if (false) {
2388                    // TODO: SQLServer outputs this hasall KEY column name -
2389
// don't know what it's for
2390
row = new Row();
2391                    row.set(TableCatalog.name, schemaName);
2392                    row.set(TableName.name, cubeName);
2393                    row.set(ColumnName.name, hierarchyName + ":(All)!KEY");
2394                    row.set(OrdinalPosition.name, ordinalPosition++);
2395                    row.set(ColumnHasDefault.name, false);
2396                    row.set(ColumnFlags.name, 0);
2397                    row.set(IsNullable.name, false);
2398                    // names are always BOOL
2399
row.set(DataType.name, DBType.BOOL.userOrdinal);
2400                    row.set(NumericPrecision.name, 255);
2401                    row.set(NumericScale.name, 255);
2402                    addRow(row, rows);
2403                }
2404            }
2405
2406            Level[] levels = hierarchy.getLevels();
2407            for (Level level : levels) {
2408                ordinalPosition = populateLevel(
2409                    cube, hierarchy, level, ordinalPosition, rows);
2410            }
2411            return ordinalPosition;
2412        }
2413
2414        private int populateLevel(
2415            Cube cube,
2416            HierarchyBase hierarchy,
2417            Level level,
2418            int ordinalPosition, List<Row> rows) {
2419
2420            String JavaDoc schemaName = cube.getSchema().getName();
2421            String JavaDoc cubeName = cube.getName();
2422            String JavaDoc hierarchyName = hierarchy.getName();
2423            String JavaDoc levelName = level.getName();
2424
2425            Row row = new Row();
2426            row.set(TableCatalog.name, schemaName);
2427            row.set(TableName.name, cubeName);
2428            row.set(ColumnName.name,
2429                hierarchyName + ':' + levelName + "!NAME");
2430            row.set(OrdinalPosition.name, ordinalPosition++);
2431            row.set(ColumnHasDefault.name, false);
2432            row.set(ColumnFlags.name, 0);
2433            row.set(IsNullable.name, false);
2434            // names are always WSTR
2435
row.set(DataType.name, DBType.WSTR.userOrdinal);
2436            row.set(CharacterMaximumLength.name, 0);
2437            row.set(CharacterOctetLength.name, 0);
2438            addRow(row, rows);
2439
2440            row = new Row();
2441            row.set(TableCatalog.name, schemaName);
2442            row.set(TableName.name, cubeName);
2443            row.set(ColumnName.name,
2444                hierarchyName + ':' + levelName + "!UNIQUE_NAME");
2445            row.set(OrdinalPosition.name, ordinalPosition++);
2446            row.set(ColumnHasDefault.name, false);
2447            row.set(ColumnFlags.name, 0);
2448            row.set(IsNullable.name, false);
2449            // names are always WSTR
2450
row.set(DataType.name, DBType.WSTR.userOrdinal);
2451            row.set(CharacterMaximumLength.name, 0);
2452            row.set(CharacterOctetLength.name, 0);
2453            addRow(row, rows);
2454
2455/*
2456TODO: see above
2457            row = new Row();
2458            row.set(TableCatalog.name, schemaName);
2459            row.set(TableName.name, cubeName);
2460            row.set(ColumnName.name,
2461                hierarchyName + ":" + levelName + "!KEY");
2462            row.set(OrdinalPosition.name, ordinalPosition++);
2463            row.set(ColumnHasDefault.name, false);
2464            row.set(ColumnFlags.name, 0);
2465            row.set(IsNullable.name, false);
2466            // names are always BOOL
2467            row.set(DataType.name, DBType.BOOL.ordinal());
2468            row.set(NumericPrecision.name, 255);
2469            row.set(NumericScale.name, 255);
2470            addRow(row, rows);
2471*/

2472            Property[] props = level.getProperties();
2473            for (Property prop : props) {
2474                String JavaDoc propName = prop.getName();
2475
2476                row = new Row();
2477                row.set(TableCatalog.name, schemaName);
2478                row.set(TableName.name, cubeName);
2479                row.set(ColumnName.name,
2480                    hierarchyName + ':' + levelName + '!' + propName);
2481                row.set(OrdinalPosition.name, ordinalPosition++);
2482                row.set(ColumnHasDefault.name, false);
2483                row.set(ColumnFlags.name, 0);
2484                row.set(IsNullable.name, false);
2485
2486                DBType dbType = getDBTypeFromProperty(prop);
2487                row.set(DataType.name, dbType.userOrdinal);
2488
2489                switch (prop.getType()) {
2490                case TYPE_STRING:
2491                    row.set(CharacterMaximumLength.name, 0);
2492                    row.set(CharacterOctetLength.name, 0);
2493                    break;
2494                case TYPE_NUMERIC:
2495                    // TODO: 16/255 seems to be what MS SQL Server
2496
// always returns.
2497
row.set(NumericPrecision.name, 16);
2498                    row.set(NumericScale.name, 255);
2499                    break;
2500                case TYPE_BOOLEAN:
2501                    row.set(NumericPrecision.name, 255);
2502                    row.set(NumericScale.name, 255);
2503                    break;
2504                case TYPE_OTHER:
2505                    // TODO: what type is it really, its
2506
// not a string
2507
row.set(CharacterMaximumLength.name, 0);
2508                    row.set(CharacterOctetLength.name, 0);
2509                    break;
2510                }
2511                addRow(row, rows);
2512            }
2513            return ordinalPosition;
2514        }
2515        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
2516            switch (propertyDef) {
2517            case Content:
2518                break;
2519            default:
2520                super.setProperty(propertyDef, value);
2521            }
2522        }
2523    }
2524
2525    static class DbschemaProviderTypesRowset extends Rowset {
2526        private final RestrictionTest dataTypeRT;
2527        DbschemaProviderTypesRowset(XmlaRequest request, XmlaHandler handler) {
2528            super(DBSCHEMA_PROVIDER_TYPES, request, handler);
2529            dataTypeRT = getRestrictionTest(DataType);
2530        }
2531
2532        /*
2533        DATA_TYPE DBTYPE_UI2
2534        BEST_MATCH DBTYPE_BOOL
2535        Column(String name, Type type, Enumeration enumeratedType,
2536        boolean restriction, boolean nullable, String description)
2537        */

2538        /*
2539         * These are the columns returned by SQL Server.
2540         */

2541        private static final Column TypeName =
2542            new Column(
2543                "TYPE_NAME",
2544                Type.String,
2545                null,
2546                Column.NOT_RESTRICTION,
2547                Column.REQUIRED,
2548                "The provider-specific data type name.");
2549        private static final Column DataType =
2550            new Column(
2551                "DATA_TYPE",
2552                Type.UnsignedShort,
2553                null,
2554                Column.RESTRICTION,
2555                Column.REQUIRED,
2556                "The indicator of the data type.");
2557        private static final Column ColumnSize =
2558            new Column(
2559                "COLUMN_SIZE",
2560                Type.UnsignedInteger,
2561                null,
2562                Column.NOT_RESTRICTION,
2563                Column.REQUIRED,
2564                "The length of a non-numeric column. If the data type is numeric, this is the upper bound on the maximum precision of the data type.");
2565        private static final Column LiteralPrefix =
2566            new Column(
2567                "LITERAL_PREFIX",
2568                Type.String,
2569                null,
2570                Column.NOT_RESTRICTION,
2571                Column.OPTIONAL,
2572                "The character or characters used to prefix a literal of this type in a text command.");
2573        private static final Column LiteralSuffix =
2574            new Column(
2575                "LITERAL_SUFFIX",
2576                Type.String,
2577                null,
2578                Column.NOT_RESTRICTION,
2579                Column.OPTIONAL,
2580                "The character or characters used to suffix a literal of this type in a text command.");
2581        private static final Column IsNullable =
2582            new Column(
2583                "IS_NULLABLE",
2584                Type.Boolean,
2585                null,
2586                Column.NOT_RESTRICTION,
2587                Column.OPTIONAL,
2588                "A Boolean that indicates whether the data type is nullable. NULL-- indicates that it is not known whether the data type is nullable.");
2589        private static final Column CaseSensitive =
2590            new Column(
2591                "CASE_SENSITIVE",
2592                Type.Boolean,
2593                null,
2594                Column.NOT_RESTRICTION,
2595                Column.OPTIONAL,
2596                "A Boolean that indicates whether the data type is a characters type and case-sensitive.");
2597        private static final Column Searchable =
2598            new Column(
2599                "SEARCHABLE",
2600                Type.UnsignedInteger,
2601                null,
2602                Column.NOT_RESTRICTION,
2603                Column.OPTIONAL,
2604                "An integer indicating how the data type can be used in searches if the provider supports ICommandText; otherwise, NULL.");
2605        private static final Column UnsignedAttribute =
2606            new Column(
2607                "UNSIGNED_ATTRIBUTE",
2608                Type.Boolean,
2609                null,
2610                Column.NOT_RESTRICTION,
2611                Column.OPTIONAL,
2612                "A Boolean that indicates whether the data type is unsigned.");
2613        private static final Column FixedPrecScale =
2614            new Column(
2615                "FIXED_PREC_SCALE",
2616                Type.Boolean,
2617                null,
2618                Column.NOT_RESTRICTION,
2619                Column.OPTIONAL,
2620                "A Boolean that indicates whether the data type has a fixed precision and scale.");
2621        private static final Column AutoUniqueValue =
2622            new Column(
2623                "AUTO_UNIQUE_VALUE",
2624                Type.Boolean,
2625                null,
2626                Column.NOT_RESTRICTION,
2627                Column.OPTIONAL,
2628                "A Boolean that indicates whether the data type is autoincrementing.");
2629        private static final Column IsLong =
2630            new Column(
2631                "IS_LONG",
2632                Type.Boolean,
2633                null,
2634                Column.NOT_RESTRICTION,
2635                Column.OPTIONAL,
2636                "A Boolean that indicates whether the data type is a binary large object (BLOB) and has very long data.");
2637        private static final Column BestMatch =
2638            new Column(
2639                "BEST_MATCH",
2640                Type.Boolean,
2641                null,
2642                Column.RESTRICTION,
2643                Column.OPTIONAL,
2644                "A Boolean that indicates whether the data type is a best match.");
2645
2646        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
2647            // Identifies the (base) data types supported by the data provider.
2648
Row row;
2649
2650            // i4
2651
Integer JavaDoc dt = DBType.I4.userOrdinal;
2652            if (dataTypeRT.passes(dt)) {
2653                row = new Row();
2654                row.set(TypeName.name, DBType.I4.userName);
2655                row.set(DataType.name, dt);
2656                row.set(ColumnSize.name, 8);
2657                row.set(IsNullable.name, true);
2658                row.set(Searchable.name, null);
2659                row.set(UnsignedAttribute.name, false);
2660                row.set(FixedPrecScale.name, false);
2661                row.set(AutoUniqueValue.name, false);
2662                row.set(IsLong.name, false);
2663                row.set(BestMatch.name, true);
2664                addRow(row, rows);
2665            }
2666
2667            // R8
2668
dt = DBType.R8.userOrdinal;
2669            if (dataTypeRT.passes(dt)) {
2670                row = new Row();
2671                row.set(TypeName.name, DBType.R8.userName);
2672                row.set(DataType.name, dt);
2673                row.set(ColumnSize.name, 16);
2674                row.set(IsNullable.name, true);
2675                row.set(Searchable.name, null);
2676                row.set(UnsignedAttribute.name, false);
2677                row.set(FixedPrecScale.name, false);
2678                row.set(AutoUniqueValue.name, false);
2679                row.set(IsLong.name, false);
2680                row.set(BestMatch.name, true);
2681                addRow(row, rows);
2682            }
2683
2684            // CY
2685
dt = DBType.CY.userOrdinal;
2686            if (dataTypeRT.passes(dt)) {
2687                row = new Row();
2688                row.set(TypeName.name, DBType.CY.userName);
2689                row.set(DataType.name, dt);
2690                row.set(ColumnSize.name, 8);
2691                row.set(IsNullable.name, true);
2692                row.set(Searchable.name, null);
2693                row.set(UnsignedAttribute.name, false);
2694                row.set(FixedPrecScale.name, false);
2695                row.set(AutoUniqueValue.name, false);
2696                row.set(IsLong.name, false);
2697                row.set(BestMatch.name, true);
2698                addRow(row, rows);
2699            }
2700
2701            // BOOL
2702
dt = DBType.BOOL.userOrdinal;
2703            if (dataTypeRT.passes(dt)) {
2704                row = new Row();
2705                row.set(TypeName.name, DBType.BOOL.userName);
2706                row.set(DataType.name, dt);
2707                row.set(ColumnSize.name, 1);
2708                row.set(IsNullable.name, true);
2709                row.set(Searchable.name, null);
2710                row.set(UnsignedAttribute.name, false);
2711                row.set(FixedPrecScale.name, false);
2712                row.set(AutoUniqueValue.name, false);
2713                row.set(IsLong.name, false);
2714                row.set(BestMatch.name, true);
2715                addRow(row, rows);
2716            }
2717
2718            // I8
2719
dt = DBType.I8.userOrdinal;
2720            if (dataTypeRT.passes(dt)) {
2721                row = new Row();
2722                row.set(TypeName.name, DBType.I8.userName);
2723                row.set(DataType.name, dt);
2724                row.set(ColumnSize.name, 16);
2725                row.set(IsNullable.name, true);
2726                row.set(Searchable.name, null);
2727                row.set(UnsignedAttribute.name, false);
2728                row.set(FixedPrecScale.name, false);
2729                row.set(AutoUniqueValue.name, false);
2730                row.set(IsLong.name, false);
2731                row.set(BestMatch.name, true);
2732                addRow(row, rows);
2733            }
2734
2735            // WSTR
2736
dt = DBType.WSTR.userOrdinal;
2737            if (dataTypeRT.passes(dt)) {
2738                row = new Row();
2739                row.set(TypeName.name, DBType.WSTR.userName);
2740                row.set(DataType.name, dt);
2741                // how big are the string columns in the db
2742
row.set(ColumnSize.name, 255);
2743                row.set(LiteralPrefix.name, "\"");
2744                row.set(LiteralSuffix.name, "\"");
2745                row.set(IsNullable.name, true);
2746                row.set(CaseSensitive.name, false);
2747                row.set(Searchable.name, null);
2748                row.set(FixedPrecScale.name, false);
2749                row.set(AutoUniqueValue.name, false);
2750                row.set(IsLong.name, false);
2751                row.set(BestMatch.name, true);
2752                addRow(row, rows);
2753            }
2754        }
2755        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
2756            switch (propertyDef) {
2757            case Content:
2758                break;
2759            default:
2760                super.setProperty(propertyDef, value);
2761            }
2762        }
2763    }
2764
2765    static class DbschemaTablesRowset extends Rowset {
2766        private final RestrictionTest tableCatalogRT;
2767        private final RestrictionTest tableNameRT;
2768        private final RestrictionTest tableTypeRT;
2769        DbschemaTablesRowset(XmlaRequest request, XmlaHandler handler) {
2770            super(DBSCHEMA_TABLES, request, handler);
2771            tableCatalogRT = getRestrictionTest(TableCatalog);
2772            tableNameRT = getRestrictionTest(TableName);
2773            tableTypeRT = getRestrictionTest(TableType);
2774        }
2775
2776        private static final Column TableCatalog =
2777            new Column(
2778                "TABLE_CATALOG",
2779                Type.String,
2780                null,
2781                Column.RESTRICTION,
2782                Column.REQUIRED,
2783                "The name of the catalog to which this object belongs.");
2784        private static final Column TableSchema =
2785            new Column(
2786                "TABLE_SCHEMA",
2787                Type.String,
2788                null,
2789                Column.RESTRICTION,
2790                Column.OPTIONAL,
2791                "The name of the cube to which this object belongs.");
2792        private static final Column TableName =
2793            new Column(
2794                "TABLE_NAME",
2795                Type.String,
2796                null,
2797                Column.RESTRICTION,
2798                Column.REQUIRED,
2799                "The name of the object, if TABLE_TYPE is TABLE.");
2800        private static final Column TableType =
2801            new Column(
2802                "TABLE_TYPE",
2803                Type.String,
2804                null,
2805                Column.RESTRICTION,
2806                Column.REQUIRED,
2807                "The type of the table. TABLE indicates the object is a measure group. SYSTEM TABLE indicates the object is a dimension.");
2808
2809        private static final Column TableGuid =
2810            new Column(
2811                "TABLE_GUID",
2812                Type.UUID,
2813                null,
2814                Column.NOT_RESTRICTION,
2815                Column.OPTIONAL,
2816                "Not supported.");
2817        private static final Column Description =
2818            new Column(
2819                "DESCRIPTION",
2820                Type.String,
2821                null,
2822                Column.NOT_RESTRICTION,
2823                Column.OPTIONAL,
2824                "A human-readable description of the object.");
2825        private static final Column TablePropId =
2826            new Column(
2827                "TABLE_PROPID",
2828                Type.UnsignedInteger,
2829                null,
2830                Column.NOT_RESTRICTION,
2831                Column.OPTIONAL,
2832                "Not supported.");
2833        private static final Column DateCreated =
2834            new Column(
2835                "DATE_CREATED",
2836                Type.DateTime,
2837                null,
2838                Column.NOT_RESTRICTION,
2839                Column.OPTIONAL,
2840                "Not supported.");
2841        private static final Column DateModified =
2842            new Column(
2843                "DATE_MODIFIED",
2844                Type.DateTime,
2845                null,
2846                Column.NOT_RESTRICTION,
2847                Column.OPTIONAL,
2848                "The date the object was last modified.");
2849
2850        /*
2851        private static final Column TableOlapType =
2852            new Column(
2853                "TABLE_OLAP_TYPE",
2854                Type.String,
2855                null,
2856                Column.RESTRICTION,
2857                Column.OPTIONAL,
2858                "The OLAP type of the object. MEASURE_GROUP indicates the object is a measure group. CUBE_DIMENSION indicated the object is a dimension.");
2859        */

2860
2861        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
2862            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
2863            DataSourcesConfig.Catalog[] catalogs =
2864                handler.getCatalogs(request, ds);
2865            String JavaDoc roleStr = request.getRole();
2866
2867            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
2868                if (dsCatalog == null || dsCatalog.definition == null) {
2869                    continue;
2870                }
2871                Connection connection =
2872                    handler.getConnection(dsCatalog, roleStr);
2873                if (connection == null) {
2874                    continue;
2875                }
2876                Role role = connection.getSchema().lookupRole(roleStr);
2877                final RolapSchema schema = (RolapSchema) connection.getSchema();
2878                String JavaDoc catalogName = dsCatalog.name;
2879                if (!tableCatalogRT.passes(catalogName)) {
2880                    continue;
2881                }
2882
2883                //final String schemaName = schema.getName();
2884

2885                Row row;
2886                for (Cube cube1 : sortedCubes(schema)) {
2887                    RolapCube cube = (RolapCube) cube1;
2888                    String JavaDoc cubeName = cube.getName();
2889
2890                    String JavaDoc tableName = cubeName;
2891                    if (!tableNameRT.passes(tableName)) {
2892                        continue;
2893                    }
2894                    SchemaReader schemaReader = cube.getSchemaReader(role);
2895
2896                    String JavaDoc desc = cube.getDescription();
2897                    if (desc == null) {
2898                        //TODO: currently this is always null
2899
desc = catalogName + " - " + cubeName + " Cube";
2900                    }
2901
2902
2903                    if (tableTypeRT.passes("TABLE")) {
2904                        row = new Row();
2905                        row.set(TableCatalog.name, catalogName);
2906                        row.set(TableName.name, tableName);
2907                        row.set(TableType.name, "TABLE");
2908                        row.set(Description.name, desc);
2909                        if (false) {
2910                            row.set(DateModified.name, dateModified);
2911                        }
2912                        addRow(row, rows);
2913                    }
2914
2915
2916                    if (tableTypeRT.passes("SYSTEM TABLE")) {
2917                        for (Dimension dimension : cube.getDimensions()) {
2918                            if (dimension.isMeasures()) {
2919                                continue;
2920                            }
2921                            Hierarchy[] hierarchies =
2922                                dimension.getHierarchies();
2923                            for (Hierarchy hierarchy1 : hierarchies) {
2924                                HierarchyBase hierarchy =
2925                                    (HierarchyBase) hierarchy1;
2926                                populateHierarchy(schemaReader, cube,
2927                                    hierarchy, rows);
2928                            }
2929                        }
2930                    }
2931                }
2932            }
2933        }
2934
2935        private void populateHierarchy(
2936            SchemaReader schemaReader,
2937            RolapCube cube,
2938            HierarchyBase hierarchy,
2939            List<Row> rows) {
2940
2941            // Access control
2942
if (!canAccess(schemaReader, hierarchy)) {
2943                return;
2944            }
2945/*
2946            String schemaName = cube.getSchema().getName();
2947            String cubeName = cube.getName();
2948            String hierarchyName = hierarchy.getName();
2949
2950            String desc = hierarchy.getDescription();
2951            if (desc == null) {
2952                //TODO: currently this is always null
2953                desc = schemaName +
2954                    " - " +
2955                    cubeName +
2956                    " Cube - " +
2957                    hierarchyName +
2958                    " Hierarchy";
2959            }
2960
2961            if (hierarchy.hasAll()) {
2962                String tableName = cubeName +
2963                    ':' + hierarchyName + ':' + "(All)";
2964
2965                Row row = new Row();
2966                row.set(TableCatalog.name, schemaName);
2967                row.set(TableName.name, tableName);
2968                row.set(TableType.name, "SYSTEM TABLE");
2969                row.set(Description.name, desc);
2970                row.set(DateModified.name, dateModified);
2971                addRow(row, rows);
2972            }
2973*/

2974            Level[] levels = hierarchy.getLevels();
2975            for (Level level : levels) {
2976                populateLevel(cube, hierarchy, level, rows);
2977            }
2978        }
2979
2980        private void populateLevel(
2981            RolapCube cube,
2982            HierarchyBase hierarchy,
2983            Level level,
2984            List<Row> rows) {
2985
2986            String JavaDoc schemaName = cube.getSchema().getName();
2987            String JavaDoc cubeName = cube.getName();
2988            String JavaDoc hierarchyName = hierarchy.getName();
2989            String JavaDoc levelName = level.getName();
2990
2991            String JavaDoc tableName = cubeName +
2992                ':' + hierarchyName + ':' + levelName;
2993
2994            String JavaDoc desc = level.getDescription();
2995            if (desc == null) {
2996                //TODO: currently this is always null
2997
desc = schemaName +
2998                    " - " +
2999                    cubeName +
3000                    " Cube - " +
3001                    hierarchyName +
3002                    " Hierarchy - " +
3003                    levelName +
3004                    " Level";
3005            }
3006
3007            Row row = new Row();
3008            row.set(TableCatalog.name, schemaName);
3009            row.set(TableName.name, tableName);
3010            row.set(TableType.name, "SYSTEM TABLE");
3011            row.set(Description.name, desc);
3012            if (false) row.set(DateModified.name, dateModified);
3013            addRow(row, rows);
3014        }
3015
3016        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
3017            switch (propertyDef) {
3018            case Content:
3019                break;
3020            default:
3021                super.setProperty(propertyDef, value);
3022            }
3023        }
3024    }
3025
3026    // TODO: Is this needed????
3027
static class DbschemaTablesInfoRowset extends Rowset {
3028        DbschemaTablesInfoRowset(XmlaRequest request, XmlaHandler handler) {
3029            super(DBSCHEMA_TABLES_INFO, request, handler);
3030        }
3031
3032        private static final Column TableCatalog =
3033            new Column(
3034                "TABLE_CATALOG",
3035                Type.String,
3036                null,
3037                Column.RESTRICTION,
3038                Column.OPTIONAL,
3039                "Catalog name. NULL if the provider does not support catalogs.");
3040        private static final Column TableSchema =
3041            new Column(
3042                "TABLE_SCHEMA",
3043                Type.String,
3044                null,
3045                Column.RESTRICTION,
3046                Column.OPTIONAL,
3047                "Unqualified schema name. NULL if the provider does not support schemas.");
3048        private static final Column TableName =
3049            new Column(
3050                "TABLE_NAME",
3051                Type.String,
3052                null,
3053                Column.RESTRICTION,
3054                Column.REQUIRED,
3055                "Table name.");
3056        private static final Column TableType =
3057            new Column(
3058                "TABLE_TYPE",
3059                Type.String,
3060                null,
3061                Column.RESTRICTION,
3062                Column.REQUIRED,
3063                "Table type. One of the following or a provider-specific value: ALIAS, TABLE, SYNONYM, SYSTEM TABLE, VIEW, GLOBAL TEMPORARY, LOCAL TEMPORARY, EXTERNAL TABLE, SYSTEM VIEW");
3064        private static final Column TableGuid =
3065            new Column(
3066                "TABLE_GUID",
3067                Type.UUID,
3068                null,
3069                Column.NOT_RESTRICTION,
3070                Column.OPTIONAL,
3071                "GUID that uniquely identifies the table. Providers that do not use GUIDs to identify tables should return NULL in this column.");
3072
3073        private static final Column Bookmarks =
3074            new Column(
3075                "BOOKMARKS",
3076                Type.Boolean,
3077                null,
3078                Column.NOT_RESTRICTION,
3079                Column.REQUIRED,
3080                "Whether this table supports bookmarks. Allways is false.");
3081        private static final Column BookmarkType =
3082            new Column(
3083                "BOOKMARK_TYPE",
3084                Type.Integer,
3085                null,
3086                Column.NOT_RESTRICTION,
3087                Column.OPTIONAL,
3088                "Default bookmark type supported on this table.");
3089        private static final Column BookmarkDataType =
3090            new Column(
3091                "BOOKMARK_DATATYPE",
3092                Type.UnsignedShort,
3093                null,
3094                Column.NOT_RESTRICTION,
3095                Column.OPTIONAL,
3096                "The indicator of the bookmark's native data type.");
3097        private static final Column BookmarkMaximumLength =
3098            new Column(
3099                "BOOKMARK_MAXIMUM_LENGTH",
3100                Type.UnsignedInteger,
3101                null,
3102                Column.NOT_RESTRICTION,
3103                Column.OPTIONAL,
3104                "Maximum length of the bookmark in bytes.");
3105        private static final Column BookmarkInformation =
3106            new Column(
3107                "BOOKMARK_INFORMATION",
3108                Type.UnsignedInteger,
3109                null,
3110                Column.NOT_RESTRICTION,
3111                Column.OPTIONAL,
3112                "A bitmask specifying additional information about bookmarks over the rowset. ");
3113        private static final Column TableVersion =
3114            new Column(
3115                "TABLE_VERSION",
3116                Type.Long,
3117                null,
3118                Column.NOT_RESTRICTION,
3119                Column.OPTIONAL,
3120                "Version number for this table or NULL if the provider does not support returning table version information.");
3121        private static final Column Cardinality =
3122            new Column(
3123                "CARDINALITY",
3124                Type.UnsignedLong,
3125                null,
3126                Column.NOT_RESTRICTION,
3127                Column.REQUIRED,
3128                "Cardinality (number of rows) of the table.");
3129        private static final Column Description =
3130            new Column(
3131                "DESCRIPTION",
3132                Type.String,
3133                null,
3134                Column.NOT_RESTRICTION,
3135                Column.OPTIONAL,
3136                "Human-readable description of the table.");
3137        private static final Column TablePropId =
3138            new Column(
3139                "TABLE_PROPID",
3140                Type.UnsignedInteger,
3141                null,
3142                Column.NOT_RESTRICTION,
3143                Column.OPTIONAL,
3144                "Property ID of the table. Return null.");
3145
3146        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
3147            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
3148            DataSourcesConfig.Catalog[] catalogs =
3149                handler.getCatalogs(request, ds);
3150            String JavaDoc role = request.getRole();
3151
3152            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
3153                if (dsCatalog == null || dsCatalog.definition == null) {
3154                    continue;
3155                }
3156                Connection connection = handler.getConnection(dsCatalog, role);
3157                if (connection == null) {
3158                    continue;
3159                }
3160                final RolapSchema schema = (RolapSchema) connection.getSchema();
3161                String JavaDoc catalogName = dsCatalog.name;
3162                //final String catalogName = schema.getName();
3163

3164                //TODO: Is this cubes or tables? SQL Server returns what
3165
// in foodmart are cube names for TABLE_NAME
3166
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtables_info_rowset.asp
3167
for (Cube cube1 : sortedCubes(schema)) {
3168                    RolapCube cube = (RolapCube) cube1;
3169                    String JavaDoc cubeName = cube.getName();
3170                    String JavaDoc desc = cube.getDescription();
3171                    if (desc == null) {
3172                        //TODO: currently this is always null
3173
desc = catalogName + " - " + cubeName + " Cube";
3174                    }
3175                    //TODO: SQL Server returns 1000000 for all tables
3176
int cardinality = 1000000;
3177                    String JavaDoc version = "null";
3178
3179                    Row row = new Row();
3180                    row.set(TableCatalog.name, catalogName);
3181                    row.set(TableName.name, cubeName);
3182                    row.set(TableType.name, "TABLE");
3183                    row.set(Bookmarks.name, false);
3184                    row.set(TableVersion.name, version);
3185                    row.set(Cardinality.name, cardinality);
3186                    row.set(Description.name, desc);
3187                    addRow(row, rows);
3188                }
3189            }
3190        }
3191        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
3192            switch (propertyDef) {
3193            case Content:
3194                break;
3195            default:
3196                super.setProperty(propertyDef, value);
3197            }
3198        }
3199    }
3200
3201    static class MdschemaActionsRowset extends Rowset {
3202        MdschemaActionsRowset(XmlaRequest request, XmlaHandler handler) {
3203            super(MDSCHEMA_ACTIONS, request, handler);
3204        }
3205
3206        private static final Column CubeName =
3207            new Column(
3208                "CUBE_NAME",
3209                Type.String,
3210                null,
3211                Column.RESTRICTION,
3212                Column.REQUIRED,
3213                null);
3214        private static final Column Coordinate =
3215            new Column(
3216                "COORDINATE",
3217                Type.String,
3218                null,
3219                Column.RESTRICTION,
3220                Column.REQUIRED,
3221                null);
3222        private static final Column CoordinateType =
3223            new Column(
3224                "COORDINATE_TYPE",
3225                Type.Integer,
3226                null,
3227                Column.RESTRICTION,
3228                Column.REQUIRED,
3229                null);
3230        /*
3231            TODO: optional columns
3232        SCHEMA_NAME
3233        ACTION_NAME
3234        ACTION_TYPE
3235        INVOCATION
3236        CUBE_SOURCE
3237    */

3238
3239        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
3240            throw new XmlaException(
3241                CLIENT_FAULT_FC,
3242                HSB_UNSUPPORTED_OPERATION_CODE,
3243                HSB_UNSUPPORTED_OPERATION_FAULT_FS,
3244                new UnsupportedOperationException JavaDoc("MDSCHEMA_ACTIONS"));
3245        }
3246    }
3247
3248    // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapcubes_rowset.asp
3249
static class MdschemaCubesRowset extends Rowset {
3250        private final RestrictionTest catalogNameRT;
3251        private final RestrictionTest cubeNameRT;
3252        MdschemaCubesRowset(XmlaRequest request, XmlaHandler handler) {
3253            super(MDSCHEMA_CUBES, request, handler);
3254            catalogNameRT = getRestrictionTest(CatalogName);
3255            cubeNameRT = getRestrictionTest(CubeName);
3256        }
3257
3258        private static final String JavaDoc MD_CUBTYPE_CUBE = "CUBE";
3259        private static final String JavaDoc MD_CUBTYPE_VIRTUAL_CUBE = "VIRTUAL CUBE";
3260
3261        private static final Column CatalogName =
3262            new Column(
3263                "CATALOG_NAME",
3264                Type.String,
3265                null,
3266                Column.RESTRICTION,
3267                Column.OPTIONAL,
3268                "The name of the catalog to which this cube belongs.");
3269        private static final Column SchemaName =
3270            new Column(
3271                "SCHEMA_NAME",
3272                Type.String,
3273                null,
3274                Column.RESTRICTION,
3275                Column.OPTIONAL,
3276                "The name of the schema to which this cube belongs.");
3277        private static final Column CubeName =
3278            new Column(
3279                "CUBE_NAME",
3280                Type.String,
3281                null,
3282                Column.RESTRICTION,
3283                Column.REQUIRED,
3284                "Name of the cube.");
3285        private static final Column CubeType =
3286            new Column(
3287                "CUBE_TYPE",
3288                Type.String,
3289                null,
3290                Column.RESTRICTION,
3291                Column.REQUIRED,
3292                "Cube type.");
3293        private static final Column CubeGuid =
3294            new Column(
3295                "CUBE_GUID",
3296                Type.UUID,
3297                null,
3298                Column.NOT_RESTRICTION,
3299                Column.OPTIONAL,
3300                "Cube type.");
3301        private static final Column CreatedOn =
3302            new Column(
3303                "CREATED_ON",
3304                Type.DateTime,
3305                null,
3306                Column.NOT_RESTRICTION,
3307                Column.OPTIONAL,
3308                "Date and time of cube creation.");
3309        private static final Column LastSchemaUpdate =
3310            new Column(
3311                "LAST_SCHEMA_UPDATE",
3312                Type.DateTime,
3313                null,
3314                Column.NOT_RESTRICTION,
3315                Column.OPTIONAL,
3316                "Date and time of last schema update.");
3317        private static final Column SchemaUpdatedBy =
3318            new Column(
3319                "SCHEMA_UPDATED_BY",
3320                Type.String,
3321                null,
3322                Column.NOT_RESTRICTION,
3323                Column.OPTIONAL,
3324                "User ID of the person who last updated the schema.");
3325        private static final Column LastDataUpdate =
3326            new Column(
3327                "LAST_DATA_UPDATE",
3328                Type.DateTime,
3329                null,
3330                Column.NOT_RESTRICTION,
3331                Column.OPTIONAL,
3332                "Date and time of last data update.");
3333        private static final Column DataUpdatedBy =
3334            new Column(
3335                "DATA_UPDATED_BY",
3336                Type.String,
3337                null,
3338                Column.NOT_RESTRICTION,
3339                Column.OPTIONAL,
3340                "User ID of the person who last updated the data. ");
3341        private static final Column IsDrillthroughEnabled =
3342            new Column(
3343                "IS_DRILLTHROUGH_ENABLED",
3344                Type.Boolean,
3345                null,
3346                Column.NOT_RESTRICTION,
3347                Column.REQUIRED,
3348                "Describes whether DRILLTHROUGH can be performed on the members of a cube");
3349        private static final Column IsWriteEnabled =
3350            new Column(
3351                "IS_WRITE_ENABLED",
3352                Type.Boolean,
3353                null,
3354                Column.NOT_RESTRICTION,
3355                Column.REQUIRED,
3356                "Describes whether a cube is write-enabled");
3357        private static final Column IsLinkable =
3358            new Column(
3359                "IS_LINKABLE",
3360                Type.Boolean,
3361                null,
3362                Column.NOT_RESTRICTION,
3363                Column.REQUIRED,
3364                "Describes whether a cube can be used in a linked cube");
3365        private static final Column IsSqlEnabled =
3366            new Column(
3367                "IS_SQL_ENABLED",
3368                Type.Boolean,
3369                null,
3370                Column.NOT_RESTRICTION,
3371                Column.REQUIRED,
3372                "Describes whether or not SQL can be used on the cube");
3373        private static final Column Description =
3374            new Column(
3375                "DESCRIPTION",
3376                Type.String,
3377                null,
3378                Column.NOT_RESTRICTION,
3379                Column.OPTIONAL,
3380                "A user-friendly description of the dimension.");
3381
3382        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
3383            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
3384            DataSourcesConfig.Catalog[] catalogs =
3385                handler.getCatalogs(request, ds);
3386            String JavaDoc roleStr = request.getRole();
3387
3388            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
3389                if (dsCatalog == null || dsCatalog.definition == null) {
3390                    continue;
3391                }
3392                Connection connection =
3393                    handler.getConnection(dsCatalog, roleStr);
3394                if (connection == null) {
3395                    continue;
3396                }
3397                Role role = connection.getSchema().lookupRole(roleStr);
3398                String JavaDoc catalogName = dsCatalog.name;
3399                if (!catalogNameRT.passes(catalogName)) {
3400                    continue;
3401                }
3402
3403                final RolapSchema schema = (RolapSchema) connection.getSchema();
3404
3405                for (Cube cube : sortedCubes(schema)) {
3406                    SchemaReader schemaReader = cube.getSchemaReader(role);
3407                    // Access control
3408
if (!canAccess(schemaReader, cube)) {
3409                        continue;
3410                    }
3411                    if (!cubeNameRT.passes(cube.getName())) {
3412                        continue;
3413                    }
3414
3415                    String JavaDoc desc = cube.getDescription();
3416                    if (desc == null) {
3417                        desc = catalogName +
3418                            " Schema - " +
3419                            cube.getName() +
3420                            " Cube";
3421                    }
3422
3423                    Row row = new Row();
3424                    row.set(CatalogName.name, catalogName);
3425                    //row.set(SchemaName.name, catalogName);
3426
row.set(CubeName.name, cube.getName());
3427                    row.set(CubeType.name,
3428                        ((RolapCube) cube).isVirtual()
3429                            ? MD_CUBTYPE_VIRTUAL_CUBE : MD_CUBTYPE_CUBE);
3430                    //row.set(CubeGuid.name, "");
3431
//row.set(CreatedOn.name, "");
3432
//row.set(LastSchemaUpdate.name, "");
3433
//row.set(SchemaUpdatedBy.name, "");
3434
//row.set(LastDataUpdate.name, "");
3435
//row.set(DataUpdatedBy.name, "");
3436
row.set(IsDrillthroughEnabled.name, true);
3437                    row.set(IsWriteEnabled.name, false);
3438                    row.set(IsLinkable.name, false);
3439                    row.set(IsSqlEnabled.name, false);
3440                    row.set(Description.name, desc);
3441                    row.set(LastSchemaUpdate.name, lastUpdateDate(schema));
3442                    addRow(row, rows);
3443                }
3444            }
3445        }
3446
3447        private String JavaDoc lastUpdateDate(RolapSchema schema) {
3448            Format JavaDoc formatter = new SimpleDateFormat JavaDoc("yyyy-MM-dd'T'HH:mm:ss");
3449            return formatter.format(schema.getSchemaLoadDate());
3450        }
3451
3452        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
3453            switch (propertyDef) {
3454            case Content:
3455                break;
3456            default:
3457                super.setProperty(propertyDef, value);
3458            }
3459        }
3460    }
3461
3462    // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapdimensions_rowset.asp
3463
static class MdschemaDimensionsRowset extends Rowset {
3464        private final RestrictionTest schemaNameRT;
3465        private final RestrictionTest cubeNameRT;
3466        private final RestrictionTest dimensionUniqueNameRT;
3467        private final RestrictionTest dimensionNameRT;
3468        MdschemaDimensionsRowset(XmlaRequest request, XmlaHandler handler) {
3469            super(MDSCHEMA_DIMENSIONS, request, handler);
3470            schemaNameRT = getRestrictionTest(SchemaName);
3471            cubeNameRT = getRestrictionTest(CubeName);
3472            dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName);
3473            dimensionNameRT = getRestrictionTest(DimensionName);
3474        }
3475
3476        public static final int MD_DIMTYPE_OTHER = 3;
3477        public static final int MD_DIMTYPE_MEASURE = 2;
3478        public static final int MD_DIMTYPE_TIME = 1;
3479
3480        private static final Column CatalogName =
3481            new Column(
3482                "CATALOG_NAME",
3483                Type.String,
3484                null,
3485                Column.RESTRICTION,
3486                Column.OPTIONAL,
3487                "The name of the database.");
3488        private static final Column SchemaName =
3489            new Column(
3490                "SCHEMA_NAME",
3491                Type.String,
3492                null,
3493                Column.RESTRICTION,
3494                Column.OPTIONAL,
3495                "Not supported.");
3496        private static final Column CubeName =
3497            new Column(
3498                "CUBE_NAME",
3499                Type.String,
3500                null,
3501                Column.RESTRICTION,
3502                Column.REQUIRED,
3503                "The name of the cube.");
3504        private static final Column DimensionName =
3505            new Column(
3506                "DIMENSION_NAME",
3507                Type.String,
3508                null,
3509                Column.RESTRICTION,
3510                Column.REQUIRED,
3511                "The name of the dimension. ");
3512        private static final Column DimensionUniqueName =
3513            new Column(
3514                "DIMENSION_UNIQUE_NAME",
3515                Type.String,
3516                null,
3517                Column.RESTRICTION,
3518                Column.REQUIRED,
3519                "The unique name of the dimension.");
3520        private static final Column DimensionGuid =
3521            new Column(
3522                "DIMENSION_GUID",
3523                Type.UUID,
3524                null,
3525                Column.NOT_RESTRICTION,
3526                Column.OPTIONAL,
3527                "Not supported.");
3528        private static final Column DimensionCaption =
3529            new Column(
3530                "DIMENSION_CAPTION",
3531                Type.String,
3532                null,
3533                Column.NOT_RESTRICTION,
3534                Column.REQUIRED,
3535                "The caption of the dimension.");
3536        private static final Column DimensionOrdinal =
3537            new Column(
3538                "DIMENSION_ORDINAL",
3539                Type.UnsignedInteger,
3540                null,
3541                Column.NOT_RESTRICTION,
3542                Column.REQUIRED,
3543                "The position of the dimension within the cube.");
3544        /*
3545         * SQL Server returns values:
3546         * MD_DIMTYPE_TIME (1)
3547         * MD_DIMTYPE_MEASURE (2)
3548         * MD_DIMTYPE_OTHER (3)
3549         */

3550        private static final Column DimensionType =
3551            new Column(
3552                "DIMENSION_TYPE",
3553                Type.Short,
3554                null,
3555                Column.NOT_RESTRICTION,
3556                Column.REQUIRED,
3557                "The type of the dimension.");
3558        private static final Column DimensionCardinality =
3559            new Column(
3560                "DIMENSION_CARDINALITY",
3561                Type.UnsignedInteger,
3562                null,
3563                Column.NOT_RESTRICTION,
3564                Column.REQUIRED,
3565                "The number of members in the key attribute.");
3566        private static final Column DefaultHierarchy =
3567            new Column(
3568                "DEFAULT_HIERARCHY",
3569                Type.String,
3570                null,
3571                Column.NOT_RESTRICTION,
3572                Column.REQUIRED,
3573                "A hierarchy from the dimension. Preserved for backwards compatibility.");
3574        private static final Column Description =
3575            new Column(
3576                "DESCRIPTION",
3577                Type.String,
3578                null,
3579                Column.NOT_RESTRICTION,
3580                Column.OPTIONAL,
3581                "A user-friendly description of the dimension.");
3582        private static final Column IsVirtual =
3583            new Column(
3584                "IS_VIRTUAL",
3585                Type.Boolean,
3586                null,
3587                Column.NOT_RESTRICTION,
3588                Column.OPTIONAL,
3589                "Always FALSE.");
3590        private static final Column IsReadWrite =
3591            new Column("IS_READWRITE",
3592                Type.Boolean,
3593                null,
3594                Column.NOT_RESTRICTION,
3595                Column.OPTIONAL,
3596                "A Boolean that indicates whether the dimension is write-enabled.");
3597        /*
3598         * SQL Server returns values: 0 or 1
3599         */

3600        private static final Column DimensionUniqueSettings =
3601            new Column(
3602                "DIMENSION_UNIQUE_SETTINGS",
3603                Type.Integer,
3604                null,
3605                Column.NOT_RESTRICTION,
3606                Column.OPTIONAL,
3607                "A bitmap that specifies which columns contain unique values if the dimension contains only members with unique names.");
3608        private static final Column DimensionMasterUniqueName =
3609            new Column(
3610                "DIMENSION_MASTER_UNIQUE_NAME",
3611                Type.String,
3612                null,
3613                Column.NOT_RESTRICTION,
3614                Column.OPTIONAL,
3615                "Always NULL.");
3616        private static final Column DimensionIsVisible =
3617            new Column(
3618                "DIMENSION_IS_VISIBLE",
3619                Type.Boolean,
3620                null,
3621                Column.NOT_RESTRICTION,
3622                Column.OPTIONAL,
3623                "Always TRUE.");
3624
3625        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
3626            DataSourcesConfig.DataSource ds =
3627                handler.getDataSource(request);
3628            String JavaDoc roleStr = request.getRole();
3629            DataSourcesConfig.Catalog[] catalogs =
3630                handler.getCatalogs(request, ds);
3631
3632            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
3633                if (dsCatalog == null || dsCatalog.definition == null) {
3634                    continue;
3635                }
3636                String JavaDoc catalogName = dsCatalog.name;
3637                if (!schemaNameRT.passes(catalogName)) {
3638                    continue;
3639                }
3640
3641                Connection connection =
3642                    handler.getConnection(dsCatalog, roleStr);
3643                if (connection == null) {
3644                    continue;
3645                }
3646                Role role = connection.getSchema().lookupRole(roleStr);
3647                populateCatalog(connection, role, catalogName, rows);
3648            }
3649        }
3650        protected void populateCatalog(Connection connection,
3651            Role role,
3652            String JavaDoc catalogName,
3653            List<Row> rows)
3654            throws XmlaException {
3655
3656            for (Cube cube : sortedCubes(connection.getSchema())) {
3657                if (!cubeNameRT.passes(cube.getName())) {
3658                    continue;
3659                }
3660                SchemaReader schemaReader = cube.getSchemaReader(role);
3661                populateCube(schemaReader, catalogName, cube, rows);
3662            }
3663        }
3664        protected void populateCube(SchemaReader schemaReader,
3665            String JavaDoc catalogName,
3666            Cube cube,
3667            List<Row> rows)
3668            throws XmlaException {
3669
3670            for (Dimension dimension : cube.getDimensions()) {
3671                String JavaDoc name = dimension.getName();
3672                String JavaDoc unique = dimension.getUniqueName();
3673                if (dimensionNameRT.passes(name) &&
3674                    dimensionUniqueNameRT.passes(unique)) {
3675                    populateDimension(schemaReader, catalogName,
3676                        cube, dimension, rows);
3677                }
3678            }
3679        }
3680        protected void populateDimension(SchemaReader schemaReader,
3681            String JavaDoc catalogName,
3682            Cube cube,
3683            Dimension dimension,
3684            List<Row> rows)
3685            throws XmlaException {
3686
3687            // Access control
3688
if (!canAccess(schemaReader, dimension)) {
3689                return;
3690            }
3691            String JavaDoc desc = dimension.getDescription();
3692            if (desc == null) {
3693                desc = cube.getName() +
3694                    " Cube - " +
3695                    dimension.getName() +
3696                    " Dimension";
3697            }
3698
3699            Row row = new Row();
3700            row.set(CatalogName.name, catalogName);
3701            // NOTE: SQL Server does not return this
3702
//row.set(SchemaName.name, cube.getSchema().getName());
3703
row.set(CubeName.name, cube.getName());
3704            row.set(DimensionName.name, dimension.getName());
3705            row.set(DimensionUniqueName.name, dimension.getUniqueName());
3706            row.set(DimensionCaption.name, dimension.getCaption());
3707            row.set(DimensionOrdinal.name, dimension.getOrdinal(cube));
3708            row.set(DimensionType.name, getDimensionType(dimension));
3709
3710            //Is this the number of primaryKey members there are??
3711
// According to microsoft this is:
3712
// "The number of members in the key attribute."
3713
// There may be a better way of doing this but
3714
// this is what I came up with. Note that I need to
3715
// add '1' to the number inorder for it to match
3716
// match what microsoft SQL Server is producing.
3717
// The '1' might have to do with whether or not the
3718
// hierarchy has a 'all' member or not - don't know yet.
3719
// large data set total for Orders cube 0m42.923s
3720
Hierarchy firstHierarchy = dimension.getHierarchies()[0];
3721            Level[] levels = firstHierarchy.getLevels();
3722            Level lastLevel = levels[levels.length-1];
3723
3724
3725
3726            /*
3727            if override config setting is set
3728                if approxRowCount has a value
3729                    use it
3730            else
3731                                    do default
3732            */

3733
3734            // Added by TWI to returned cached row numbers
3735
int n=schemaReader.getLevelCardinality(lastLevel, true, true);
3736            row.set(DimensionCardinality.name, n+1);
3737
3738            // TODO: I think that this is just the dimension name
3739
row.set(DefaultHierarchy.name, dimension.getUniqueName());
3740            row.set(Description.name, desc);
3741            row.set(IsVirtual.name, false);
3742            // SQL Server always returns false
3743
row.set(IsReadWrite.name, false);
3744            // TODO: don't know what to do here
3745
// Are these the levels with uniqueMembers == true?
3746
// How are they mapped to specific column numbers?
3747
row.set(DimensionUniqueSettings.name, 0);
3748            row.set(DimensionIsVisible.name, true);
3749
3750            addRow(row, rows);
3751        }
3752
3753        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
3754            switch (propertyDef) {
3755            case Content:
3756                break;
3757            default:
3758                super.setProperty(propertyDef, value);
3759            }
3760        }
3761    }
3762
3763    static int getDimensionType(Dimension dim) {
3764        if (dim.isMeasures())
3765            return MdschemaDimensionsRowset.MD_DIMTYPE_MEASURE;
3766        else if (DimensionType.TimeDimension.equals(dim.getDimensionType())) {
3767            return MdschemaDimensionsRowset.MD_DIMTYPE_TIME;
3768        } else {
3769            return MdschemaDimensionsRowset.MD_DIMTYPE_OTHER;
3770        }
3771    }
3772
3773    static class MdschemaFunctionsRowset extends Rowset {
3774        /**
3775         * http://www.csidata.com/custserv/onlinehelp/VBSdocs/vbs57.htm
3776         */

3777        enum VarType {
3778            Empty("Uninitialized (default)"),
3779            Null("Contains no valid data"),
3780            Integer("Integer subtype"),
3781            Long("Long subtype"),
3782            Single("Single subtype"),
3783            Double("Double subtype"),
3784            Currency("Currency subtype"),
3785            Date("Date subtype"),
3786            String("String subtype"),
3787            Object("Object subtype"),
3788            Error("Error subtype"),
3789            Boolean("Boolean subtype"),
3790            Variant("Variant subtype"),
3791            DataObject("DataObject subtype"),
3792            Decimal("Decimal subtype"),
3793            Byte("Byte subtype"),
3794            Array("Array subtype");
3795
3796            static VarType forCategory(int category) {
3797                switch (category) {
3798                case Category.Unknown:
3799                    // expression == unknown ???
3800
// case Category.Expression:
3801
return Empty;
3802                case Category.Array:
3803                    return Array;
3804                case Category.Dimension:
3805                case Category.Hierarchy:
3806                case Category.Level:
3807                case Category.Member:
3808                case Category.Set:
3809                case Category.Tuple:
3810                case Category.Cube:
3811                case Category.Value:
3812                    return Variant;
3813                case Category.Logical:
3814                    return Boolean;
3815                case Category.Numeric:
3816                    return Double;
3817                case Category.String:
3818                case Category.Symbol:
3819                case Category.Constant:
3820                    return String;
3821                case Category.Integer:
3822                case Category.Mask:
3823                    return Integer;
3824                }
3825                // NOTE: this should never happen
3826
return Empty;
3827            }
3828
3829            VarType(String JavaDoc description) {
3830                Util.discard(description);
3831            }
3832        }
3833
3834        private final RestrictionTest functionNameRT;
3835        MdschemaFunctionsRowset(XmlaRequest request, XmlaHandler handler) {
3836            super(MDSCHEMA_FUNCTIONS, request, handler);
3837            functionNameRT = getRestrictionTest(FunctionName);
3838        }
3839
3840        private static final Column FunctionName =
3841            new Column(
3842                "FUNCTION_NAME",
3843                Type.String,
3844                null,
3845                Column.RESTRICTION,
3846                Column.REQUIRED,
3847                "The name of the function.");
3848        private static final Column Description =
3849            new Column(
3850                "DESCRIPTION",
3851                Type.String,
3852                null,
3853                Column.NOT_RESTRICTION,
3854                Column.OPTIONAL,
3855                "A description of the function.");
3856        private static final Column ParameterList =
3857            new Column(
3858                "PARAMETER_LIST",
3859                Type.String,
3860                null,
3861                Column.NOT_RESTRICTION,
3862                Column.OPTIONAL,
3863                "A comma delimited list of parameters.");
3864        private static final Column ReturnType =
3865            new Column(
3866                "RETURN_TYPE",
3867                Type.Integer,
3868                null,
3869                Column.NOT_RESTRICTION,
3870                Column.REQUIRED,
3871                "The VARTYPE of the return data type of the function.");
3872        private static final Column Origin =
3873            new Column(
3874                "ORIGIN",
3875                Type.Integer,
3876                null,
3877                Column.RESTRICTION,
3878                Column.REQUIRED,
3879                "The origin of the function: 1 for MDX functions. 2 for user-defined functions.");
3880        private static final Column InterfaceName =
3881            new Column(
3882                "INTERFACE_NAME",
3883                Type.String,
3884                null,
3885                Column.RESTRICTION,
3886                Column.REQUIRED,
3887                "The name of the interface for user-defined functions");
3888        private static final Column LibraryName =
3889            new Column(
3890                "LIBRARY_NAME",
3891                Type.String,
3892                null,
3893                Column.RESTRICTION,
3894                Column.OPTIONAL,
3895                "The name of the type library for user-defined functions. NULL for MDX functions.");
3896        private static final Column Caption =
3897            new Column(
3898                "CAPTION",
3899                Type.String,
3900                null,
3901                Column.NOT_RESTRICTION,
3902                Column.OPTIONAL,
3903                "The display caption for the function.");
3904
3905        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
3906            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
3907            DataSourcesConfig.Catalog[] catalogs =
3908                handler.getCatalogs(request, ds);
3909            String JavaDoc role = request.getRole();
3910
3911            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
3912                if (dsCatalog == null || dsCatalog.definition == null) {
3913                    continue;
3914                }
3915                Connection connection = handler.getConnection(dsCatalog, role);
3916                if (connection == null) {
3917                    continue;
3918                }
3919                final RolapSchema schema = (RolapSchema) connection.getSchema();
3920                FunTable funTable = schema.getFunTable();
3921
3922                StringBuilder JavaDoc buf = new StringBuilder JavaDoc(50);
3923                List<FunInfo> functions = funTable.getFunInfoList();
3924                for (FunInfo fi : functions) {
3925                    if (!functionNameRT.passes(fi.getName())) {
3926                        continue;
3927                    }
3928
3929                    int[][] paramCategories = fi.getParameterCategories();
3930                    int[] returnCategories = fi.getReturnCategories();
3931
3932                    // Convert Windows newlines in 'description' to UNIX format.
3933
String JavaDoc description = fi.getDescription();
3934                    if (description != null) {
3935                        description = Util.replace(fi.getDescription(),
3936                            "\r",
3937                            "");
3938                    }
3939                    if ((paramCategories == null) ||
3940                        (paramCategories.length == 0)) {
3941                        Row row = new Row();
3942                        row.set(FunctionName.name, fi.getName());
3943                        row.set(Description.name, description);
3944                        row.set(ParameterList.name, "(none)");
3945                        row.set(ReturnType.name, 1);
3946                        row.set(Origin.name, 1);
3947                        //row.set(LibraryName.name, "");
3948
// TODO WHAT VALUE should this have
3949
row.set(InterfaceName.name, "");
3950                        row.set(Caption.name, fi.getName());
3951                        addRow(row, rows);
3952
3953                    } else {
3954                        for (int i = 0; i < paramCategories.length; i++) {
3955                            int[] pc = paramCategories[i];
3956                            int returnCategory = returnCategories[i];
3957
3958                            Row row = new Row();
3959                            row.set(FunctionName.name, fi.getName());
3960                            row.set(Description.name, description);
3961
3962                            buf.setLength(0);
3963                            for (int j = 0; j < pc.length; j++) {
3964                                int v = pc[j];
3965                                if (j > 0) {
3966                                    buf.append(", ");
3967                                }
3968                                buf.append(Category.instance.getDescription(
3969                                    v & Category.Mask));
3970                            }
3971                            row.set(ParameterList.name, buf.toString());
3972
3973                            VarType varType = VarType.forCategory(returnCategory);
3974                            row.set(ReturnType.name, varType.ordinal());
3975
3976                            //TODO: currently FunInfo can not tell us which
3977
// functions are MDX and which are UDFs.
3978
row.set(Origin.name, 1);
3979
3980                            // TODO: Name of the type library for UDFs. NULL for MDX
3981
// functions.
3982
//row.set(LibraryName.name, "");
3983

3984                            // TODO: Name of the interface for UDF and Group name
3985
// for the MDX functions.
3986
// TODO WHAT VALUE should this have
3987
row.set(InterfaceName.name, "");
3988
3989                            row.set(Caption.name, fi.getName());
3990                            addRow(row, rows);
3991                        }
3992                    }
3993                }
3994            }
3995        }
3996        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
3997            switch (propertyDef) {
3998            case Content:
3999                break;
4000            default:
4001                super.setProperty(propertyDef, value);
4002            }
4003        }
4004    }
4005
4006
4007    static class MdschemaHierarchiesRowset extends Rowset {
4008        private final RestrictionTest schemaNameRT;
4009        private final RestrictionTest cubeNameRT;
4010        private final RestrictionTest dimensionUniqueNameRT;
4011        private final RestrictionTest hierarchyUniqueNameRT;
4012        private final RestrictionTest hierarchyNameRT;
4013        MdschemaHierarchiesRowset(XmlaRequest request, XmlaHandler handler) {
4014            super(MDSCHEMA_HIERARCHIES, request, handler);
4015            schemaNameRT = getRestrictionTest(SchemaName);
4016            cubeNameRT = getRestrictionTest(CubeName);
4017            dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName);
4018            hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName);
4019            hierarchyNameRT = getRestrictionTest(HierarchyName);
4020        }
4021
4022        private static final Column CatalogName =
4023            new Column(
4024                "CATALOG_NAME",
4025                Type.String,
4026                null,
4027                Column.RESTRICTION,
4028                Column.OPTIONAL,
4029                "The name of the catalog to which this hierarchy belongs.");
4030        private static final Column SchemaName =
4031            new Column(
4032                "SCHEMA_NAME",
4033                Type.String,
4034                null,
4035                Column.RESTRICTION,
4036                Column.OPTIONAL,
4037                "Not supported");
4038        private static final Column CubeName =
4039            new Column(
4040                "CUBE_NAME",
4041                Type.String,
4042                null,
4043                Column.RESTRICTION,
4044                Column.REQUIRED,
4045                "The name of the cube to which this hierarchy belongs.");
4046        private static final Column DimensionUniqueName =
4047            new Column(
4048                "DIMENSION_UNIQUE_NAME",
4049                Type.String,
4050                null,
4051                Column.RESTRICTION,
4052                Column.REQUIRED,
4053                "The unique name of the dimension to which this hierarchy belongs. ");
4054        private static final Column HierarchyName =
4055            new Column(
4056                "HIERARCHY_NAME",
4057                Type.String,
4058                null,
4059                Column.RESTRICTION,
4060                Column.REQUIRED,
4061                "The name of the hierarchy. Blank if there is only a single hierarchy in the dimension.");
4062        private static final Column HierarchyUniqueName =
4063            new Column(
4064                "HIERARCHY_UNIQUE_NAME",
4065                Type.String,
4066                null,
4067                Column.RESTRICTION,
4068                Column.REQUIRED,
4069                "The unique name of the hierarchy.");
4070
4071        private static final Column HierarchyGuid =
4072            new Column(
4073                "HIERARCHY_GUID",
4074                Type.UUID,
4075                null,
4076                Column.NOT_RESTRICTION,
4077                Column.OPTIONAL,
4078                "Hierarchy GUID.");
4079
4080        private static final Column HierarchyCaption =
4081            new Column(
4082                "HIERARCHY_CAPTION",
4083                Type.String,
4084                null,
4085                Column.NOT_RESTRICTION,
4086                Column.REQUIRED,
4087                "A label or a caption associated with the hierarchy.");
4088        private static final Column DimensionType =
4089            new Column(
4090                "DIMENSION_TYPE",
4091                Type.Short,
4092                null,
4093                Column.NOT_RESTRICTION,
4094                Column.REQUIRED,
4095                "The type of the dimension. ");
4096        private static final Column HierarchyCardinality =
4097            new Column(
4098                "HIERARCHY_CARDINALITY",
4099                Type.UnsignedInteger,
4100                null,
4101                Column.NOT_RESTRICTION,
4102                Column.REQUIRED,
4103                "The number of members in the hierarchy.");
4104        private static final Column DefaultMember =
4105            new Column(
4106                "DEFAULT_MEMBER",
4107                Type.String,
4108                null,
4109                Column.NOT_RESTRICTION,
4110                Column.OPTIONAL,
4111                "The default member for this hierarchy. ");
4112        private static final Column AllMember =
4113            new Column(
4114                "ALL_MEMBER",
4115                Type.String,
4116                null,
4117                Column.NOT_RESTRICTION,
4118                Column.OPTIONAL,
4119                "The member at the highest level of rollup in the hierarchy.");
4120        private static final Column Description =
4121            new Column(
4122                "DESCRIPTION",
4123                Type.String,
4124                null,
4125                Column.NOT_RESTRICTION,
4126                Column.OPTIONAL,
4127                "A human-readable description of the hierarchy. NULL if no description exists.");
4128        private static final Column Structure =
4129            new Column(
4130                "STRUCTURE",
4131                Type.Short,
4132                null,
4133                Column.NOT_RESTRICTION,
4134                Column.REQUIRED,
4135                "The structure of the hierarchy.");
4136        private static final Column IsVirtual =
4137            new Column(
4138                "IS_VIRTUAL",
4139                Type.Boolean,
4140                null,
4141                Column.NOT_RESTRICTION,
4142                Column.REQUIRED,
4143                "Always returns False.");
4144        private static final Column IsReadWrite =
4145            new Column(
4146                "IS_READWRITE",
4147                Type.Boolean,
4148                null,
4149                Column.NOT_RESTRICTION,
4150                Column.REQUIRED,
4151                "A Boolean that indicates whether the Write Back to dimension column is enabled.");
4152        private static final Column DimensionUniqueSettings =
4153            new Column(
4154                "DIMENSION_UNIQUE_SETTINGS",
4155                Type.Integer,
4156                null,
4157                Column.NOT_RESTRICTION,
4158                Column.REQUIRED,
4159                "Always returns MDDIMENSIONS_MEMBER_KEY_UNIQUE (1).");
4160        private static final Column DimensionIsVisible =
4161            new Column(
4162                "DIMENSION_IS_VISIBLE",
4163                Type.Boolean,
4164                null,
4165                Column.NOT_RESTRICTION,
4166                Column.REQUIRED,
4167                "Always returns true.");
4168        private static final Column HierarchyOrdinal =
4169            new Column(
4170                "HIERARCHY_ORDINAL",
4171                Type.UnsignedInteger,
4172                null,
4173                Column.NOT_RESTRICTION,
4174                Column.REQUIRED,
4175                "The ordinal number of the hierarchy across all hierarchies of the cube.");
4176        private static final Column DimensionIsShared =
4177            new Column(
4178                "DIMENSION_IS_SHARED",
4179                Type.Boolean,
4180                null,
4181                Column.NOT_RESTRICTION,
4182                Column.REQUIRED,
4183                "Always returns true.");
4184
4185
4186        /*
4187         * NOTE: This is non-standard, where did it come from?
4188         */

4189        private static final Column ParentChild =
4190            new Column(
4191                "PARENT_CHILD",
4192                Type.Boolean,
4193                null,
4194                Column.NOT_RESTRICTION,
4195                Column.OPTIONAL,
4196                "Is hierarchy a parent.");
4197
4198        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
4199            DataSourcesConfig.DataSource ds =
4200                handler.getDataSource(request);
4201            String JavaDoc roleStr = request.getRole();
4202            DataSourcesConfig.Catalog[] catalogs =
4203                handler.getCatalogs(request, ds);
4204
4205            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
4206                if (dsCatalog == null || dsCatalog.definition == null) {
4207                    continue;
4208                }
4209                String JavaDoc catalogName = dsCatalog.name;
4210                if (!schemaNameRT.passes(catalogName)) {
4211                    continue;
4212                }
4213
4214                Connection connection =
4215                    handler.getConnection(dsCatalog, roleStr);
4216                if (connection == null) {
4217                    continue;
4218                }
4219                Role role = connection.getSchema().lookupRole(roleStr);
4220                populateCatalog(connection, role, catalogName, rows);
4221            }
4222        }
4223        protected void populateCatalog(Connection connection,
4224            Role role,
4225            String JavaDoc catalogName,
4226            List<Row> rows)
4227            throws XmlaException {
4228            try {
4229                for (Cube cube : sortedCubes(connection.getSchema())) {
4230                    if (!cubeNameRT.passes(cube.getName())) {
4231                        continue;
4232                    }
4233                    SchemaReader schemaReader = cube.getSchemaReader(role);
4234                    populateCube(schemaReader, catalogName, cube, rows);
4235                }
4236            } finally {
4237            }
4238        }
4239        protected void populateCube(SchemaReader schemaReader,
4240            String JavaDoc catalogName,
4241            Cube cube,
4242            List<Row> rows)
4243            throws XmlaException {
4244            try {
4245                int ordinal = 0;
4246                for (Dimension dimension : cube.getDimensions()) {
4247                    String JavaDoc unique = dimension.getUniqueName();
4248                    // Must increment ordinal for all dimensions but
4249
// only output some of them.
4250
boolean genOutput = dimensionUniqueNameRT.passes(unique);
4251                    ordinal = populateDimension(
4252                        genOutput,
4253                        schemaReader, catalogName,
4254                        cube, dimension, ordinal, rows);
4255                }
4256            } finally {
4257            }
4258        }
4259        protected int populateDimension(
4260            boolean genOutput,
4261            SchemaReader schemaReader,
4262            String JavaDoc catalogName,
4263            Cube cube,
4264            Dimension dimension,
4265            int ordinal,
4266            List<Row> rows)
4267            throws XmlaException {
4268            try {
4269                Hierarchy[] hierarchies = dimension.getHierarchies();
4270                for (Hierarchy hierarchy : hierarchies) {
4271                    if (genOutput) {
4272                        String JavaDoc unique = hierarchy.getUniqueName();
4273                        if (hierarchyNameRT.passes(hierarchy.getName()) &&
4274                            hierarchyUniqueNameRT.passes(unique)) {
4275                            populateHierarchy(schemaReader, catalogName,
4276                                cube, dimension, (HierarchyBase) hierarchy,
4277                                ordinal++, rows);
4278                        } else {
4279                            ordinal++;
4280                        }
4281                    } else {
4282                        ordinal++;
4283                    }
4284                }
4285                return ordinal;
4286            } finally {
4287            }
4288        }
4289        protected void populateHierarchy(SchemaReader schemaReader,
4290            String JavaDoc catalogName,
4291            Cube cube,
4292            Dimension dimension,
4293            HierarchyBase hierarchy,
4294            int ordinal,
4295            List<Row> rows)
4296            throws XmlaException {
4297
4298            // Access control
4299
if (!canAccess(schemaReader, hierarchy)) {
4300                return;
4301            }
4302
4303            String JavaDoc desc = hierarchy.getDescription();
4304            if (desc == null) {
4305                desc = cube.getName() +
4306                    " Cube - " +
4307                    hierarchy.getName() +
4308                    " Hierarchy";
4309            }
4310
4311            Row row = new Row();
4312            row.set(CatalogName.name, catalogName);
4313
4314            // SQL Server does not return Schema name
4315
//row.set(SchemaName.name, cube.getSchema().getName());
4316

4317            row.set(CubeName.name, cube.getName());
4318            row.set(DimensionUniqueName.name, dimension.getUniqueName());
4319            row.set(HierarchyName.name, hierarchy.getName());
4320            row.set(HierarchyUniqueName.name, hierarchy.getUniqueName());
4321            //row.set(HierarchyGuid.name, "");
4322

4323            row.set(HierarchyCaption.name, hierarchy.getCaption());
4324            row.set(DimensionType.name, getDimensionType(dimension));
4325            // The number of members in the hierarchy. Because
4326
// of the presence of multiple hierarchies, this number
4327
// might not be the same as DIMENSION_CARDINALITY. This
4328
// value can be an approximation of the real
4329
// cardinality. Consumers should not assume that this
4330
// value is accurate.
4331
int cardinality =
4332                RolapMember.getHierarchyCardinality(schemaReader, hierarchy);
4333            row.set(HierarchyCardinality.name, cardinality);
4334
4335            row.set(DefaultMember.name, hierarchy.getDefaultMember());
4336            if (hierarchy.hasAll()) {
4337                row.set(AllMember.name,
4338                    Util.makeFqName(hierarchy, hierarchy.getAllMemberName()));
4339            }
4340            row.set(Description.name, desc);
4341
4342            //TODO: only support:
4343
// MD_STRUCTURE_FULLYBALANCED (0)
4344
// MD_STRUCTURE_RAGGEDBALANCED (1)
4345
row.set(Structure.name, hierarchy.isRagged() ? 1 : 0);
4346
4347            row.set(IsVirtual.name, false);
4348            row.set(IsReadWrite.name, false);
4349
4350            // NOTE that SQL Server returns '0' not '1'.
4351
row.set(DimensionUniqueSettings.name, 0);
4352
4353            // always true
4354
row.set(DimensionIsVisible.name, true);
4355
4356            row.set(HierarchyOrdinal.name, ordinal);
4357
4358            // always true
4359
row.set(DimensionIsShared.name, true);
4360
4361            RolapLevel nonAllFirstLevel =
4362                (RolapLevel) hierarchy.getLevels()[
4363                    (hierarchy.hasAll() ? 1 : 0)];
4364            row.set(ParentChild.name, nonAllFirstLevel.isParentChild());
4365            addRow(row, rows);
4366        }
4367
4368
4369
4370        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
4371            switch (propertyDef) {
4372            case Content:
4373                break;
4374            default:
4375                super.setProperty(propertyDef, value);
4376            }
4377        }
4378    }
4379
4380    static class MdschemaLevelsRowset extends Rowset {
4381        private final RestrictionTest schemaNameRT;
4382        private final RestrictionTest cubeNameRT;
4383        private final RestrictionTest dimensionUniqueNameRT;
4384        private final RestrictionTest hierarchyUniqueNameRT;
4385        private final RestrictionTest levelUniqueNameRT;
4386        private final RestrictionTest levelNameRT;
4387        MdschemaLevelsRowset(XmlaRequest request, XmlaHandler handler) {
4388            super(MDSCHEMA_LEVELS, request, handler);
4389            schemaNameRT = getRestrictionTest(SchemaName);
4390            cubeNameRT = getRestrictionTest(CubeName);
4391            dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName);
4392            hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName);
4393            levelUniqueNameRT = getRestrictionTest(LevelUniqueName);
4394            levelNameRT = getRestrictionTest(LevelName);
4395        }
4396
4397        public static final int MDLEVEL_TYPE_UNKNOWN = 0x0000;
4398        public static final int MDLEVEL_TYPE_REGULAR = 0x0000;
4399        public static final int MDLEVEL_TYPE_ALL = 0x0001;
4400        public static final int MDLEVEL_TYPE_CALCULATED = 0x0002;
4401        public static final int MDLEVEL_TYPE_TIME = 0x0004;
4402        public static final int MDLEVEL_TYPE_RESERVED1 = 0x0008;
4403        public static final int MDLEVEL_TYPE_TIME_YEARS = 0x0014;
4404        public static final int MDLEVEL_TYPE_TIME_HALF_YEAR = 0x0024;
4405        public static final int MDLEVEL_TYPE_TIME_QUARTERS = 0x0044;
4406        public static final int MDLEVEL_TYPE_TIME_MONTHS = 0x0084;
4407        public static final int MDLEVEL_TYPE_TIME_WEEKS = 0x0104;
4408        public static final int MDLEVEL_TYPE_TIME_DAYS = 0x0204;
4409        public static final int MDLEVEL_TYPE_TIME_HOURS = 0x0304;
4410        public static final int MDLEVEL_TYPE_TIME_MINUTES = 0x0404;
4411        public static final int MDLEVEL_TYPE_TIME_SECONDS = 0x0804;
4412        public static final int MDLEVEL_TYPE_TIME_UNDEFINED = 0x1004;
4413
4414        private static final Column CatalogName =
4415            new Column(
4416                "CATALOG_NAME",
4417                Type.String,
4418                null,
4419                Column.RESTRICTION,
4420                Column.OPTIONAL,
4421                "The name of the catalog to which this level belongs.");
4422        private static final Column SchemaName =
4423            new Column(
4424                "SCHEMA_NAME",
4425                Type.String,
4426                null,
4427                Column.RESTRICTION,
4428                Column.OPTIONAL,
4429                "The name of the schema to which this level belongs.");
4430        private static final Column CubeName =
4431            new Column(
4432                "CUBE_NAME",
4433                Type.String,
4434                null,
4435                Column.RESTRICTION,
4436                Column.REQUIRED,
4437                "The name of the cube to which this level belongs.");
4438        private static final Column DimensionUniqueName =
4439            new Column(
4440                "DIMENSION_UNIQUE_NAME",
4441                Type.String,
4442                null,
4443                Column.RESTRICTION,
4444                Column.REQUIRED,
4445                "The unique name of the dimension to which this level belongs.");
4446        private static final Column HierarchyUniqueName =
4447            new Column(
4448                "HIERARCHY_UNIQUE_NAME",
4449                Type.String,
4450                null,
4451                Column.RESTRICTION,
4452                Column.REQUIRED,
4453                "The unique name of the hierarchy.");
4454        private static final Column LevelName =
4455            new Column(
4456                "LEVEL_NAME",
4457                Type.String,
4458                null,
4459                Column.RESTRICTION,
4460                Column.REQUIRED,
4461                "The name of the level.");
4462        private static final Column LevelUniqueName =
4463            new Column(
4464                "LEVEL_UNIQUE_NAME",
4465                Type.String,
4466                null,
4467                Column.RESTRICTION,
4468                Column.REQUIRED,
4469                "The properly escaped unique name of the level.");
4470        private static final Column LevelGuid =
4471            new Column(
4472                "LEVEL_GUID",
4473                Type.UUID,
4474                null,
4475                Column.NOT_RESTRICTION,
4476                Column.OPTIONAL,
4477                "Level GUID.");
4478        private static final Column LevelCaption =
4479            new Column(
4480                "LEVEL_CAPTION",
4481                Type.String,
4482                null,
4483                Column.NOT_RESTRICTION,
4484                Column.REQUIRED,
4485                "A label or caption associated with the hierarchy.");
4486        private static final Column LevelNumber =
4487            new Column(
4488                "LEVEL_NUMBER",
4489                Type.UnsignedInteger,
4490                null,
4491                Column.NOT_RESTRICTION,
4492                Column.REQUIRED,
4493                "The distance of the level from the root of the hierarchy. Root level is zero (0).");
4494        private static final Column LevelCardinality =
4495            new Column(
4496                "LEVEL_CARDINALITY",
4497                Type.UnsignedInteger,
4498                null,
4499                Column.NOT_RESTRICTION,
4500                Column.REQUIRED,
4501                "The number of members in the level. This value can be an approximation of the real cardinality.");
4502        private static final Column LevelType =
4503            new Column(
4504                "LEVEL_TYPE",
4505                Type.Integer,
4506                null,
4507                Column.NOT_RESTRICTION,
4508                Column.REQUIRED,
4509                "Type of the level");
4510        private static final Column CustomRollupSettings =
4511            new Column(
4512                "CUSTOM_ROLLUP_SETTINGS",
4513                Type.Integer,
4514                null,
4515                Column.NOT_RESTRICTION,
4516                Column.REQUIRED,
4517                "A bitmap that specifies the custom rollup options.");
4518        private static final Column LevelUniqueSettings =
4519            new Column(
4520                "LEVEL_UNIQUE_SETTINGS",
4521                Type.Integer,
4522                null,
4523                Column.NOT_RESTRICTION,
4524                Column.REQUIRED,
4525                "A bitmap that specifies which columns contain unique values, if the level only has members with unique names or keys.");
4526        private static final Column LevelIsVisible =
4527            new Column(
4528                "LEVEL_IS_VISIBLE",
4529                Type.Boolean,
4530                null,
4531                Column.NOT_RESTRICTION,
4532                Column.REQUIRED,
4533                "A Boolean that indicates whether the level is visible.");
4534        private static final Column Description =
4535            new Column(
4536                "DESCRIPTION",
4537                Type.String,
4538                null,
4539                Column.NOT_RESTRICTION,
4540                Column.OPTIONAL,
4541                "A human-readable description of the level. NULL if no description exists.");
4542
4543        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
4544            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
4545            String JavaDoc roleStr = request.getRole();
4546            DataSourcesConfig.Catalog[] catalogs =
4547                handler.getCatalogs(request, ds);
4548
4549            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
4550                if (dsCatalog == null || dsCatalog.definition == null) {
4551                    continue;
4552                }
4553                String JavaDoc catalogName = dsCatalog.name;
4554                if (!schemaNameRT.passes(catalogName)) {
4555                    continue;
4556                }
4557
4558                Connection connection =
4559                    handler.getConnection(dsCatalog, roleStr);
4560                if (connection == null) {
4561                    continue;
4562                }
4563                Role role = connection.getSchema().lookupRole(roleStr);
4564                populateCatalog(connection, role, catalogName, rows);
4565            }
4566        }
4567        protected void populateCatalog(Connection connection,
4568            Role role,
4569            String JavaDoc catalogName,
4570            List<Row> rows)
4571            throws XmlaException {
4572
4573            for (Cube cube : sortedCubes(connection.getSchema())) {
4574                if (!cubeNameRT.passes(cube.getName())) {
4575                    continue;
4576                }
4577                SchemaReader schemaReader = cube.getSchemaReader(role);
4578                populateCube(schemaReader, catalogName, cube, rows);
4579            }
4580        }
4581
4582        protected void populateCube(SchemaReader schemaReader,
4583            String JavaDoc catalogName,
4584            Cube cube,
4585            List<Row> rows)
4586            throws XmlaException {
4587            try {
4588                for (Dimension dimension : cube.getDimensions()) {
4589                    String JavaDoc uniqueName = dimension.getUniqueName();
4590                    if (dimensionUniqueNameRT.passes(uniqueName)) {
4591                        populateDimension(schemaReader, catalogName,
4592                            cube, dimension, rows);
4593                    }
4594                }
4595            } finally {
4596            }
4597        }
4598        protected void populateDimension(SchemaReader schemaReader,
4599            String JavaDoc catalogName,
4600            Cube cube,
4601            Dimension dimension,
4602            List<Row> rows)
4603            throws XmlaException {
4604            try {
4605                Hierarchy[] hierarchies = dimension.getHierarchies();
4606                for (Hierarchy hierarchy : hierarchies) {
4607                    String JavaDoc uniqueName = hierarchy.getUniqueName();
4608                    if (hierarchyUniqueNameRT.passes(uniqueName)) {
4609                        populateHierarchy(schemaReader, catalogName,
4610                            cube, hierarchy, rows);
4611                    }
4612                }
4613            } finally {
4614            }
4615        }
4616        protected void populateHierarchy(SchemaReader schemaReader,
4617            String JavaDoc catalogName,
4618            Cube cube,
4619            Hierarchy hierarchy,
4620            List<Row> rows)
4621            throws XmlaException {
4622
4623            final Level[] levels = hierarchy.getLevels();
4624            for (Level level : levels) {
4625                String JavaDoc uniqueName = level.getUniqueName();
4626                String JavaDoc name = level.getName();
4627                if (levelUniqueNameRT.passes(uniqueName) &&
4628                    levelNameRT.passes(name)) {
4629                    outputLevel(schemaReader,
4630                        catalogName, cube, hierarchy, level, rows);
4631                }
4632            }
4633        }
4634        protected void outputLevel(SchemaReader schemaReader,
4635            String JavaDoc catalogName,
4636            Cube cube,
4637            Hierarchy hierarchy,
4638            Level level,
4639            List<Row> rows)
4640            throws XmlaException {
4641
4642            // Access control
4643
if (!canAccess(schemaReader, level)) {
4644                return;
4645            }
4646            String JavaDoc desc = level.getDescription();
4647            if (desc == null) {
4648                desc = cube.getName() +
4649                    " Cube - " +
4650                    hierarchy.getName() +
4651                    " Hierarchy" +
4652                    level.getName() +
4653                    " Level";
4654            }
4655
4656            Row row = new Row();
4657            row.set(CatalogName.name, catalogName);
4658            row.set(SchemaName.name, catalogName);
4659            row.set(CubeName.name, cube.getName());
4660            row.set(DimensionUniqueName.name,
4661                hierarchy.getDimension().getUniqueName());
4662            row.set(HierarchyUniqueName.name, hierarchy.getUniqueName());
4663            row.set(LevelName.name, level.getName());
4664            row.set(LevelUniqueName.name, level.getUniqueName());
4665            //row.set(LevelGuid.name, "");
4666
row.set(LevelCaption.name, level.getCaption());
4667            // see notes on this #getDepth()
4668
row.set(LevelNumber.name, level.getDepth());
4669
4670            // Get level cardinality
4671
// According to microsoft this is:
4672
// "The number of members in the level."
4673
int n = schemaReader.getLevelCardinality(level, true, true);
4674            row.set(LevelCardinality.name, n);
4675
4676            row.set(LevelType.name, getLevelType(level));
4677
4678            // TODO: most of the time this is correct
4679
row.set(CustomRollupSettings.name, 0);
4680
4681            if (level instanceof RolapLevel) {
4682                RolapLevel rl = (RolapLevel) level;
4683                row.set(LevelUniqueSettings.name,
4684                    (rl.isUnique() ? 1 : 0) +
4685                        (rl.isAll() ? 2 : 0)
4686                );
4687            } else {
4688                // can not access unique member attribute
4689
// this is the best we can do.
4690
row.set(LevelUniqueSettings.name,
4691                    (level.isAll() ? 2 : 0)
4692                );
4693            }
4694            row.set(LevelIsVisible.name, true);
4695            row.set(Description.name, desc);
4696            addRow(row, rows);
4697        }
4698
4699
4700        private int getLevelType(Level lev) {
4701            int ret = 0;
4702
4703            if (lev.isAll()) {
4704                ret |= MDLEVEL_TYPE_ALL;
4705            }
4706
4707            mondrian.olap.LevelType type = lev.getLevelType();
4708            switch (type) {
4709            case Regular:
4710                ret |= MDLEVEL_TYPE_REGULAR;
4711                break;
4712            case TimeDays:
4713                ret |= MDLEVEL_TYPE_TIME_DAYS;
4714                break;
4715            case TimeMonths:
4716                ret |= MDLEVEL_TYPE_TIME_MONTHS;
4717                break;
4718            case TimeQuarters:
4719                ret |= MDLEVEL_TYPE_TIME_QUARTERS;
4720                break;
4721            case TimeWeeks:
4722                ret |= MDLEVEL_TYPE_TIME_WEEKS;
4723                break;
4724            case TimeYears:
4725                ret |= MDLEVEL_TYPE_TIME_YEARS;
4726                break;
4727            default:
4728                ret |= MDLEVEL_TYPE_UNKNOWN;
4729            }
4730
4731            return ret;
4732        }
4733        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
4734            switch (propertyDef) {
4735            case Content:
4736                break;
4737            default:
4738                super.setProperty(propertyDef, value);
4739            }
4740        }
4741    }
4742
4743
4744    // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapmeasures_rowset.asp
4745
static class MdschemaMeasuresRowset extends Rowset {
4746        public static final int MDMEASURE_AGGR_UNKNOWN = 0;
4747        public static final int MDMEASURE_AGGR_SUM = 1;
4748        public static final int MDMEASURE_AGGR_COUNT = 2;
4749        public static final int MDMEASURE_AGGR_MIN = 3;
4750        public static final int MDMEASURE_AGGR_MAX = 4;
4751        public static final int MDMEASURE_AGGR_AVG = 5;
4752        public static final int MDMEASURE_AGGR_VAR = 6;
4753        public static final int MDMEASURE_AGGR_STD = 7;
4754        public static final int MDMEASURE_AGGR_CALCULATED = 127;
4755
4756        private final RestrictionTest schemaNameRT;
4757        private final RestrictionTest cubeNameRT;
4758        private final RestrictionTest measureUniqueNameRT;
4759        private final RestrictionTest measureNameRT;
4760        MdschemaMeasuresRowset(XmlaRequest request, XmlaHandler handler) {
4761            super(MDSCHEMA_MEASURES, request, handler);
4762            schemaNameRT = getRestrictionTest(SchemaName);
4763            cubeNameRT = getRestrictionTest(CubeName);
4764            measureNameRT = getRestrictionTest(MeasureName);
4765            measureUniqueNameRT = getRestrictionTest(MeasureUniqueName);
4766        }
4767
4768        private static final Column CatalogName =
4769            new Column(
4770                "CATALOG_NAME",
4771                Type.String,
4772                null,
4773                Column.RESTRICTION,
4774                Column.OPTIONAL,
4775                "The name of the catalog to which this measure belongs. ");
4776        private static final Column SchemaName =
4777            new Column(
4778                "SCHEMA_NAME",
4779                Type.String,
4780                null,
4781                Column.RESTRICTION,
4782                Column.OPTIONAL,
4783                "The name of the schema to which this measure belongs.");
4784        private static final Column CubeName =
4785            new Column(
4786                "CUBE_NAME",
4787                Type.String,
4788                null,
4789                Column.RESTRICTION,
4790                Column.REQUIRED,
4791                "The name of the cube to which this measure belongs.");
4792        private static final Column MeasureName =
4793            new Column(
4794                "MEASURE_NAME",
4795                Type.String,
4796                null,
4797                Column.RESTRICTION,
4798                Column.REQUIRED,
4799                "The name of the measure.");
4800        private static final Column MeasureUniqueName =
4801            new Column(
4802                "MEASURE_UNIQUE_NAME",
4803                Type.String,
4804                null,
4805                Column.RESTRICTION,
4806                Column.REQUIRED,
4807                "The Unique name of the measure.");
4808        private static final Column MeasureCaption =
4809            new Column(
4810                "MEASURE_CAPTION",
4811                Type.String,
4812                null,
4813                Column.NOT_RESTRICTION,
4814                Column.REQUIRED,
4815                "A label or caption associated with the measure. ");
4816        private static final Column MeasureGuid =
4817            new Column(
4818                "MEASURE_GUID",
4819                Type.UUID,
4820                null,
4821                Column.NOT_RESTRICTION,
4822                Column.OPTIONAL,
4823                "Measure GUID.");
4824        private static final Column MeasureAggregator =
4825            new Column(
4826                "MEASURE_AGGREGATOR",
4827                Type.Integer,
4828                null,
4829                Column.NOT_RESTRICTION,
4830                Column.REQUIRED,
4831                "How a measure was derived. ");
4832        private static final Column DataType =
4833            new Column(
4834                "DATA_TYPE",
4835                Type.UnsignedShort,
4836                null,
4837                Column.NOT_RESTRICTION,
4838                Column.REQUIRED,
4839                "Data type of the measure.");
4840        private static final Column MeasureIsVisible =
4841            new Column(
4842                "MEASURE_IS_VISIBLE",
4843                Type.Boolean,
4844                null,
4845                Column.NOT_RESTRICTION,
4846                Column.REQUIRED,
4847                "A Boolean that always returns True. If the measure is not visible, it will not be included in the schema rowset.");
4848        private static final Column LevelsList =
4849            new Column(
4850                "LEVELS_LIST",
4851                Type.String,
4852                null,
4853                Column.NOT_RESTRICTION,
4854                Column.OPTIONAL,
4855                "A string that always returns NULL. EXCEPT that SQL Server returns non-null values!!!");
4856        private static final Column Description =
4857            new Column(
4858                "DESCRIPTION",
4859                Type.String,
4860                null,
4861                Column.NOT_RESTRICTION,
4862                Column.OPTIONAL,
4863                "A human-readable description of the measure. ");
4864
4865        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
4866            DataSourcesConfig.DataSource ds = handler.getDataSource(request);
4867            String JavaDoc roleStr = request.getRole();
4868            DataSourcesConfig.Catalog[] catalogs =
4869                handler.getCatalogs(request, ds);
4870
4871            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
4872                if (dsCatalog == null || dsCatalog.definition == null) {
4873                    continue;
4874                }
4875                Connection connection =
4876                    handler.getConnection(dsCatalog, roleStr);
4877                if (connection == null) {
4878                    continue;
4879                }
4880
4881                String JavaDoc catalogName = dsCatalog.name;
4882                if (schemaNameRT.passes(catalogName)) {
4883                    Role role = connection.getSchema().lookupRole(roleStr);
4884                    populateCatalog(connection, role, catalogName, rows);
4885                }
4886            }
4887        }
4888        protected void populateCatalog(
4889            Connection connection,
4890            Role role,
4891            String JavaDoc catalogName,
4892            List<Row> rows)
4893            throws XmlaException {
4894
4895            // SQL Server actually includes the LEVELS_LIST row
4896
StringBuilder JavaDoc buf = new StringBuilder JavaDoc(100);
4897
4898            for (Cube cube : sortedCubes(connection.getSchema())) {
4899                if (cubeNameRT.passes(cube.getName())) {
4900                    SchemaReader schemaReader = cube.getSchemaReader(role);
4901                    Dimension measuresDimension = cube.getDimensions()[0];
4902                    Hierarchy measuresHierarchy =
4903                        measuresDimension.getHierarchies()[0];
4904                    Level measuresLevel =
4905                        measuresHierarchy.getLevels()[0];
4906
4907                    buf.setLength(0);
4908
4909                    int j = 0;
4910                    for (Dimension dimension : cube.getDimensions()) {
4911                        if (dimension.isMeasures()) {
4912                            continue;
4913                        }
4914                        for (Hierarchy hierarchy : dimension.getHierarchies()) {
4915                            Level[] levels = hierarchy.getLevels();
4916                            Level lastLevel = levels[levels.length - 1];
4917                            if (j++ > 0) {
4918                                buf.append(',');
4919                            }
4920                            buf.append(lastLevel.getUniqueName());
4921                        }
4922                    }
4923                    String JavaDoc levelListStr = buf.toString();
4924
4925                    Member[] storedMembers =
4926                        schemaReader.getLevelMembers(measuresLevel, false);
4927                    for (Member member : storedMembers) {
4928                        String JavaDoc name = member.getName();
4929                        String JavaDoc unique = member.getUniqueName();
4930                        if (measureNameRT.passes(name) &&
4931                            measureUniqueNameRT.passes(unique)) {
4932                            populateMember(schemaReader, catalogName,
4933                                member, cube, levelListStr, rows);
4934                        }
4935                    }
4936
4937                    for (Member member :
4938                        schemaReader.getCalculatedMembers(measuresHierarchy)) {
4939                        String JavaDoc name = member.getName();
4940                        String JavaDoc unique = member.getUniqueName();
4941                        if (measureNameRT.passes(name) &&
4942                            measureUniqueNameRT.passes(unique)) {
4943                            populateMember(schemaReader, catalogName,
4944                                member, cube, null, rows);
4945                        }
4946                    }
4947                }
4948            }
4949        }
4950
4951        private void populateMember(
4952            SchemaReader schemaReader,
4953            String JavaDoc catalogName,
4954            Member member,
4955            Cube cube,
4956            String JavaDoc levelListStr,
4957            List<Row> rows) {
4958
4959            // Access control
4960
if (!canAccess(schemaReader, member)) {
4961                return;
4962            }
4963
4964            if (member instanceof MemberBase) {
4965                MemberBase mb = (MemberBase) member;
4966                Boolean JavaDoc isVisible = (Boolean JavaDoc)
4967                    mb.getPropertyValue(Property.VISIBLE.name);
4968                if (isVisible != null && !isVisible) {
4969                    return;
4970                }
4971            }
4972
4973            //TODO: currently this is always null
4974
String JavaDoc desc = member.getDescription();
4975            if (desc == null) {
4976                desc = cube.getName() +
4977                    " Cube - " +
4978                    member.getName() +
4979                    " Member";
4980            }
4981
4982            Row row = new Row();
4983            row.set(CatalogName.name, catalogName);
4984
4985            // SQL Server does not return this
4986
//row.set(SchemaName.name, cube.getSchema().getName());
4987

4988            row.set(CubeName.name, cube.getName());
4989            row.set(MeasureName.name, member.getName());
4990            row.set(MeasureUniqueName.name, member.getUniqueName());
4991            row.set(MeasureCaption.name, member.getCaption());
4992            //row.set(MeasureGuid.name, "");
4993

4994            Object JavaDoc aggProp =
4995                member.getPropertyValue(Property.AGGREGATION_TYPE.getName());
4996            int aggNumber = MDMEASURE_AGGR_UNKNOWN;
4997            if (aggProp != null) {
4998                RolapAggregator agg = (RolapAggregator) aggProp;
4999                if (agg == RolapAggregator.Sum) {
5000                    aggNumber = MDMEASURE_AGGR_SUM;
5001                } else if (agg == RolapAggregator.Count) {
5002                    aggNumber = MDMEASURE_AGGR_COUNT;
5003                } else if (agg == RolapAggregator.Min) {
5004                    aggNumber = MDMEASURE_AGGR_MIN;
5005                } else if (agg == RolapAggregator.Max) {
5006                    aggNumber = MDMEASURE_AGGR_MAX;
5007                } else if (agg == RolapAggregator.Avg) {
5008                    aggNumber = MDMEASURE_AGGR_AVG;
5009                }
5010                //TODO: what are VAR and STD
5011
} else {
5012                aggNumber = MDMEASURE_AGGR_CALCULATED;
5013            }
5014            row.set(MeasureAggregator.name, aggNumber);
5015
5016            // DATA_TYPE DBType best guess is string
5017
int dbType = DBType.WSTR.userOrdinal;
5018            String JavaDoc datatype = (String JavaDoc)
5019                member.getPropertyValue(Property.DATATYPE.getName());
5020            if (datatype != null) {
5021                if (datatype.equals("Integer")) {
5022                    dbType = DBType.I4.userOrdinal;
5023                } else if (datatype.equals("Numeric")) {
5024                    dbType = DBType.R8.userOrdinal;
5025                } else {
5026                    dbType = DBType.WSTR.userOrdinal;
5027                }
5028            }
5029            row.set(DataType.name, dbType);
5030            row.set(MeasureIsVisible.name, true);
5031
5032            if (levelListStr != null) {
5033                row.set(LevelsList.name, levelListStr);
5034            }
5035
5036            row.set(Description.name, desc);
5037            addRow(row, rows);
5038        }
5039        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
5040            switch (propertyDef) {
5041            case Content:
5042                break;
5043            default:
5044                super.setProperty(propertyDef, value);
5045            }
5046        }
5047    }
5048
5049    static class MdschemaMembersRowset extends Rowset {
5050        private final RestrictionTest schemaNameRT;
5051        private final RestrictionTest cubeNameRT;
5052        private final RestrictionTest dimensionUniqueNameRT;
5053        private final RestrictionTest hierarchyUniqueNameRT;
5054        private final RestrictionTest memberNameRT;
5055        private final RestrictionTest memberUniqueNameRT;
5056        private final RestrictionTest memberTypeRT;
5057
5058        MdschemaMembersRowset(XmlaRequest request, XmlaHandler handler) {
5059            super(MDSCHEMA_MEMBERS, request, handler);
5060            schemaNameRT = getRestrictionTest(SchemaName);
5061            cubeNameRT = getRestrictionTest(CubeName);
5062            dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName);
5063            hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName);
5064            memberNameRT = getRestrictionTest(MemberName);
5065            memberUniqueNameRT = getRestrictionTest(MemberUniqueName);
5066            memberTypeRT = getRestrictionTest(MemberType);
5067        }
5068
5069        private static final Column CatalogName =
5070            new Column(
5071                "CATALOG_NAME",
5072                Type.String,
5073                null,
5074                Column.RESTRICTION,
5075                Column.OPTIONAL,
5076                "The name of the catalog to which this member belongs. ");
5077        private static final Column SchemaName =
5078            new Column(
5079                "SCHEMA_NAME",
5080                Type.String,
5081                null,
5082                Column.RESTRICTION,
5083                Column.OPTIONAL,
5084                "The name of the schema to which this member belongs. ");
5085        private static final Column CubeName =
5086            new Column(
5087                "CUBE_NAME",
5088                Type.String,
5089                null,
5090                Column.RESTRICTION,
5091                Column.REQUIRED,
5092                "Name of the cube to which this member belongs.");
5093        private static final Column DimensionUniqueName =
5094            new Column(
5095                "DIMENSION_UNIQUE_NAME",
5096                Type.String,
5097                null,
5098                Column.RESTRICTION,
5099                Column.REQUIRED,
5100                "Unique name of the dimension to which this member belongs. ");
5101        private static final Column HierarchyUniqueName =
5102            new Column(
5103                "HIERARCHY_UNIQUE_NAME",
5104                Type.String,
5105                null,
5106                Column.RESTRICTION,
5107                Column.REQUIRED,
5108                "Unique name of the hierarchy. If the member belongs to more than one hierarchy, there is one row for each hierarchy to which it belongs.");
5109        private static final Column LevelUniqueName =
5110            new Column(
5111                "LEVEL_UNIQUE_NAME",
5112                Type.String,
5113                null,
5114                Column.RESTRICTION,
5115                Column.REQUIRED,
5116                " Unique name of the level to which the member belongs.");
5117        private static final Column LevelNumber =
5118            new Column(
5119                "LEVEL_NUMBER",
5120                Type.UnsignedInteger,
5121                null,
5122                Column.RESTRICTION,
5123                Column.REQUIRED,
5124                "The distance of the member from the root of the hierarchy.");
5125        private static final Column MemberOrdinal =
5126            new Column(
5127                "MEMBER_ORDINAL",
5128                Type.UnsignedInteger,
5129                null,
5130                Column.NOT_RESTRICTION,
5131                Column.REQUIRED,
5132                "Ordinal number of the member. Sort rank of the member when members of this dimension are sorted in their natural sort order. If providers do not have the concept of natural ordering, this should be the rank when sorted by MEMBER_NAME.");
5133        private static final Column MemberName =
5134            new Column(
5135                "MEMBER_NAME",
5136                Type.String,
5137                null,
5138                Column.RESTRICTION,
5139                Column.REQUIRED,
5140                "Name of the member.");
5141        private static final Column MemberUniqueName =
5142            new Column(
5143                "MEMBER_UNIQUE_NAME",
5144                Type.String,
5145                null,
5146                Column.RESTRICTION,
5147                Column.REQUIRED,
5148                " Unique name of the member.");
5149        private static final Column MemberType =
5150            new Column(
5151                "MEMBER_TYPE",
5152                Type.Integer,
5153                null,
5154                Column.RESTRICTION,
5155                Column.REQUIRED,
5156                "Type of the member.");
5157        private static final Column MemberGuid =
5158            new Column(
5159                "MEMBER_GUID",
5160                Type.UUID,
5161                null,
5162                Column.NOT_RESTRICTION,
5163                Column.OPTIONAL,
5164                "Memeber GUID.");
5165        private static final Column MemberCaption =
5166            new Column(
5167                "MEMBER_CAPTION",
5168                Type.String,
5169                null,
5170                Column.RESTRICTION,
5171                Column.REQUIRED,
5172                "A label or caption associated with the member.");
5173        private static final Column ChildrenCardinality =
5174            new Column(
5175                "CHILDREN_CARDINALITY",
5176                Type.UnsignedInteger,
5177                null,
5178                Column.NOT_RESTRICTION,
5179                Column.REQUIRED,
5180                "Number of children that the member has.");
5181        private static final Column ParentLevel =
5182            new Column(
5183                "PARENT_LEVEL",
5184                Type.UnsignedInteger,
5185                null,
5186                Column.NOT_RESTRICTION,
5187                Column.REQUIRED,
5188                "The distance of the member's parent from the root level of the hierarchy. ");
5189        private static final Column ParentUniqueName =
5190            new Column(
5191                "PARENT_UNIQUE_NAME",
5192                Type.String,
5193                null,
5194                Column.NOT_RESTRICTION,
5195                Column.OPTIONAL,
5196                "Unique name of the member's parent.");
5197        private static final Column ParentCount =
5198            new Column(
5199                "PARENT_COUNT",
5200                Type.UnsignedInteger,
5201                null,
5202                Column.NOT_RESTRICTION,
5203                Column.REQUIRED,
5204                "Number of parents that this member has.");
5205        private static final Column TreeOp =
5206            new Column(
5207                "TREE_OP",
5208                Type.Enumeration,
5209                Enumeration.TreeOp.enumeration,
5210                Column.RESTRICTION,
5211                Column.OPTIONAL,
5212                "Tree Operation");
5213        /* Mondrian specified member properties. */
5214        private static final Column Depth =
5215            new Column(
5216                "DEPTH",
5217                Type.Integer,
5218                null,
5219                Column.NOT_RESTRICTION,
5220                Column.OPTIONAL,
5221                "depth");
5222
5223        public void populate(XmlaResponse response, List<Row> rows)
5224            throws XmlaException {
5225
5226            DataSourcesConfig.DataSource ds =
5227                handler.getDataSource(request);
5228            String JavaDoc roleStr = request.getRole();
5229            DataSourcesConfig.Catalog[] catalogs =
5230                handler.getCatalogs(request, ds);
5231
5232            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
5233                if (dsCatalog == null || dsCatalog.definition == null) {
5234                    continue;
5235                }
5236                Connection connection =
5237                    handler.getConnection(dsCatalog, roleStr);
5238                if (connection == null) {
5239                    continue;
5240                }
5241
5242                String JavaDoc catalogName = dsCatalog.name;
5243                if (schemaNameRT.passes(catalogName)) {
5244                    Role role = connection.getSchema().lookupRole(roleStr);
5245                    populateCatalog(connection, role, catalogName, rows);
5246                }
5247            }
5248        }
5249        protected void populateCatalog(Connection connection,
5250            Role role,
5251            String JavaDoc catalogName,
5252            List<Row> rows)
5253            throws XmlaException {
5254
5255            for (Cube cube : sortedCubes(connection.getSchema())) {
5256                if (cubeNameRT.passes(cube.getName())) {
5257                    SchemaReader schemaReader = cube.getSchemaReader(role);
5258                    populateCube(schemaReader, catalogName, cube, rows);
5259                }
5260            }
5261        }
5262        protected void populateCube(SchemaReader schemaReader,
5263            String JavaDoc catalogName,
5264            Cube cube,
5265            List<Row> rows)
5266            throws XmlaException {
5267
5268            if (isRestricted(MemberUniqueName)) {
5269                // NOTE: it is believed that if MEMBER_UNIQUE_NAME is
5270
// a restriction, then none of the remaining possible
5271
// restrictions other than TREE_OP are relevant
5272
// (or allowed??).
5273
outputUniqueMemberName(schemaReader,
5274                    catalogName, cube, rows);
5275            } else if (isRestricted(LevelUniqueName)) {
5276                // Note: If the LEVEL_UNIQUE_NAME has been specified, then
5277
// the dimension and hierarchy are specified implicitly.
5278
String JavaDoc levelUniqueName =
5279                    getRestrictionValueAsString(LevelUniqueName);
5280                if (levelUniqueName == null) {
5281                    // The query specified two or more unique names
5282
// which means that nothing will match.
5283
return;
5284                }
5285                final String JavaDoc[] nameParts = Util.explode(levelUniqueName);
5286                Hierarchy hier = cube.lookupHierarchy(nameParts[0], false);
5287                if (hier == null) {
5288                    return;
5289                }
5290                Level[] levels = hier.getLevels();
5291                for (Level level : levels) {
5292                    if (!level.getUniqueName().equals(levelUniqueName)) {
5293                        continue;
5294                    }
5295                    // Get members of this level, without access control, but
5296
// including calculated members.
5297
Member[] members =
5298                        cube.getSchemaReader(null).getLevelMembers(level, true);
5299                    outputMembers(schemaReader, members,
5300                        catalogName, cube, rows);
5301                }
5302            } else {
5303                for (Dimension dimension : cube.getDimensions()) {
5304                    String JavaDoc uniqueName = dimension.getUniqueName();
5305                    if (dimensionUniqueNameRT.passes(uniqueName)) {
5306                        populateDimension(schemaReader, catalogName,
5307                            cube, dimension, rows);
5308                    }
5309                }
5310            }
5311        }
5312        protected void populateDimension(SchemaReader schemaReader,
5313            String JavaDoc catalogName,
5314            Cube cube,
5315            Dimension dimension,
5316            List<Row> rows)
5317            throws XmlaException {
5318
5319            Hierarchy[] hierarchies = dimension.getHierarchies();
5320            for (Hierarchy hierarchy : hierarchies) {
5321                String JavaDoc uniqueName = hierarchy.getUniqueName();
5322                if (hierarchyUniqueNameRT.passes(uniqueName)) {
5323                    populateHierarchy(schemaReader, catalogName,
5324                        cube, hierarchy, rows);
5325                }
5326            }
5327        }
5328        protected void populateHierarchy(SchemaReader schemaReader,
5329            String JavaDoc catalogName,
5330            Cube cube,
5331            Hierarchy hierarchy,
5332            List<Row> rows)
5333            throws XmlaException {
5334
5335
5336            if (isRestricted(LevelNumber)) {
5337                int levelNumber = getRestrictionValueAsInt(LevelNumber);
5338                if (levelNumber == -1) {
5339                    LOGGER.warn("RowsetDefinition.populateHierarchy: " +
5340                        "LevelNumber invalid"
5341                    );
5342                    return;
5343                }
5344                Level[] levels = hierarchy.getLevels();
5345                if (levelNumber >= levels.length) {
5346                    LOGGER.warn("RowsetDefinition.populateHierarchy: " +
5347                        "LevelNumber (" +
5348                        levelNumber +
5349                        ") is greater than number of levels (" +
5350                        levels.length +
5351                        ") for hierarchy \"" +
5352                        hierarchy.getUniqueName() +
5353                        "\""
5354                    );
5355                    return;
5356                }
5357
5358                Level level = levels[levelNumber];
5359                Member[] members =
5360                    schemaReader.getLevelMembers(level, false);
5361                outputMembers(schemaReader, members, catalogName, cube, rows);
5362            } else {
5363                // At this point we get ALL of the members associated with
5364
// the Hierarchy (rather than getting them one at a time).
5365
// The value returned is not used at this point but they are
5366
// now cached in the SchemaReader.
5367
Member[][] membersArray =
5368                    RolapMember.getAllMembers(schemaReader, hierarchy);
5369                for (Member[] members : membersArray) {
5370                    outputMembers(schemaReader, members,
5371                        catalogName, cube, rows);
5372                }
5373            }
5374        }
5375
5376        /**
5377         * Returns whether a value contains all of the bits in a mask.
5378         */

5379        private static boolean mask(int value, int mask) {
5380            return (value & mask) == mask;
5381        }
5382
5383        /**
5384         * Adds a member to a result list and, depending upon the
5385         * <code>treeOp</code> parameter, other relatives of the member. This
5386         * method recursively invokes itself to walk up, down, or across the
5387         * hierarchy.
5388         */

5389        private void populateMember(
5390            final SchemaReader schemaReader,
5391            String JavaDoc catalogName,
5392            Cube cube,
5393            Member member,
5394            int treeOp,
5395            List<Row> rows) {
5396
5397            // Visit node itself.
5398
if (mask(treeOp, Enumeration.TreeOp.Self.userOrdinal())) {
5399                outputMember(schemaReader, member, catalogName, cube, rows);
5400            }
5401            // Visit node's siblings (not including itself).
5402
if (mask(treeOp, Enumeration.TreeOp.Siblings.userOrdinal())) {
5403                final Member parent =
5404                    schemaReader.getMemberParent(member);
5405                final Member[] siblings = (parent == null)
5406                    ? schemaReader.getHierarchyRootMembers(member.getHierarchy())
5407                    : schemaReader.getMemberChildren(parent);
5408
5409                for (Member sibling : siblings) {
5410                    if (sibling == member) {
5411                        continue;
5412                    }
5413                    populateMember(
5414                        schemaReader, catalogName,
5415                        cube, sibling,
5416                        Enumeration.TreeOp.Self.userOrdinal(), rows);
5417                }
5418            }
5419            // Visit node's descendants or its immediate children, but not both.
5420
if (mask(treeOp, Enumeration.TreeOp.Descendants.userOrdinal())) {
5421                final Member[] children = schemaReader.getMemberChildren(member);
5422                for (Member child : children) {
5423                    populateMember(
5424                        schemaReader, catalogName,
5425                        cube, child,
5426                        Enumeration.TreeOp.Self.userOrdinal() |
5427                            Enumeration.TreeOp.Descendants.userOrdinal(),
5428                        rows);
5429                }
5430            } else if (mask(treeOp, Enumeration.TreeOp.Children.userOrdinal())) {
5431                final Member[] children =
5432                    schemaReader.getMemberChildren(member);
5433                for (Member child : children) {
5434                    populateMember(
5435                        schemaReader, catalogName,
5436                        cube, child,
5437                        Enumeration.TreeOp.Self.userOrdinal(), rows);
5438                }
5439            }
5440            // Visit node's ancestors or its immediate parent, but not both.
5441
if (mask(treeOp, Enumeration.TreeOp.Ancestors.userOrdinal())) {
5442                final Member parent = schemaReader.getMemberParent(member);
5443                if (parent != null) {
5444                    populateMember(
5445                        schemaReader, catalogName,
5446                        cube, parent,
5447                        Enumeration.TreeOp.Self.userOrdinal() |
5448                            Enumeration.TreeOp.Ancestors.userOrdinal(), rows);
5449                }
5450            } else if (mask(treeOp, Enumeration.TreeOp.Parent.userOrdinal())) {
5451                final Member parent = schemaReader.getMemberParent(member);
5452                if (parent != null) {
5453                    populateMember(
5454                        schemaReader, catalogName,
5455                        cube, parent,
5456                        Enumeration.TreeOp.Self.userOrdinal(), rows);
5457                }
5458            }
5459        }
5460
5461        protected ArrayList<Column> pruneRestrictions(ArrayList<Column> list) {
5462            // If they've restricted TreeOp, we don't want to literally filter
5463
// the result on TreeOp (because it's not an output column) or
5464
// on MemberUniqueName (because TreeOp will have caused us to
5465
// generate other members than the one asked for).
5466
if (list.contains(TreeOp)) {
5467                list.remove(TreeOp);
5468                list.remove(MemberUniqueName);
5469            }
5470            return list;
5471        }
5472
5473        private void outputMembers(
5474            final SchemaReader schemaReader,
5475            Member[] members,
5476            final String JavaDoc catalogName,
5477            Cube cube, List<Row> rows) {
5478
5479            for (Member member : members) {
5480                outputMember(schemaReader, member, catalogName, cube, rows);
5481            }
5482        }
5483        private void outputUniqueMemberName(
5484            final SchemaReader schemaReader,
5485            final String JavaDoc catalogName,
5486            Cube cube, List<Row> rows) {
5487
5488            String JavaDoc memberUniqueName =
5489                getRestrictionValueAsString(MemberUniqueName);
5490            if (memberUniqueName == null) {
5491                // The query specified two or more unique names
5492
// which means that nothing will match.
5493
return;
5494            }
5495            final String JavaDoc[] nameParts = Util.explode(memberUniqueName);
5496
5497            Member member = schemaReader.getMemberByUniqueName(
5498                nameParts, false);
5499
5500            if (member == null) {
5501                return;
5502            }
5503            if (isRestricted(TreeOp)) {
5504                int treeOp = getRestrictionValueAsInt(TreeOp);
5505                if (treeOp == -1) {
5506                    return;
5507                }
5508                populateMember(
5509                    schemaReader, catalogName,
5510                    cube, member, treeOp, rows);
5511            } else {
5512                outputMember(schemaReader, member, catalogName, cube, rows);
5513            }
5514        }
5515
5516        private void outputMember(
5517            final SchemaReader schemaReader,
5518            Member member,
5519            final String JavaDoc catalogName,
5520            Cube cube, List<Row> rows) {
5521
5522            // Access control
5523
if (!canAccess(schemaReader, member)) {
5524                return;
5525            }
5526            if (! memberNameRT.passes(member.getName())) {
5527                return;
5528            }
5529            if (! memberTypeRT.passes(member.getMemberType())) {
5530                return;
5531            }
5532
5533            if (member.getOrdinal() == -1) {
5534                RolapMember.setOrdinals(schemaReader, member);
5535            }
5536
5537            // Check whether the members is visible, otherwise do not dump.
5538
Boolean JavaDoc isVisible = (Boolean JavaDoc)
5539                member.getPropertyValue(Property.VISIBLE.name);
5540            if (isVisible != null && !isVisible) {
5541                return;
5542            }
5543
5544            final Level level = member.getLevel();
5545            final Hierarchy hierarchy = level.getHierarchy();
5546            final Dimension dimension = hierarchy.getDimension();
5547            Row row = new Row();
5548            row.set(CatalogName.name, catalogName);
5549            row.set(SchemaName.name, catalogName);
5550            row.set(CubeName.name, cube.getName());
5551            row.set(DimensionUniqueName.name, dimension.getUniqueName());
5552            row.set(HierarchyUniqueName.name, hierarchy.getUniqueName());
5553            row.set(LevelUniqueName.name, level.getUniqueName());
5554            row.set(LevelNumber.name, level.getDepth());
5555            row.set(MemberOrdinal.name, member.getOrdinal());
5556            row.set(MemberName.name, member.getName());
5557            row.set(MemberUniqueName.name, member.getUniqueName());
5558            row.set(MemberType.name, member.getMemberType().ordinal());
5559            //row.set(MemberGuid.name, "");
5560
row.set(MemberCaption.name, member.getCaption());
5561            row.set(ChildrenCardinality.name,
5562                member.getPropertyValue(Property.CHILDREN_CARDINALITY.name));
5563            row.set(ChildrenCardinality.name, 100);
5564
5565            row.set(ParentLevel.name,
5566                (member.getParentMember() == null)
5567                    ? 0 : member.getParentMember().getDepth());
5568
5569            String JavaDoc parentUniqueName = member.getParentUniqueName();
5570            if (parentUniqueName != null) {
5571                row.set(ParentUniqueName.name, parentUniqueName);
5572            } else {
5573                // row.set(ParentUniqueName.name, "");
5574
}
5575
5576            row.set(ParentCount.name, member.getParentMember() == null ? 0 : 1);
5577
5578            row.set(Depth.name, member.getDepth());
5579            addRow(row, rows);
5580        }
5581        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
5582            switch (propertyDef) {
5583            case Content:
5584                break;
5585            default:
5586                super.setProperty(propertyDef, value);
5587            }
5588        }
5589
5590/*
5591RME: this code was used to test various algorithms to set member ordinals.
5592        void setOrdinals(SchemaReader schemaReader, Member startMember) {
5593            //int v = 0;
5594            //int v = 1;
5595            //int v = 2;
5596            //int v = 3;
5597            int v = 4;
5598LOGGER.debug("RowsetDefinition.setOrdinals: v==" +v);
5599            if (v == 0) {
5600                // foodmart time for Sales: time=63
5601                // For very big data set, it takes time= 651865ms
5602                RolapMember.setOrdinals(schemaReader, startMember);
5603            } else if (v == 1) {
5604                // foodmart time for Sales: time=32
5605                // result is same as v == 0
5606                // For very big data set, it takes time= 73880ms
5607                Hierarchy hierarchy = startMember.getHierarchy();
5608                Member[][] membersArray =
5609                    RolapMember.getAllMembers(schemaReader, hierarchy);
5610                RolapMember.setOrdinals(schemaReader, startMember);
5611            } else if (v == 2) {
5612                // foodmart time for Sales: time=18
5613                // result is NOT same as v == 0
5614                int ordinal = 0;
5615                Hierarchy hierarchy = startMember.getHierarchy();
5616                Member[][] membersArray =
5617                    RolapMember.getAllMembers(schemaReader, hierarchy);
5618
5619                // RME: this does a breath first setting of ordinals
5620                // for very big data set, it takes time= 4197ms
5621                for (int i = 0; i < membersArray.length; i++) {
5622                    Member[] members = membersArray[i];
5623                    for (int j = 0; j < members.length; j++) {
5624                        Member member = members[j];
5625                         ((RolapMember) member).setOrdinal(ordinal++);
5626                    }
5627                }
5628            } else if (v == 3) {
5629                // foodmart time for Sales: time=19
5630                // result is same as v == 0
5631                int ordinal = 1;
5632                int depth = 1;
5633                Hierarchy hierarchy = startMember.getHierarchy();
5634                Member[][] membersArray =
5635                    RolapMember.getAllMembers(schemaReader, hierarchy);
5636                Member[] rootMembers = membersArray[0];
5637LOGGER.debug("RowsetDefinition.setOrdinals: rootMembers.length=" +rootMembers.length);
5638                // RME: this does a depth first setting of ordinals
5639                // for very big data set, it takes time= 97310ms
5640                for (int i = 0; i < rootMembers.length; i++) {
5641                    Member member = rootMembers[i];
5642                    if (member.getOrdinal() == -1) {
5643LOGGER.debug("RowsetDefinition.setOrdinals: member=" +member.getName());
5644                        ((RolapMember) member).setOrdinal(ordinal++);
5645                    } else {
5646LOGGER.debug("RowsetDefinition.setOrdinals: NO member=" +member.getName());
5647                    }
5648                    ordinal = setOrdinals(ordinal, member, membersArray, depth);
5649                }
5650            } else {
5651                // foodmart time for Sales: time=17
5652                // result is same as v == 0
5653                // bottom up depth first
5654                // For very big data set, it takes time= 4241ms
5655                int ordinal = 1;
5656                Hierarchy hierarchy = startMember.getHierarchy();
5657                Member[][] membersArray =
5658                    RolapMember.getAllMembers(schemaReader, hierarchy);
5659                Member[] leafMembers = membersArray[membersArray.length-1];
5660
5661                for (int i = 0; i < leafMembers.length; i++) {
5662                    Member child = leafMembers[i];
5663                    ordinal = bottomUpSetOrdinals(ordinal, child);
5664                    ((RolapMember) child).setOrdinal(ordinal++);
5665                }
5666                boolean needsFullTopDown = false;
5667                for (int i = 0; i < membersArray.length-1; i++) {
5668                    Member[] members = membersArray[i];
5669                    for (int j = 0; j < members.length; j++) {
5670                        Member member = members[j];
5671                        if (member.getOrdinal() == -1) {
5672                            needsFullTopDown = true;
5673                            break;
5674                        }
5675                    }
5676                }
5677LOGGER.debug("RowsetDefinition.setOrdinals: needsFullTopDown=" +needsFullTopDown);
5678            }
5679        }
5680        int bottomUpSetOrdinals(int ordinal, Member child) {
5681            Member parent = child.getParentMember();
5682            if (parent.getOrdinal() == -1) {
5683                ordinal = bottomUpSetOrdinals(ordinal, parent);
5684                ((RolapMember) parent).setOrdinal(ordinal++);
5685            }
5686            return ordinal;
5687        }
5688
5689
5690        // RME: this is used as part of the depth first setting of ordinals
5691        int setOrdinals(int ordinal, Member parent, Member[][] membersArray, int depth) {
5692            boolean nextLevelExists = (depth+1 < membersArray.length);
5693            Member[] members = membersArray[depth];
5694            for (int i = 0; i < members.length; i++) {
5695                Member member = members[i];
5696                if (member.getParentMember() == parent) {
5697                    ((RolapMember) member).setOrdinal(ordinal++);
5698                    if (nextLevelExists) {
5699                        ordinal =
5700                            setOrdinals(ordinal, member, membersArray, depth+1);
5701                    }
5702                }
5703            }
5704            return ordinal;
5705        }
5706*/

5707
5708    }
5709
5710    static class MdschemaSetsRowset extends Rowset {
5711        MdschemaSetsRowset(XmlaRequest request, XmlaHandler handler) {
5712            super(MDSCHEMA_SETS, request, handler);
5713        }
5714
5715        private static final Column CatalogName =
5716            new Column(
5717                "CATALOG_NAME",
5718                Type.String,
5719                null,
5720                true,
5721                true,
5722                null);
5723        private static final Column SchemaName =
5724            new Column(
5725                "SCHEMA_NAME",
5726                Type.String,
5727                null,
5728                true,
5729                true,
5730                null);
5731        private static final Column CubeName =
5732            new Column(
5733                "CUBE_NAME",
5734                Type.String,
5735                null,
5736                true,
5737                false,
5738                null);
5739        private static final Column SetName =
5740            new Column(
5741                "SET_NAME",
5742                Type.String,
5743                null,
5744                true,
5745                false,
5746                null);
5747        private static final Column SetCaption =
5748            new Column(
5749                "SET_CAPTION",
5750                Type.String,
5751                null,
5752                true,
5753                true,
5754                null);
5755        private static final Column Scope =
5756            new Column(
5757                "SCOPE",
5758                Type.Integer,
5759                null,
5760                true,
5761                false,
5762                null);
5763        private static final Column Description =
5764            new Column("DESCRIPTION",
5765                Type.String,
5766                null,
5767                false,
5768                true,
5769                "A human-readable description of the measure.");
5770
5771        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
5772            throw new XmlaException(
5773                CLIENT_FAULT_FC,
5774                HSB_UNSUPPORTED_OPERATION_CODE,
5775                HSB_UNSUPPORTED_OPERATION_FAULT_FS,
5776                new UnsupportedOperationException JavaDoc("MDSCHEMA_SETS"));
5777        }
5778    }
5779
5780    static class MdschemaPropertiesRowset extends Rowset {
5781        private final RestrictionTest schemaNameRT;
5782        private final RestrictionTest cubeNameRT;
5783        private final RestrictionTest dimensionUniqueNameRT;
5784        private final RestrictionTest hierarchyUniqueNameRT;
5785        private final RestrictionTest propertyNameRT;
5786        MdschemaPropertiesRowset(XmlaRequest request, XmlaHandler handler) {
5787            super(MDSCHEMA_PROPERTIES, request, handler);
5788            schemaNameRT = getRestrictionTest(SchemaName);
5789            cubeNameRT = getRestrictionTest(CubeName);
5790            dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName);
5791            hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName);
5792            propertyNameRT = getRestrictionTest(PropertyName);
5793        }
5794
5795        private static final int MDPROP_MEMBER = 0x01;
5796        private static final int MDPROP_CELL = 0x02;
5797        private static final int MDPROP_SYSTEM = 0x04;
5798        private static final int MDPROP_BLOB = 0x08;
5799
5800        private static final int MD_PROPTYPE_REGULAR = 0x00;
5801
5802        private static final Column CatalogName =
5803            new Column(
5804                "CATALOG_NAME",
5805                Type.String,
5806                null,
5807                Column.RESTRICTION,
5808                Column.OPTIONAL,
5809                "The name of the database.");
5810        private static final Column SchemaName =
5811            new Column(
5812                "SCHEMA_NAME",
5813                Type.String,
5814                null,
5815                Column.RESTRICTION,
5816                Column.OPTIONAL,
5817                "The name of the schema to which this property belongs.");
5818        private static final Column CubeName =
5819            new Column(
5820                "CUBE_NAME",
5821                Type.String,
5822                null,
5823                Column.RESTRICTION,
5824                Column.REQUIRED,
5825                "The name of the cube.");
5826        private static final Column DimensionUniqueName =
5827            new Column(
5828                "DIMENSION_UNIQUE_NAME",
5829                Type.String,
5830                null,
5831                Column.RESTRICTION,
5832                Column.REQUIRED,
5833                "The unique name of the dimension.");
5834        private static final Column HierarchyUniqueName =
5835            new Column(
5836                "HIERARCHY_UNIQUE_NAME",
5837                Type.String,
5838                null,
5839                Column.RESTRICTION,
5840                Column.REQUIRED,
5841                "The unique name of the hierarchy.");
5842        private static final Column LevelUniqueName =
5843            new Column(
5844                "LEVEL_UNIQUE_NAME",
5845                Type.String,
5846                null,
5847                Column.RESTRICTION,
5848                Column.REQUIRED,
5849                "The unique name of the level to which this property belongs.");
5850        // According to MS this should not be nullable
5851
private static final Column MemberUniqueName =
5852            new Column(
5853                "MEMBER_UNIQUE_NAME",
5854                Type.String,
5855                null,
5856                Column.RESTRICTION,
5857                Column.OPTIONAL,
5858                "The unique name of the member to which the property belongs.");
5859        private static final Column PropertyName =
5860            new Column(
5861                "PROPERTY_NAME",
5862                Type.String,
5863                null,
5864                Column.RESTRICTION,
5865                Column.REQUIRED,
5866                "Name of the property.");
5867        private static final Column PropertyType =
5868            new Column(
5869                "PROPERTY_TYPE",
5870                Type.Short,
5871                null,
5872                Column.RESTRICTION,
5873                Column.REQUIRED,
5874                "A bitmap that specifies the type of the property");
5875        private static final Column PropertyCaption =
5876            new Column(
5877                "PROPERTY_CAPTION",
5878                Type.String,
5879                null,
5880                Column.NOT_RESTRICTION,
5881                Column.REQUIRED,
5882                "A label or caption associated with the property, used primarily for display purposes.");
5883        private static final Column DataType =
5884            new Column(
5885                "DATA_TYPE",
5886                Type.UnsignedShort,
5887                null,
5888                Column.NOT_RESTRICTION,
5889                Column.REQUIRED,
5890                "Data type of the property.");
5891        private static final Column PropertyContentType =
5892            new Column(
5893                "PROPERTY_CONTENT_TYPE",
5894                Type.Short,
5895                null,
5896                Column.RESTRICTION,
5897                Column.OPTIONAL,
5898                "The type of the property. ");
5899        private static final Column Description =
5900            new Column(
5901                "DESCRIPTION",
5902                Type.String,
5903                null,
5904                Column.NOT_RESTRICTION,
5905                Column.OPTIONAL,
5906                "A human-readable description of the measure. ");
5907
5908        public void populate(XmlaResponse response, List<Row> rows) throws XmlaException {
5909            DataSourcesConfig.DataSource ds =
5910                handler.getDataSource(request);
5911            String JavaDoc roleStr = request.getRole();
5912            DataSourcesConfig.Catalog[] catalogs =
5913                handler.getCatalogs(request, ds);
5914
5915            for (DataSourcesConfig.Catalog dsCatalog : catalogs) {
5916                if (dsCatalog == null || dsCatalog.definition == null) {
5917                    continue;
5918                }
5919                Connection connection =
5920                    handler.getConnection(dsCatalog, roleStr);
5921                if (connection == null) {
5922                    continue;
5923                }
5924
5925                String JavaDoc catalogName = dsCatalog.name;
5926                if (schemaNameRT.passes(catalogName)) {
5927                    Role role = connection.getSchema().lookupRole(roleStr);
5928                    populateCatalog(connection, role, catalogName, rows);
5929                }
5930            }
5931        }
5932        protected void populateCatalog(Connection connection,
5933            Role role,
5934            String JavaDoc catalogName,
5935            List<Row> rows)
5936            throws XmlaException {
5937
5938            for (Cube cube : sortedCubes(connection.getSchema())) {
5939                if (cubeNameRT.passes(cube.getName())) {
5940                    SchemaReader schemaReader = cube.getSchemaReader(role);
5941                    populateCube(schemaReader, catalogName, cube, rows);
5942                }
5943            }
5944        }
5945
5946        protected void populateCube(SchemaReader schemaReader,
5947            String JavaDoc catalogName,
5948            Cube cube,
5949            List<Row> rows)
5950            throws XmlaException {
5951            if (isRestricted(LevelUniqueName)) {
5952                // Note: If the LEVEL_UNIQUE_NAME has been specified, then
5953
// the dimension and hierarchy are specified implicitly.
5954
String JavaDoc levelUniqueName =
5955                    getRestrictionValueAsString(LevelUniqueName);
5956                if (levelUniqueName == null) {
5957                    // The query specified two or more unique names
5958
// which means that nothing will match.
5959
return;
5960                }
5961                final String JavaDoc[] nameParts = Util.explode(levelUniqueName);
5962                Hierarchy hier = cube.lookupHierarchy(nameParts[0], false);
5963                if (hier == null) {
5964                    return;
5965                }
5966                Level[] levels = hier.getLevels();
5967                for (Level level : levels) {
5968                    if (level.getUniqueName().equals(levelUniqueName)) {
5969                        populateLevel(schemaReader, catalogName,
5970                            cube, level, rows);
5971                        break;
5972                    }
5973                }
5974
5975            } else {
5976                for (Dimension dimension : cube.getDimensions()) {
5977                    String JavaDoc uniqueName = dimension.getUniqueName();
5978                    if (dimensionUniqueNameRT.passes(uniqueName)) {
5979                        populateDimension(schemaReader, catalogName,
5980                            cube, dimension, rows);
5981                    }
5982                }
5983            }
5984        }
5985        private void populateDimension(
5986            final SchemaReader schemaReader,
5987            final String JavaDoc catalogName,
5988            Cube cube, Dimension dimension, List<Row> rows) {
5989
5990            Hierarchy[] hierarchies = dimension.getHierarchies();
5991            for (Hierarchy hierarchy : hierarchies) {
5992                String JavaDoc unique = hierarchy.getUniqueName();
5993                if (hierarchyUniqueNameRT.passes(unique)) {
5994                    populateHierarchy(schemaReader, catalogName,
5995                        cube, hierarchy, rows);
5996                }
5997            }
5998        }
5999        private void populateHierarchy(
6000            final SchemaReader schemaReader,
6001            final String JavaDoc catalogName,
6002            Cube cube, Hierarchy hierarchy, List<Row> rows) {
6003
6004            Level[] levels = hierarchy.getLevels();
6005            for (Level level : levels) {
6006                populateLevel(schemaReader, catalogName,
6007                    cube, level, rows);
6008            }
6009        }
6010        private void populateLevel(
6011            final SchemaReader schemaReader,
6012            final String JavaDoc catalogName,
6013            Cube cube, Level level, List<Row> rows) {
6014
6015            Property[] properties = level.getProperties();
6016            for (Property property : properties) {
6017                if (propertyNameRT.passes(property.getName())) {
6018                    outputProperty(schemaReader, property,
6019                        catalogName, cube, level, rows);
6020                }
6021            }
6022        }
6023
6024        private void outputProperty(
6025            final SchemaReader schemaReader,
6026            Property property,
6027            final String JavaDoc catalogName,
6028            Cube cube, Level level, List<Row> rows) {
6029
6030            Hierarchy hierarchy = level.getHierarchy();
6031            Dimension dimension = hierarchy.getDimension();
6032
6033            String JavaDoc propertyName = property.getName();
6034
6035            Row row = new Row();
6036            row.set(CatalogName.name, catalogName);
6037            row.set(SchemaName.name, catalogName);
6038            row.set(CubeName.name, cube.getName());
6039            row.set(DimensionUniqueName.name, dimension.getUniqueName());
6040            row.set(HierarchyUniqueName.name, hierarchy.getUniqueName());
6041            row.set(LevelUniqueName.name, level.getUniqueName());
6042            //TODO: what is the correct value here
6043
//row.set(MemberUniqueName.name, "");
6044

6045            row.set(PropertyName.name, propertyName);
6046            // Only member properties now
6047
row.set(PropertyType.name, MDPROP_MEMBER);
6048            row.set(PropertyContentType.name, MD_PROPTYPE_REGULAR);
6049            row.set(PropertyCaption.name, property.getCaption());
6050            DBType dbType = getDBTypeFromProperty(property);
6051            row.set(DataType.name, dbType.userOrdinal);
6052
6053            String JavaDoc desc = cube.getName() +
6054                " Cube - " +
6055                hierarchy.getName() +
6056                " Hierarchy - " +
6057                level.getName() +
6058                " Level - " +
6059                property.getName() +
6060                " Property";
6061            row.set(Description.name, desc);
6062
6063            addRow(row, rows);
6064        }
6065
6066
6067        protected void setProperty(PropertyDefinition propertyDef, String JavaDoc value) {
6068            switch (propertyDef) {
6069            case Content:
6070                break;
6071            default:
6072                super.setProperty(propertyDef, value);
6073            }
6074        }
6075    }
6076
6077    private static boolean canAccess(SchemaReader schemaReader, OlapElement elem) {
6078        Role role = schemaReader.getRole();
6079        return role.canAccess(elem);
6080    }
6081
6082    private static <T extends Comparable JavaDoc> List<T> sort(
6083        Collection<T> collection)
6084    {
6085        Object JavaDoc[] a = collection.toArray(new Object JavaDoc[collection.size()]);
6086        Arrays.sort(a);
6087        return (List<T>) (List) Arrays.asList(a);
6088    }
6089
6090    private static <T> List<T> sortArray(
6091        T[] a,
6092        Comparator<T> comparator)
6093    {
6094        T[] a2 = a.clone();
6095        Arrays.sort(a2, comparator);
6096        return Arrays.asList(a2);
6097    }
6098
6099    static void serialize(StringBuilder JavaDoc buf, Collection<String JavaDoc> strings) {
6100        int k = 0;
6101        for (String JavaDoc name : sort(strings)) {
6102            if (k++ > 0) {
6103                buf.append(',');
6104            }
6105            buf.append(name);
6106        }
6107    }
6108
6109    static List<Cube> sortedCubes(Schema schema) {
6110        final Cube[] cubes = schema.getCubes();
6111        List<Cube> cubeList = sortArray(
6112            cubes,
6113            new Comparator<Cube>() {
6114                public int compare(Cube o1, Cube o2) {
6115                    return o1.getName().compareTo(o2.getName());
6116                }
6117            }
6118        );
6119        return cubeList;
6120    }
6121}
6122
6123// End RowsetDefinition.java
6124
Popular Tags