001 /* 002 // $Id: //open/mondrian/src/main/mondrian/xmla/RowsetDefinition.java#62 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2003-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.xmla; 011 012 import mondrian.olap.*; 013 import mondrian.olap.fun.FunInfo; 014 import mondrian.rolap.RolapCube; 015 import mondrian.rolap.RolapLevel; 016 import mondrian.rolap.RolapSchema; 017 import mondrian.rolap.RolapAggregator; 018 import mondrian.rolap.RolapMember; 019 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Method; 022 import java.lang.reflect.InvocationTargetException; 023 import java.util.*; 024 import java.text.SimpleDateFormat; 025 import java.text.Format; 026 027 /** 028 * <code>RowsetDefinition</code> defines a rowset, including the columns it 029 * should contain. 030 * 031 * <p>See "XML for Analysis Rowsets", page 38 of the XML for Analysis 032 * Specification, version 1.1. 033 * 034 * @author jhyde 035 * @version $Id: //open/mondrian/src/main/mondrian/xmla/RowsetDefinition.java#62 $ 036 */ 037 enum RowsetDefinition { 038 /** 039 * Returns a list of XML for Analysis data sources 040 * available on the server or Web Service. (For an 041 * example of how these may be published, see 042 * "XML for Analysis Implementation Walkthrough" 043 * in the XML for Analysis specification.) 044 * 045 * http://msdn2.microsoft.com/en-us/library/ms126129(SQL.90).aspx 046 * 047 * 048 * restrictions 049 * 050 * Not supported 051 */ 052 DISCOVER_DATASOURCES( 053 0, 054 "Returns a list of XML for Analysis data sources available on the server or Web Service.", 055 new Column[] { 056 DiscoverDatasourcesRowset.DataSourceName, 057 DiscoverDatasourcesRowset.DataSourceDescription, 058 DiscoverDatasourcesRowset.URL, 059 DiscoverDatasourcesRowset.DataSourceInfo, 060 DiscoverDatasourcesRowset.ProviderName, 061 DiscoverDatasourcesRowset.ProviderType, 062 DiscoverDatasourcesRowset.AuthenticationMode, 063 }, 064 null /* not sorted */) { 065 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 066 return new DiscoverDatasourcesRowset(request, handler); 067 } 068 }, 069 070 /** 071 * Note that SQL Server also returns the data-mining columns. 072 * 073 * 074 * restrictions 075 * 076 * Not supported 077 */ 078 DISCOVER_SCHEMA_ROWSETS( 079 2, 080 "Returns the names, values, and other information of all supported RequestType enumeration values.", 081 new Column[] { 082 DiscoverSchemaRowsetsRowset.SchemaName, 083 DiscoverSchemaRowsetsRowset.SchemaGuid, 084 DiscoverSchemaRowsetsRowset.Restrictions, 085 DiscoverSchemaRowsetsRowset.Description, 086 }, 087 null /* not sorted */) { 088 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 089 return new DiscoverSchemaRowsetsRowset(request, handler); 090 } 091 protected void writeRowsetXmlSchemaRowDef(SaxWriter writer) { 092 writer.startElement("xsd:complexType", new String[] { 093 "name", "row" 094 }); 095 writer.startElement("xsd:sequence"); 096 for (Column column : columnDefinitions) { 097 final String name = XmlaUtil.encodeElementName(column.name); 098 099 if (column == DiscoverSchemaRowsetsRowset.Restrictions) { 100 writer.startElement("xsd:element", new String[]{ 101 "sql:field", column.name, 102 "name", name, 103 "minOccurs", "0", 104 "maxOccurs", "unbounded" 105 }); 106 writer.startElement("xsd:complexType"); 107 writer.startElement("xsd:sequence"); 108 writer.element("xsd:element", new String[]{ 109 "name", "Name", 110 "type", "xsd:string", 111 "sql:field", "Name" 112 }); 113 writer.element("xsd:element", new String[]{ 114 "name", "Type", 115 "type", "xsd:string", 116 "sql:field", "Type" 117 }); 118 119 writer.endElement(); // xsd:sequence 120 writer.endElement(); // xsd:complexType 121 writer.endElement(); // xsd:element 122 123 } else { 124 final String xsdType = column.type.columnType; 125 126 String[] attrs; 127 if (column.nullable) { 128 if (column.unbounded) { 129 attrs = new String[]{ 130 "sql:field", column.name, 131 "name", name, 132 "type", xsdType, 133 "minOccurs", "0", 134 "maxOccurs", "unbounded" 135 }; 136 } else { 137 attrs = new String[]{ 138 "sql:field", column.name, 139 "name", name, 140 "type", xsdType, 141 "minOccurs", "0" 142 }; 143 } 144 } else { 145 if (column.unbounded) { 146 attrs = new String[]{ 147 "sql:field", column.name, 148 "name", name, 149 "type", xsdType, 150 "maxOccurs", "unbounded" 151 }; 152 } else { 153 attrs = new String[]{ 154 "sql:field", column.name, 155 "name", name, 156 "type", xsdType 157 }; 158 } 159 } 160 writer.element("xsd:element", attrs); 161 } 162 } 163 writer.endElement(); // xsd:sequence 164 writer.endElement(); // xsd:complexType 165 } 166 }, 167 168 /** 169 * 170 * 171 * 172 * restrictions 173 * 174 * Not supported 175 */ 176 DISCOVER_ENUMERATORS( 177 3, 178 "Returns a list of names, data types, and enumeration values for enumerators supported by the provider of a specific data source.", 179 new Column[] { 180 DiscoverEnumeratorsRowset.EnumName, 181 DiscoverEnumeratorsRowset.EnumDescription, 182 DiscoverEnumeratorsRowset.EnumType, 183 DiscoverEnumeratorsRowset.ElementName, 184 DiscoverEnumeratorsRowset.ElementDescription, 185 DiscoverEnumeratorsRowset.ElementValue, 186 }, 187 null /* not sorted */) { 188 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 189 return new DiscoverEnumeratorsRowset(request, handler); 190 } 191 }, 192 193 /** 194 * 195 * 196 * 197 * restrictions 198 * 199 * Not supported 200 */ 201 DISCOVER_PROPERTIES( 202 1, 203 "Returns a list of information and values about the requested properties that are supported by the specified data source provider.", 204 new Column[] { 205 DiscoverPropertiesRowset.PropertyName, 206 DiscoverPropertiesRowset.PropertyDescription, 207 DiscoverPropertiesRowset.PropertyType, 208 DiscoverPropertiesRowset.PropertyAccessType, 209 DiscoverPropertiesRowset.IsRequired, 210 DiscoverPropertiesRowset.Value, 211 }, 212 null /* not sorted */) { 213 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 214 return new DiscoverPropertiesRowset(request, handler); 215 } 216 }, 217 218 /** 219 * 220 * 221 * 222 * restrictions 223 * 224 * Not supported 225 */ 226 DISCOVER_KEYWORDS( 227 4, 228 "Returns an XML list of keywords reserved by the provider.", 229 new Column[] { 230 DiscoverKeywordsRowset.Keyword, 231 }, 232 null /* not sorted */) { 233 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 234 return new DiscoverKeywordsRowset(request, handler); 235 } 236 }, 237 238 /** 239 * 240 * 241 * 242 * restrictions 243 * 244 * Not supported 245 */ 246 DISCOVER_LITERALS( 247 5, 248 "Returns information about literals supported by the provider.", 249 new Column[] { 250 DiscoverLiteralsRowset.LiteralName, 251 DiscoverLiteralsRowset.LiteralValue, 252 DiscoverLiteralsRowset.LiteralInvalidChars, 253 DiscoverLiteralsRowset.LiteralInvalidStartingChars, 254 DiscoverLiteralsRowset.LiteralMaxLength, 255 }, 256 null /* not sorted */) { 257 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 258 return new DiscoverLiteralsRowset(request, handler); 259 } 260 }, 261 262 /** 263 * 264 * 265 * 266 * restrictions 267 * 268 * Not supported 269 */ 270 DBSCHEMA_CATALOGS( 271 6, 272 "Returns information about literals supported by the provider.", 273 new Column[] { 274 DbschemaCatalogsRowset.CatalogName, 275 DbschemaCatalogsRowset.Description, 276 DbschemaCatalogsRowset.Roles, 277 DbschemaCatalogsRowset.DateModified, 278 }, 279 new Column[] { 280 DbschemaCatalogsRowset.CatalogName, 281 }) { 282 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 283 return new DbschemaCatalogsRowset(request, handler); 284 } 285 }, 286 287 /** 288 * 289 * 290 * 291 * restrictions 292 * 293 * Not supported 294 * COLUMN_OLAP_TYPE 295 */ 296 DBSCHEMA_COLUMNS( 297 7, null, 298 new Column[] { 299 DbschemaColumnsRowset.TableCatalog, 300 DbschemaColumnsRowset.TableSchema, 301 DbschemaColumnsRowset.TableName, 302 DbschemaColumnsRowset.ColumnName, 303 DbschemaColumnsRowset.OrdinalPosition, 304 DbschemaColumnsRowset.ColumnHasDefault, 305 DbschemaColumnsRowset.ColumnFlags, 306 DbschemaColumnsRowset.IsNullable, 307 DbschemaColumnsRowset.DataType, 308 DbschemaColumnsRowset.CharacterMaximumLength, 309 DbschemaColumnsRowset.CharacterOctetLength, 310 DbschemaColumnsRowset.NumericPrecision, 311 DbschemaColumnsRowset.NumericScale, 312 }, 313 new Column[] { 314 DbschemaColumnsRowset.TableCatalog, 315 DbschemaColumnsRowset.TableSchema, 316 DbschemaColumnsRowset.TableName, 317 }) { 318 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 319 return new DbschemaColumnsRowset(request, handler); 320 } 321 }, 322 323 /** 324 * 325 * 326 * 327 * restrictions 328 * 329 * Not supported 330 */ 331 DBSCHEMA_PROVIDER_TYPES( 332 8, null, 333 new Column[] { 334 DbschemaProviderTypesRowset.TypeName, 335 DbschemaProviderTypesRowset.DataType, 336 DbschemaProviderTypesRowset.ColumnSize, 337 DbschemaProviderTypesRowset.LiteralPrefix, 338 DbschemaProviderTypesRowset.LiteralSuffix, 339 DbschemaProviderTypesRowset.IsNullable, 340 DbschemaProviderTypesRowset.CaseSensitive, 341 DbschemaProviderTypesRowset.Searchable, 342 DbschemaProviderTypesRowset.UnsignedAttribute, 343 DbschemaProviderTypesRowset.FixedPrecScale, 344 DbschemaProviderTypesRowset.AutoUniqueValue, 345 DbschemaProviderTypesRowset.IsLong, 346 DbschemaProviderTypesRowset.BestMatch, 347 }, 348 new Column[] { 349 DbschemaProviderTypesRowset.DataType, 350 }) { 351 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 352 return new DbschemaProviderTypesRowset(request, handler); 353 } 354 }, 355 356 DBSCHEMA_SCHEMATA( 357 8, null, 358 new Column[] { 359 DbschemaSchemataRowset.CatalogName, 360 DbschemaSchemataRowset.SchemaName, 361 DbschemaSchemataRowset.SchemaOwner, 362 }, 363 new Column[] { 364 DbschemaSchemataRowset.CatalogName, 365 DbschemaSchemataRowset.SchemaName, 366 DbschemaSchemataRowset.SchemaOwner, 367 }) { 368 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 369 return new DbschemaSchemataRowset(request, handler); 370 } 371 }, 372 373 /** 374 * http://msdn2.microsoft.com/en-us/library/ms126299(SQL.90).aspx 375 * 376 * restrictions: 377 * TABLE_CATALOG Optional 378 * TABLE_SCHEMA Optional 379 * TABLE_NAME Optional 380 * TABLE_TYPE Optional 381 * TABLE_OLAP_TYPE Optional 382 * 383 * Not supported 384 */ 385 DBSCHEMA_TABLES( 386 9, null, 387 new Column[] { 388 DbschemaTablesRowset.TableCatalog, 389 DbschemaTablesRowset.TableSchema, 390 DbschemaTablesRowset.TableName, 391 DbschemaTablesRowset.TableType, 392 DbschemaTablesRowset.TableGuid, 393 DbschemaTablesRowset.Description, 394 DbschemaTablesRowset.TablePropId, 395 DbschemaTablesRowset.DateCreated, 396 DbschemaTablesRowset.DateModified, 397 //TableOlapType, 398 }, 399 new Column[] { 400 DbschemaTablesRowset.TableType, 401 DbschemaTablesRowset.TableCatalog, 402 DbschemaTablesRowset.TableSchema, 403 DbschemaTablesRowset.TableName, 404 }) { 405 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 406 return new DbschemaTablesRowset(request, handler); 407 } 408 }, 409 410 /** 411 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtables_info_rowset.asp 412 * 413 * 414 * restrictions 415 * 416 * Not supported 417 */ 418 DBSCHEMA_TABLES_INFO( 419 10, null, 420 new Column[] { 421 DbschemaTablesInfoRowset.TableCatalog, 422 DbschemaTablesInfoRowset.TableSchema, 423 DbschemaTablesInfoRowset.TableName, 424 DbschemaTablesInfoRowset.TableType, 425 DbschemaTablesInfoRowset.TableGuid, 426 DbschemaTablesInfoRowset.Bookmarks, 427 DbschemaTablesInfoRowset.BookmarkType, 428 DbschemaTablesInfoRowset.BookmarkDataType, 429 DbschemaTablesInfoRowset.BookmarkMaximumLength, 430 DbschemaTablesInfoRowset.BookmarkInformation, 431 DbschemaTablesInfoRowset.TableVersion, 432 DbschemaTablesInfoRowset.Cardinality, 433 DbschemaTablesInfoRowset.Description, 434 DbschemaTablesInfoRowset.TablePropId, 435 }, 436 null /* cannot find doc -- presume unsorted */) { 437 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 438 return new DbschemaTablesInfoRowset(request, handler); 439 } 440 }, 441 442 /** 443 * http://msdn2.microsoft.com/en-us/library/ms126032(SQL.90).aspx 444 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapactions_rowset.asp 445 * 446 * restrictions 447 * CATALOG_NAME Optional 448 * SCHEMA_NAME Optional 449 * CUBE_NAME Mandatory 450 * ACTION_NAME Optional 451 * ACTION_TYPE Optional 452 * COORDINATE Mandatory 453 * COORDINATE_TYPE Mandatory 454 * INVOCATION 455 * (Optional) The INVOCATION restriction column defaults to the 456 * value of MDACTION_INVOCATION_INTERACTIVE. To retrieve all 457 * actions, use the MDACTION_INVOCATION_ALL value in the 458 * INVOCATION restriction column. 459 * CUBE_SOURCE 460 * (Optional) A bitmap with one of the following valid values: 461 * 462 * 1 CUBE 463 * 2 DIMENSION 464 * 465 * Default restriction is a value of 1. 466 * 467 * Not supported 468 */ 469 MDSCHEMA_ACTIONS( 470 11, null, new Column[] { 471 MdschemaActionsRowset.SchemaName, 472 MdschemaActionsRowset.CubeName, 473 MdschemaActionsRowset.ActionName, 474 MdschemaActionsRowset.Coordinate, 475 MdschemaActionsRowset.CoordinateType, 476 }, new Column[] { 477 // Spec says sort on CATALOG_NAME, SCHEMA_NAME, CUBE_NAME, 478 // ACTION_NAME. 479 MdschemaActionsRowset.SchemaName, 480 MdschemaActionsRowset.CubeName, 481 MdschemaActionsRowset.ActionName, 482 }) { 483 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 484 return new MdschemaActionsRowset(request, handler); 485 } 486 }, 487 488 /** 489 * http://msdn2.microsoft.com/en-us/library/ms126271(SQL.90).aspx 490 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp 491 * 492 * restrictions 493 * CATALOG_NAME Optional. 494 * SCHEMA_NAME Optional. 495 * CUBE_NAME Optional. 496 * CUBE_TYPE 497 * (Optional) A bitmap with one of these valid values: 498 * 1 CUBE 499 * 2 DIMENSION 500 * Default restriction is a value of 1. 501 * BASE_CUBE_NAME Optional. 502 * 503 * Not supported 504 * CREATED_ON 505 * LAST_SCHEMA_UPDATE 506 * SCHEMA_UPDATED_BY 507 * LAST_DATA_UPDATE 508 * DATA_UPDATED_BY 509 * ANNOTATIONS 510 */ 511 MDSCHEMA_CUBES( 512 12, null, 513 new Column[] { 514 MdschemaCubesRowset.CatalogName, 515 MdschemaCubesRowset.SchemaName, 516 MdschemaCubesRowset.CubeName, 517 MdschemaCubesRowset.CubeType, 518 MdschemaCubesRowset.CubeGuid, 519 MdschemaCubesRowset.CreatedOn, 520 MdschemaCubesRowset.LastSchemaUpdate, 521 MdschemaCubesRowset.SchemaUpdatedBy, 522 MdschemaCubesRowset.LastDataUpdate, 523 MdschemaCubesRowset.DataUpdatedBy, 524 MdschemaCubesRowset.IsDrillthroughEnabled, 525 MdschemaCubesRowset.IsWriteEnabled, 526 MdschemaCubesRowset.IsLinkable, 527 MdschemaCubesRowset.IsSqlEnabled, 528 MdschemaCubesRowset.Description 529 }, 530 new Column[] { 531 MdschemaCubesRowset.CatalogName, 532 MdschemaCubesRowset.SchemaName, 533 MdschemaCubesRowset.CubeName, 534 }) { 535 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 536 return new MdschemaCubesRowset(request, handler); 537 } 538 }, 539 540 /** 541 * http://msdn2.microsoft.com/en-us/library/ms126180(SQL.90).aspx 542 * http://msdn2.microsoft.com/en-us/library/ms126180.aspx 543 * 544 * restrictions 545 * CATALOG_NAME Optional. 546 * SCHEMA_NAME Optional. 547 * CUBE_NAME Optional. 548 * DIMENSION_NAME Optional. 549 * DIMENSION_UNIQUE_NAME Optional. 550 * CUBE_SOURCE (Optional) A bitmap with one of the following valid values: 551 * 1 CUBE 552 * 2 DIMENSION 553 * Default restriction is a value of 1. 554 * 555 * DIMENSION_VISIBILITY (Optional) A bitmap with one of the following valid values: 556 * 1 Visible 557 * 2 Not visible 558 * Default restriction is a value of 1. 559 */ 560 MDSCHEMA_DIMENSIONS( 561 13, null, 562 new Column[] { 563 MdschemaDimensionsRowset.CatalogName, 564 MdschemaDimensionsRowset.SchemaName, 565 MdschemaDimensionsRowset.CubeName, 566 MdschemaDimensionsRowset.DimensionName, 567 MdschemaDimensionsRowset.DimensionUniqueName, 568 MdschemaDimensionsRowset.DimensionGuid, 569 MdschemaDimensionsRowset.DimensionCaption, 570 MdschemaDimensionsRowset.DimensionOrdinal, 571 MdschemaDimensionsRowset.DimensionType, 572 MdschemaDimensionsRowset.DimensionCardinality, 573 MdschemaDimensionsRowset.DefaultHierarchy, 574 MdschemaDimensionsRowset.Description, 575 MdschemaDimensionsRowset.IsVirtual, 576 MdschemaDimensionsRowset.IsReadWrite, 577 MdschemaDimensionsRowset.DimensionUniqueSettings, 578 MdschemaDimensionsRowset.DimensionMasterUniqueName, 579 MdschemaDimensionsRowset.DimensionIsVisible, 580 }, 581 new Column[] { 582 MdschemaDimensionsRowset.CatalogName, 583 MdschemaDimensionsRowset.SchemaName, 584 MdschemaDimensionsRowset.CubeName, 585 MdschemaDimensionsRowset.DimensionName, 586 }) { 587 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 588 return new MdschemaDimensionsRowset(request, handler); 589 } 590 }, 591 592 /** 593 * http://msdn2.microsoft.com/en-us/library/ms126257(SQL.90).aspx 594 * http://msdn.microsoft.com/library/en-us/oledb/htm/olapfunctions_rowset.asp 595 * 596 * restrictions 597 * LIBRARY_NAME Optional. 598 * INTERFACE_NAME Optional. 599 * FUNCTION_NAME Optional. 600 * ORIGIN Optional. 601 * 602 * Not supported 603 * DLL_NAME 604 * Optional 605 * HELP_FILE 606 * Optional 607 * HELP_CONTEXT 608 * Optional 609 * - SQL Server xml schema says that this must be present 610 * OBJECT 611 * Optional 612 * CAPTION The display caption for the function. 613 */ 614 MDSCHEMA_FUNCTIONS( 615 14, null, 616 new Column[] { 617 MdschemaFunctionsRowset.FunctionName, 618 MdschemaFunctionsRowset.Description, 619 MdschemaFunctionsRowset.ParameterList, 620 MdschemaFunctionsRowset.ReturnType, 621 MdschemaFunctionsRowset.Origin, 622 MdschemaFunctionsRowset.InterfaceName, 623 MdschemaFunctionsRowset.LibraryName, 624 MdschemaFunctionsRowset.Caption, 625 }, 626 new Column[] { 627 MdschemaFunctionsRowset.LibraryName, 628 MdschemaFunctionsRowset.InterfaceName, 629 MdschemaFunctionsRowset.FunctionName, 630 MdschemaFunctionsRowset.Origin, 631 }) { 632 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 633 return new MdschemaFunctionsRowset(request, handler); 634 } 635 }, 636 637 /** 638 * http://msdn2.microsoft.com/en-us/library/ms126062(SQL.90).aspx 639 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp 640 * 641 * restrictions 642 * CATALOG_NAME Optional. 643 * SCHEMA_NAME Optional. 644 * CUBE_NAME Optional. 645 * DIMENSION_UNIQUE_NAME Optional. 646 * HIERARCHY_NAME Optional. 647 * HIERARCHY_UNIQUE_NAME Optional. 648 * HIERARCHY_ORIGIN 649 * (Optional) A default restriction is in effect 650 * on MD_USER_DEFINED and MD_SYSTEM_ENABLED. 651 * CUBE_SOURCE 652 * (Optional) A bitmap with one of the following valid values: 653 * 1 CUBE 654 * 2 DIMENSION 655 * Default restriction is a value of 1. 656 * HIERARCHY_VISIBILITY 657 * (Optional) A bitmap with one of the following valid values: 658 * 1 Visible 659 * 2 Not visible 660 * Default restriction is a value of 1. 661 * 662 * Not supported 663 * HIERARCHY_IS_VISIBLE 664 * HIERARCHY_ORIGIN 665 * HIERARCHY_DISPLAY_FOLDER 666 * INSTANCE_SELECTION 667 */ 668 MDSCHEMA_HIERARCHIES( 669 15, null, 670 new Column[] { 671 MdschemaHierarchiesRowset.CatalogName, 672 MdschemaHierarchiesRowset.SchemaName, 673 MdschemaHierarchiesRowset.CubeName, 674 MdschemaHierarchiesRowset.DimensionUniqueName, 675 MdschemaHierarchiesRowset.HierarchyName, 676 MdschemaHierarchiesRowset.HierarchyUniqueName, 677 MdschemaHierarchiesRowset.HierarchyGuid, 678 MdschemaHierarchiesRowset.HierarchyCaption, 679 MdschemaHierarchiesRowset.DimensionType, 680 MdschemaHierarchiesRowset.HierarchyCardinality, 681 MdschemaHierarchiesRowset.DefaultMember, 682 MdschemaHierarchiesRowset.AllMember, 683 MdschemaHierarchiesRowset.Description, 684 MdschemaHierarchiesRowset.Structure, 685 MdschemaHierarchiesRowset.IsVirtual, 686 MdschemaHierarchiesRowset.IsReadWrite, 687 MdschemaHierarchiesRowset.DimensionUniqueSettings, 688 MdschemaHierarchiesRowset.DimensionIsVisible, 689 MdschemaHierarchiesRowset.HierarchyOrdinal, 690 MdschemaHierarchiesRowset.DimensionIsShared, 691 MdschemaHierarchiesRowset.ParentChild, 692 }, 693 new Column[] { 694 MdschemaHierarchiesRowset.CatalogName, 695 MdschemaHierarchiesRowset.SchemaName, 696 MdschemaHierarchiesRowset.CubeName, 697 MdschemaHierarchiesRowset.DimensionUniqueName, 698 MdschemaHierarchiesRowset.HierarchyName, 699 }) { 700 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 701 return new MdschemaHierarchiesRowset(request, handler); 702 } 703 }, 704 705 /** 706 * http://msdn2.microsoft.com/en-us/library/ms126038(SQL.90).aspx 707 * http://msdn.microsoft.com/library/en-us/oledb/htm/olaplevels_rowset.asp 708 * 709 * restriction 710 * CATALOG_NAME Optional. 711 * SCHEMA_NAME Optional. 712 * CUBE_NAME Optional. 713 * DIMENSION_UNIQUE_NAME Optional. 714 * HIERARCHY_UNIQUE_NAME Optional. 715 * LEVEL_NAME Optional. 716 * LEVEL_UNIQUE_NAME Optional. 717 * LEVEL_ORIGIN 718 * (Optional) A default restriction is in effect 719 * on MD_USER_DEFINED and MD_SYSTEM_ENABLED 720 * CUBE_SOURCE 721 * (Optional) A bitmap with one of the following valid values: 722 * 1 CUBE 723 * 2 DIMENSION 724 * Default restriction is a value of 1. 725 * LEVEL_VISIBILITY 726 * (Optional) A bitmap with one of the following values: 727 * 1 Visible 728 * 2 Not visible 729 * Default restriction is a value of 1. 730 * 731 * Not supported 732 * CUSTOM_ROLLUP_SETTINGS 733 * LEVEL_UNIQUE_SETTINGS 734 * LEVEL_ORDERING_PROPERTY 735 * LEVEL_DBTYPE 736 * LEVEL_MASTER_UNIQUE_NAME 737 * LEVEL_NAME_SQL_COLUMN_NAME Customers:(All)!NAME 738 * LEVEL_KEY_SQL_COLUMN_NAME Customers:(All)!KEY 739 * LEVEL_UNIQUE_NAME_SQL_COLUMN_NAME Customers:(All)!UNIQUE_NAME 740 * LEVEL_ATTRIBUTE_HIERARCHY_NAME 741 * LEVEL_KEY_CARDINALITY 742 * LEVEL_ORIGIN 743 * 744 */ 745 MDSCHEMA_LEVELS( 746 16, null, 747 new Column[] { 748 MdschemaLevelsRowset.CatalogName, 749 MdschemaLevelsRowset.SchemaName, 750 MdschemaLevelsRowset.CubeName, 751 MdschemaLevelsRowset.DimensionUniqueName, 752 MdschemaLevelsRowset.HierarchyUniqueName, 753 MdschemaLevelsRowset.LevelName, 754 MdschemaLevelsRowset.LevelUniqueName, 755 MdschemaLevelsRowset.LevelGuid, 756 MdschemaLevelsRowset.LevelCaption, 757 MdschemaLevelsRowset.LevelNumber, 758 MdschemaLevelsRowset.LevelCardinality, 759 MdschemaLevelsRowset.LevelType, 760 MdschemaLevelsRowset.CustomRollupSettings, 761 MdschemaLevelsRowset.LevelUniqueSettings, 762 MdschemaLevelsRowset.LevelIsVisible, 763 MdschemaLevelsRowset.Description, 764 }, 765 new Column[] { 766 MdschemaLevelsRowset.CatalogName, 767 MdschemaLevelsRowset.SchemaName, 768 MdschemaLevelsRowset.CubeName, 769 MdschemaLevelsRowset.DimensionUniqueName, 770 MdschemaLevelsRowset.HierarchyUniqueName, 771 MdschemaLevelsRowset.LevelNumber, 772 }) { 773 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 774 return new MdschemaLevelsRowset(request, handler); 775 } 776 }, 777 778 /** 779 * http://msdn2.microsoft.com/en-us/library/ms126250(SQL.90).aspx 780 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapmeasures_rowset.asp 781 * 782 * restrictions 783 * CATALOG_NAME Optional. 784 * SCHEMA_NAME Optional. 785 * CUBE_NAME Optional. 786 * MEASURE_NAME Optional. 787 * MEASURE_UNIQUE_NAME Optional. 788 * CUBE_SOURCE 789 * (Optional) A bitmap with one of the following valid values: 790 * 1 CUBE 791 * 2 DIMENSION 792 * Default restriction is a value of 1. 793 * MEASURE_VISIBILITY 794 * (Optional) A bitmap with one of the following valid values: 795 * 1 Visible 796 * 2 Not Visible 797 * Default restriction is a value of 1. 798 * 799 * Not supported 800 * MEASURE_GUID 801 * NUMERIC_PRECISION 802 * NUMERIC_SCALE 803 * MEASURE_UNITS 804 * EXPRESSION 805 * MEASURE_NAME_SQL_COLUMN_NAME 806 * MEASURE_UNQUALIFIED_CAPTION 807 * MEASUREGROUP_NAME 808 * MEASURE_DISPLAY_FOLDER 809 * DEFAULT_FORMAT_STRING 810 */ 811 MDSCHEMA_MEASURES( 812 17, null, 813 new Column[] { 814 MdschemaMeasuresRowset.CatalogName, 815 MdschemaMeasuresRowset.SchemaName, 816 MdschemaMeasuresRowset.CubeName, 817 MdschemaMeasuresRowset.MeasureName, 818 MdschemaMeasuresRowset.MeasureUniqueName, 819 MdschemaMeasuresRowset.MeasureCaption, 820 MdschemaMeasuresRowset.MeasureGuid, 821 MdschemaMeasuresRowset.MeasureAggregator, 822 MdschemaMeasuresRowset.DataType, 823 MdschemaMeasuresRowset.MeasureIsVisible, 824 MdschemaMeasuresRowset.LevelsList, 825 MdschemaMeasuresRowset.Description, 826 }, 827 new Column[] { 828 MdschemaMeasuresRowset.CatalogName, 829 MdschemaMeasuresRowset.SchemaName, 830 MdschemaMeasuresRowset.CubeName, 831 MdschemaMeasuresRowset.MeasureName, 832 }) { 833 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 834 return new MdschemaMeasuresRowset(request, handler); 835 } 836 }, 837 838 /** 839 * 840 * http://msdn2.microsoft.com/es-es/library/ms126046.aspx 841 * 842 * 843 * restrictions 844 * CATALOG_NAME Optional. 845 * SCHEMA_NAME Optional. 846 * CUBE_NAME Optional. 847 * DIMENSION_UNIQUE_NAME Optional. 848 * HIERARCHY_UNIQUE_NAME Optional. 849 * LEVEL_UNIQUE_NAME Optional. 850 * LEVEL_NUMBER Optional. 851 * MEMBER_NAME Optional. 852 * MEMBER_UNIQUE_NAME Optional. 853 * MEMBER_CAPTION Optional. 854 * MEMBER_TYPE Optional. 855 * TREE_OP (Optional) Only applies to a single member: 856 * MDTREEOP_ANCESTORS (0x20) returns all of the ancestors. 857 * MDTREEOP_CHILDREN (0x01) returns only the immediate children. 858 * MDTREEOP_SIBLINGS (0x02) returns members on the same level. 859 * MDTREEOP_PARENT (0x04) returns only the immediate parent. 860 * MDTREEOP_SELF (0x08) returns itself in the list of 861 * returned rows. 862 * MDTREEOP_DESCENDANTS (0x10) returns all of the descendants. 863 * CUBE_SOURCE (Optional) A bitmap with one of the 864 * following valid values: 865 * 1 CUBE 866 * 2 DIMENSION 867 * Default restriction is a value of 1. 868 * 869 * Not supported 870 */ 871 MDSCHEMA_MEMBERS( 872 18, null, 873 new Column[] { 874 MdschemaMembersRowset.CatalogName, 875 MdschemaMembersRowset.SchemaName, 876 MdschemaMembersRowset.CubeName, 877 MdschemaMembersRowset.DimensionUniqueName, 878 MdschemaMembersRowset.HierarchyUniqueName, 879 MdschemaMembersRowset.LevelUniqueName, 880 MdschemaMembersRowset.LevelNumber, 881 MdschemaMembersRowset.MemberOrdinal, 882 MdschemaMembersRowset.MemberName, 883 MdschemaMembersRowset.MemberUniqueName, 884 MdschemaMembersRowset.MemberType, 885 MdschemaMembersRowset.MemberGuid, 886 MdschemaMembersRowset.MemberCaption, 887 MdschemaMembersRowset.ChildrenCardinality, 888 MdschemaMembersRowset.ParentLevel, 889 MdschemaMembersRowset.ParentUniqueName, 890 MdschemaMembersRowset.ParentCount, 891 MdschemaMembersRowset.TreeOp, 892 MdschemaMembersRowset.Depth, 893 }, 894 new Column[] { 895 MdschemaMembersRowset.CatalogName, 896 MdschemaMembersRowset.SchemaName, 897 MdschemaMembersRowset.CubeName, 898 MdschemaMembersRowset.DimensionUniqueName, 899 MdschemaMembersRowset.HierarchyUniqueName, 900 MdschemaMembersRowset.LevelUniqueName, 901 MdschemaMembersRowset.LevelNumber, 902 MdschemaMembersRowset.MemberOrdinal, 903 }) { 904 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 905 return new MdschemaMembersRowset(request, handler); 906 } 907 }, 908 909 /** 910 * http://msdn2.microsoft.com/en-us/library/ms126309(SQL.90).aspx 911 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp 912 * 913 * restrictions 914 * CATALOG_NAME Mandatory 915 * SCHEMA_NAME Optional 916 * CUBE_NAME Optional 917 * DIMENSION_UNIQUE_NAME Optional 918 * HIERARCHY_UNIQUE_NAME Optional 919 * LEVEL_UNIQUE_NAME Optional 920 * 921 * MEMBER_UNIQUE_NAME Optional 922 * PROPERTY_NAME Optional 923 * PROPERTY_TYPE Optional 924 * PROPERTY_CONTENT_TYPE 925 * (Optional) A default restriction is in place on MDPROP_MEMBER 926 * OR MDPROP_CELL. 927 * PROPERTY_ORIGIN 928 * (Optional) A default restriction is in place on MD_USER_DEFINED 929 * OR MD_SYSTEM_ENABLED 930 * CUBE_SOURCE 931 * (Optional) A bitmap with one of the following valid values: 932 * 1 CUBE 933 * 2 DIMENSION 934 * Default restriction is a value of 1. 935 * PROPERTY_VISIBILITY 936 * (Optional) A bitmap with one of the following valid values: 937 * 1 Visible 938 * 2 Not visible 939 * Default restriction is a value of 1. 940 * 941 * Not supported 942 * PROPERTY_ORIGIN 943 * CUBE_SOURCE 944 * PROPERTY_VISIBILITY 945 * CHARACTER_MAXIMUM_LENGTH 946 * CHARACTER_OCTET_LENGTH 947 * NUMERIC_PRECISION 948 * NUMERIC_SCALE 949 * DESCRIPTION 950 * SQL_COLUMN_NAME 951 * LANGUAGE 952 * PROPERTY_ATTRIBUTE_HIERARCHY_NAME 953 * PROPERTY_CARDINALITY 954 * MIME_TYPE 955 * PROPERTY_IS_VISIBLE 956 */ 957 MDSCHEMA_PROPERTIES( 958 19, null, 959 new Column[] { 960 MdschemaPropertiesRowset.CatalogName, 961 MdschemaPropertiesRowset.SchemaName, 962 MdschemaPropertiesRowset.CubeName, 963 MdschemaPropertiesRowset.DimensionUniqueName, 964 MdschemaPropertiesRowset.HierarchyUniqueName, 965 MdschemaPropertiesRowset.LevelUniqueName, 966 MdschemaPropertiesRowset.MemberUniqueName, 967 MdschemaPropertiesRowset.PropertyName, 968 MdschemaPropertiesRowset.PropertyCaption, 969 MdschemaPropertiesRowset.PropertyType, 970 MdschemaPropertiesRowset.DataType, 971 MdschemaPropertiesRowset.PropertyContentType, 972 MdschemaPropertiesRowset.Description 973 }, 974 null /* not sorted */) { 975 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 976 return new MdschemaPropertiesRowset(request, handler); 977 } 978 }, 979 980 /** 981 * http://msdn2.microsoft.com/en-us/library/ms126290(SQL.90).aspx 982 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/olapproperties_rowset.asp 983 * 984 * restrictions 985 * CATALOG_NAME Optional. 986 * SCHEMA_NAME Optional. 987 * CUBE_NAME Optional. 988 * SET_NAME Optional. 989 * SCOPE Optional. 990 * HIERARCHY_UNIQUE_NAME Optional. 991 * CUBE_SOURCE Optional. 992 * Note: Only one hierarchy can be included, and only those named 993 * sets whose hierarchies exactly match the restriction are 994 * returned. 995 * 996 * Not supported 997 * EXPRESSION 998 * DIMENSIONS 999 * SET_DISPLAY_FOLDER 1000 */ 1001 MDSCHEMA_SETS( 1002 20, null, 1003 new Column[] { 1004 MdschemaSetsRowset.CatalogName, 1005 MdschemaSetsRowset.SchemaName, 1006 MdschemaSetsRowset.CubeName, 1007 MdschemaSetsRowset.SetName, 1008 MdschemaSetsRowset.Scope, 1009 }, 1010 new Column[] { 1011 MdschemaSetsRowset.CatalogName, 1012 MdschemaSetsRowset.SchemaName, 1013 MdschemaSetsRowset.CubeName, 1014 }) { 1015 public Rowset getRowset(XmlaRequest request, XmlaHandler handler) { 1016 return new MdschemaSetsRowset(request, handler); 1017 } 1018 }; 1019 1020 private static final boolean EMIT_INVISIBLE_MEMBERS = true; 1021 1022 transient final Column[] columnDefinitions; 1023 transient final Column[] sortColumnDefinitions; 1024 1025 /** 1026 * Date the schema was last modified. 1027 * 1028 * <p>TODO: currently schema grammar does not support modify date 1029 * so we return just some date for now. 1030 */ 1031 private static final String dateModified = "2005-01-25T17:35:32"; 1032 private final String description; 1033 1034 /** 1035 * Creates a rowset definition. 1036 * 1037 * @param ordinal Rowset ordinal, per OLE DB for OLAP 1038 * @param description Description 1039 * @param columnDefinitions List of column definitions 1040 * @param sortColumnDefinitions List of column definitions to sort on, 1041 */ 1042 RowsetDefinition( 1043 int ordinal, 1044 String description, 1045 Column[] columnDefinitions, 1046 Column[] sortColumnDefinitions) 1047 { 1048 Util.discard(ordinal); 1049 this.description = description; 1050 this.columnDefinitions = columnDefinitions; 1051 this.sortColumnDefinitions = sortColumnDefinitions; 1052 } 1053 1054 public abstract Rowset getRowset(XmlaRequest request, XmlaHandler handler); 1055 1056 public Column lookupColumn(String name) { 1057 for (Column columnDefinition : columnDefinitions) { 1058 if (columnDefinition.name.equals(name)) { 1059 return columnDefinition; 1060 } 1061 } 1062 return null; 1063 } 1064 1065 /** 1066 * Returns a comparator with which to sort rows of this rowset definition. 1067 * The sort order is defined by the {@link #sortColumnDefinitions} field. 1068 * If the rowset is not sorted, returns null. 1069 */ 1070 Comparator<Rowset.Row> getComparator() { 1071 if (sortColumnDefinitions == null) { 1072 return null; 1073 } 1074 return new Comparator<Rowset.Row>() { 1075 public int compare(Rowset.Row row1, Rowset.Row row2) { 1076 // A faster implementation is welcome. 1077 for (Column sortColumn : sortColumnDefinitions) { 1078 Comparable val1 = (Comparable) row1.get(sortColumn.name); 1079 Comparable val2 = (Comparable) row2.get(sortColumn.name); 1080 if ((val1 == null) && (val2 == null)) { 1081 // columns can be optional, compare next column 1082 continue; 1083 } else if (val1 == null) { 1084 return -1; 1085 } else if (val2 == null) { 1086 return 1; 1087 } else if (val1 instanceof String && 1088 val2 instanceof String) { 1089 int v = 1090 ((String) val1).compareToIgnoreCase((String) val2); 1091 // if equal (= 0), compare next column 1092 if (v != 0) { 1093 return v; 1094 } 1095 } else { 1096 int v = val1.compareTo(val2); 1097 // if equal (= 0), compare next column 1098 if (v != 0) { 1099 return v; 1100 } 1101 } 1102 } 1103 return 0; 1104 } 1105 }; 1106 } 1107 1108 /** 1109 * Generates an XML schema description to the writer. 1110 * This is broken into top, Row definition and bottom so that on a 1111 * case by case basis a RowsetDefinition can redefine the Row 1112 * definition output. The default assumes a flat set of elements, but 1113 * for example, SchemaRowsets has a element with child elements. 1114 * 1115 * @param writer SAX writer 1116 * @see XmlaHandler#writeDatasetXmlSchema(SaxWriter, mondrian.xmla.XmlaHandler.SetType) 1117 */ 1118 void writeRowsetXmlSchema(SaxWriter writer) { 1119 writeRowsetXmlSchemaTop(writer); 1120 writeRowsetXmlSchemaRowDef(writer); 1121 writeRowsetXmlSchemaBottom(writer); 1122 } 1123 1124 protected void writeRowsetXmlSchemaTop(SaxWriter writer) { 1125 writer.startElement("xsd:schema", new String[] { 1126 "xmlns:xsd", XmlaConstants.NS_XSD, 1127 "xmlns", XmlaConstants.NS_XMLA_ROWSET, 1128 "xmlns:xsi", XmlaConstants.NS_XSI, 1129 "xmlns:sql", "urn:schemas-microsoft-com:xml-sql", 1130 "targetNamespace", XmlaConstants.NS_XMLA_ROWSET, 1131 "elementFormDefault", "qualified" 1132 }); 1133 1134 writer.startElement("xsd:element", new String[] { 1135 "name", "root" 1136 }); 1137 writer.startElement("xsd:complexType"); 1138 writer.startElement("xsd:sequence"); 1139 writer.element("xsd:element", new String[] { 1140 "name", "row", 1141 "type", "row", 1142 "minOccurs", "0", 1143 "maxOccurs", "unbounded" 1144 }); 1145 writer.endElement(); // xsd:sequence 1146 writer.endElement(); // xsd:complexType 1147 writer.endElement(); // xsd:element 1148 1149 // MS SQL includes this in its schema section even thought 1150 // its not need for most queries. 1151 writer.startElement("xsd:simpleType", new String[] { 1152 "name", "uuid" 1153 }); 1154 writer.startElement("xsd:restriction", new String[] { 1155 "base", "xsd:string" 1156 }); 1157 writer.element("xsd:pattern", new String[] { 1158 "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}" 1159 }); 1160 1161 writer.endElement(); // xsd:restriction 1162 writer.endElement(); // xsd:simpleType 1163 1164 } 1165 1166 protected void writeRowsetXmlSchemaRowDef(SaxWriter writer) { 1167 writer.startElement("xsd:complexType", new String[] { 1168 "name", "row" 1169 }); 1170 writer.startElement("xsd:sequence"); 1171 for (Column column : columnDefinitions) { 1172 final String name = XmlaUtil.encodeElementName(column.name); 1173 final String xsdType = column.type.columnType; 1174 1175 String[] attrs; 1176 if (column.nullable) { 1177 if (column.unbounded) { 1178 attrs = new String[]{ 1179 "sql:field", column.name, 1180 "name", name, 1181 "type", xsdType, 1182 "minOccurs", "0", 1183 "maxOccurs", "unbounded" 1184 }; 1185 } else { 1186 attrs = new String[]{ 1187 "sql:field", column.name, 1188 "name", name, 1189 "type", xsdType, 1190 "minOccurs", "0" 1191 }; 1192 } 1193 } else { 1194 if (column.unbounded) { 1195 attrs = new String[]{ 1196 "sql:field", column.name, 1197 "name", name, 1198 "type", xsdType, 1199 "maxOccurs", "unbounded" 1200 }; 1201 } else { 1202 attrs = new String[]{ 1203 "sql:field", column.name, 1204 "name", name, 1205 "type", xsdType 1206 }; 1207 } 1208 } 1209 writer.element("xsd:element", attrs); 1210 } 1211 writer.endElement(); // xsd:sequence 1212 writer.endElement(); // xsd:complexType 1213 } 1214 1215 protected void writeRowsetXmlSchemaBottom(SaxWriter writer) { 1216 writer.endElement(); // xsd:schema 1217 } 1218 1219 enum Type { 1220 String("xsd:string"), 1221 StringArray("xsd:string"), 1222 Array("xsd:string"), 1223 Enumeration("xsd:string"), 1224 EnumerationArray("xsd:string"), 1225 EnumString("xsd:string"), 1226 Boolean("xsd:boolean"), 1227 StringSometimesArray("xsd:string"), 1228 Integer("xsd:int"), 1229 UnsignedInteger("xsd:unsignedInt"), 1230 DateTime("xsd:dateTime"), 1231 Short("xsd:short"), 1232 UUID("uuid"), 1233 UnsignedShort("xsd:unsignedShort"), 1234 Long("xsd:long"), 1235 UnsignedLong("xsd:unsignedLong"); 1236 1237 public final String columnType; 1238 1239 Type(String columnType) { 1240 this.columnType = columnType; 1241 } 1242 1243 boolean isEnum() { 1244 return this == Enumeration || 1245 this == EnumerationArray || 1246 this == EnumString; 1247 } 1248 1249 String getName() { 1250 return this == String ? "string" : name(); 1251 } 1252 } 1253 1254 private static DBType getDBTypeFromProperty(Property prop) { 1255 switch (prop.getType()) { 1256 case TYPE_STRING: 1257 return DBType.WSTR; 1258 case TYPE_NUMERIC: 1259 return DBType.R8; 1260 case TYPE_BOOLEAN: 1261 return DBType.BOOL; 1262 case TYPE_OTHER: 1263 default: 1264 // TODO: what type is it really, its not a string 1265 return DBType.WSTR; 1266 } 1267 } 1268 1269 /** 1270 * The only OLE DB Types Indicators returned by SQL Server are thoses coded 1271 * below. 1272 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtype_indicators.asp 1273 */ 1274 1275 enum DBType { 1276 /* 1277 * The following values exactly match VARENUM 1278 * in Automation and may be used in VARIANT. 1279 */ 1280 I4("INTEGER", 3, "DBTYPE_I4", "A four-byte, signed integer: INTEGER"), 1281 1282 R8("DOUBLE", 5, 1283 "DBTYPE_R8", "A double-precision floating-point value: Double"), 1284 1285 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."), 1286 1287 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."), 1288 1289 /** 1290 * Used by SQL Server for value. 1291 */ 1292 VARIANT("VARIANT", 12, "DBTYPE_VARIANT", "An Automation VARIANT"), 1293 1294 /** 1295 * Used by SQL Server for font size. 1296 */ 1297 UI2("UNSIGNED_SHORT", 18, "DBTYPE_UI2", "A two-byte, unsigned integer"), 1298 1299 /** 1300 * Used by SQL Server for colors, font flags and cell ordinal. 1301 */ 1302 UI4("UNSIGNED_INTEGER", 19, "DBTYPE_UI4", "A four-byte, unsigned integer"), 1303 1304 /* 1305 * The following values exactly match VARENUM 1306 * in Automation but cannot be used in VARIANT. 1307 */ 1308 I8("LARGE_INTEGER", 20, "DBTYPE_I8", "An eight-byte, signed integer: LARGE_INTEGER"), 1309 1310 /* 1311 * The following values are not in VARENUM in OLE. 1312 */ 1313 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."); 1314 1315 1316 /** 1317 * The length of a non-numeric column or parameter that refers to either 1318 * the maximum or the length defined for this type by the provider. For 1319 * character data, this is the maximum or defined length in characters. 1320 * For DateTime data types, this is the length of the string 1321 * representation (assuming the maximum allowed precision of the 1322 * fractional seconds component). 1323 * 1324 * If the data type is numeric, this is the upper bound on the maximum 1325 * precision of the data type. 1326 int columnSize; 1327 */ 1328 1329 private final String userName; 1330 private final int userOrdinal; 1331 /** 1332 * A Boolean that indicates whether the data type is nullable. 1333 * VARIANT_TRUE indicates that the data type is nullable. 1334 * VARIANT_FALSE indicates that the data type is not nullable. 1335 * NULL-- indicates that it is not known whether the data type is 1336 * nullable. 1337 boolean isNullable; 1338 */ 1339 1340 String dbTypeIndicator; 1341 1342 DBType( 1343 String userName, 1344 int userOrdinal, 1345 String dbTypeIndicator, 1346 String description) 1347 { 1348 this.userName = userName; 1349 this.userOrdinal = userOrdinal; 1350 Util.discard(description); 1351 this.dbTypeIndicator = dbTypeIndicator; 1352 } 1353 1354 } 1355 1356 static class Column { 1357 1358 /** 1359 * This is used as the true value for the restriction parameter. 1360 */ 1361 static final boolean RESTRICTION = true; 1362 /** 1363 * This is used as the false value for the restriction parameter. 1364 */ 1365 static final boolean NOT_RESTRICTION = false; 1366 1367 /** 1368 * This is used as the false value for the nullable parameter. 1369 */ 1370 static final boolean REQUIRED = false; 1371 /** 1372 * This is used as the true value for the nullable parameter. 1373 */ 1374 static final boolean OPTIONAL = true; 1375 1376 /** 1377 * This is used as the false value for the unbounded parameter. 1378 */ 1379 static final boolean ONE_MAX = false; 1380 /** 1381 * This is used as the true value for the unbounded parameter. 1382 */ 1383 static final boolean UNBOUNDED = true; 1384 1385 final String name; 1386 final Type type; 1387 final Enumeration enumeration; 1388 final String description; 1389 final boolean restriction; 1390 final boolean nullable; 1391 final boolean unbounded; 1392 1393 /** 1394 * Creates a column. 1395 * 1396 * @param name Name of column 1397 * @param type A {@link mondrian.xmla.RowsetDefinition.Type} value 1398 * @param enumeratedType Must be specified for enumeration or array 1399 * of enumerations 1400 * @param description Description of column 1401 * @param restriction Whether column can be used as a filter on its 1402 * rowset 1403 * @param nullable Whether column can contain null values 1404 * @pre type != null 1405 * @pre (type == Type.Enumeration || type == Type.EnumerationArray || type == Type.EnumString) == (enumeratedType != null) 1406 * @pre description == null || description.indexOf('\r') == -1 1407 */ 1408 Column( 1409 String name, 1410 Type type, 1411 Enumeration enumeratedType, 1412 boolean restriction, 1413 boolean nullable, 1414 String description) 1415 { 1416 this( 1417 name, type, enumeratedType, 1418 restriction, nullable, ONE_MAX, description); 1419 } 1420 1421 Column( 1422 String name, 1423 Type type, 1424 Enumeration enumeratedType, 1425 boolean restriction, 1426 boolean nullable, 1427 boolean unbounded, 1428 String description) 1429 { 1430 assert type != null; 1431 assert (type == Type.Enumeration || 1432 type == Type.EnumerationArray || 1433 type == Type.EnumString) == 1434 (enumeratedType != null); 1435 // Line endings must be UNIX style (LF) not Windows style (LF+CR). 1436 // Thus the client will receive the same XML, regardless 1437 // of the server O/S. 1438 assert description == null || description.indexOf('\r') == -1; 1439 this.name = name; 1440 this.type = type; 1441 this.enumeration = enumeratedType; 1442 this.description = description; 1443 this.restriction = restriction; 1444 this.nullable = nullable; 1445 this.unbounded = unbounded; 1446 } 1447 1448 /** 1449 * Retrieves a value of this column from a row. The base implementation 1450 * uses reflection to call an accessor method; a derived class may 1451 * provide a different implementation. 1452 * 1453 * @param row Row 1454 */ 1455 protected Object get(Object row) { 1456 return getFromAccessor(row); 1457 } 1458 1459 /** 1460 * Retrieves the value of this column "MyColumn" from a field called 1461 * "myColumn". 1462 * 1463 * @param row Current row 1464 * @return Value of given this property of the given row 1465 */ 1466 protected final Object getFromField(Object row) { 1467 try { 1468 String javaFieldName = name.substring(0, 1).toLowerCase() + 1469 name.substring(1); 1470 Field field = row.getClass().getField(javaFieldName); 1471 return field.get(row); 1472 } catch (NoSuchFieldException e) { 1473 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1474 } catch (SecurityException e) { 1475 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1476 } catch (IllegalAccessException e) { 1477 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1478 } 1479 } 1480 1481 /** 1482 * Retrieves the value of this column "MyColumn" by calling a method 1483 * called "getMyColumn()". 1484 * 1485 * @param row Current row 1486 * @return Value of given this property of the given row 1487 */ 1488 protected final Object getFromAccessor(Object row) { 1489 try { 1490 String javaMethodName = "get" + name; 1491 Method method = row.getClass().getMethod(javaMethodName); 1492 return method.invoke(row); 1493 } catch (SecurityException e) { 1494 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1495 } catch (IllegalAccessException e) { 1496 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1497 } catch (NoSuchMethodException e) { 1498 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1499 } catch (InvocationTargetException e) { 1500 throw Util.newInternal(e, "Error while accessing rowset column " + name); 1501 } 1502 } 1503 1504 public String getColumnType() { 1505 if (type.isEnum()) { 1506 return enumeration.type.columnType; 1507 } 1508 return type.columnType; 1509 } 1510 } 1511 1512 // ------------------------------------------------------------------------- 1513 // From this point on, just rowset classess. 1514 1515 static class DiscoverDatasourcesRowset extends Rowset { 1516 private static final Column DataSourceName = 1517 new Column( 1518 "DataSourceName", 1519 Type.String, 1520 null, 1521 Column.RESTRICTION, 1522 Column.REQUIRED, 1523 "The name of the data source, such as FoodMart 2000."); 1524 private static final Column DataSourceDescription = 1525 new Column( 1526 "DataSourceDescription", 1527 Type.String, 1528 null, 1529 Column.NOT_RESTRICTION, 1530 Column.OPTIONAL, 1531 "A description of the data source, as entered by the publisher."); 1532 private static final Column URL = 1533 new Column( 1534 "URL", 1535 Type.String, 1536 null, 1537 Column.RESTRICTION, 1538 Column.OPTIONAL, 1539 "The unique path that shows where to invoke the XML for Analysis methods for that data source."); 1540 private static final Column DataSourceInfo = 1541 new Column( 1542 "DataSourceInfo", 1543 Type.String, 1544 null, 1545 Column.NOT_RESTRICTION, 1546 Column.OPTIONAL, 1547 "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" + 1548 "Example: \"Provider=MSOLAP;Data Source=Local;\""); 1549 private static final Column ProviderName = 1550 new Column( 1551 "ProviderName", 1552 Type.String, 1553 null, 1554 Column.RESTRICTION, 1555 Column.OPTIONAL, 1556 "The name of the provider behind the data source. \n" + 1557 "Example: \"MSDASQL\""); 1558 private static final Column ProviderType = 1559 new Column( 1560 "ProviderType", 1561 Type.EnumerationArray, 1562 Enumeration.ProviderType.enumeration, 1563 Column.RESTRICTION, 1564 Column.REQUIRED, 1565 Column.UNBOUNDED, 1566 "The types of data supported by the provider. May include one or more of the following types. Example follows this table.\n" + 1567 "TDP: tabular data provider.\n" + 1568 "MDP: multidimensional data provider.\n" + 1569 "DMP: data mining provider. A DMP provider implements the OLE DB for Data Mining specification."); 1570 private static final Column AuthenticationMode = 1571 new Column( 1572 "AuthenticationMode", 1573 Type.EnumString, 1574 Enumeration.AuthenticationMode.enumeration, 1575 Column.RESTRICTION, 1576 Column.REQUIRED, 1577 "Specification of what type of security mode the data source uses. Values can be one of the following:\n" + 1578 "Unauthenticated: no user ID or password needs to be sent.\n" + 1579 "Authenticated: User ID and Password must be included in the information required for the connection.\n" + 1580 "Integrated: the data source uses the underlying security to determine authorization, such as Integrated Security provided by Microsoft Internet Information Services (IIS)."); 1581 1582 public DiscoverDatasourcesRowset(XmlaRequest request, XmlaHandler handler) { 1583 super(DISCOVER_DATASOURCES, request, handler); 1584 } 1585 1586 public void populate( 1587 XmlaResponse response, 1588 List<Row> rows) 1589 throws XmlaException 1590 { 1591 for (DataSourcesConfig.DataSource ds : handler 1592 .getDataSourceEntries().values()) { 1593 Row row = new Row(); 1594 row.set(DataSourceName.name, ds.getDataSourceName()); 1595 row.set(DataSourceDescription.name, 1596 ds.getDataSourceDescription()); 1597 row.set(URL.name, ds.getURL()); 1598 row.set(DataSourceInfo.name, ds.getDataSourceName()); 1599 row.set(ProviderName.name, ds.getProviderName()); 1600 row.set(ProviderType.name, ds.getProviderType()); 1601 row.set(AuthenticationMode.name, ds.getAuthenticationMode()); 1602 addRow(row, rows); 1603 } 1604 } 1605 1606 protected void setProperty( 1607 PropertyDefinition propertyDef, 1608 String value) 1609 { 1610 switch (propertyDef) { 1611 case Content: 1612 break; 1613 default: 1614 super.setProperty(propertyDef, value); 1615 } 1616 } 1617 } 1618 1619 static class DiscoverSchemaRowsetsRowset extends Rowset { 1620 private static final Column SchemaName = 1621 new Column( 1622 "SchemaName", 1623 Type.StringArray, 1624 null, 1625 Column.RESTRICTION, 1626 Column.REQUIRED, 1627 "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"); 1628 private static final Column SchemaGuid = 1629 new Column( 1630 "SchemaGuid", 1631 Type.UUID, 1632 null, 1633 Column.NOT_RESTRICTION, 1634 Column.OPTIONAL, 1635 "The GUID of the schema."); 1636 private static final Column Restrictions = 1637 new Column( 1638 "Restrictions", 1639 Type.Array, 1640 null, 1641 Column.NOT_RESTRICTION, 1642 Column.REQUIRED, 1643 "An array of the restrictions suppoted by provider. An example follows this table."); 1644 private static final Column Description = 1645 new Column( 1646 "Description", 1647 Type.String, 1648 null, 1649 Column.NOT_RESTRICTION, 1650 Column.REQUIRED, 1651 "A localizable description of the schema"); 1652 1653 public DiscoverSchemaRowsetsRowset(XmlaRequest request, XmlaHandler handler) { 1654 super(DISCOVER_SCHEMA_ROWSETS, request, handler); 1655 } 1656 1657 public void populate( 1658 XmlaResponse response, 1659 List<Row> rows) 1660 throws XmlaException 1661 { 1662 RowsetDefinition[] rowsetDefinitions = 1663 RowsetDefinition.class.getEnumConstants().clone(); 1664 Arrays.sort( 1665 rowsetDefinitions, 1666 new Comparator<Enum>() { 1667 public int compare(Enum o1, Enum o2) { 1668 return o1.name().compareTo(o2.name()); 1669 } 1670 }); 1671 for (RowsetDefinition rowsetDefinition : rowsetDefinitions) { 1672 Row row = new Row(); 1673 row.set(SchemaName.name, rowsetDefinition.name()); 1674 1675 // TODO: If we have a SchemaGuid output here 1676 //row.set(SchemaGuid.name, ""); 1677 1678 row.set(Restrictions.name, getRestrictions(rowsetDefinition)); 1679 1680 String desc = rowsetDefinition.getDescription(); 1681 row.set(Description.name, (desc == null) ? "" : desc); 1682 addRow(row, rows); 1683 } 1684 } 1685 1686 private List<XmlElement> getRestrictions(RowsetDefinition rowsetDefinition) { 1687 List<XmlElement> restrictionList = new ArrayList<XmlElement>(); 1688 final Column[] columns = rowsetDefinition.columnDefinitions; 1689 for (Column column : columns) { 1690 if (column.restriction) { 1691 restrictionList.add( 1692 new XmlElement(Restrictions.name, 1693 null, 1694 new XmlElement[]{ 1695 new XmlElement("Name", null, column.name), 1696 new XmlElement("Type", 1697 null, 1698 column.getColumnType()) 1699 })); 1700 } 1701 } 1702 return restrictionList; 1703 } 1704 1705 protected void setProperty(PropertyDefinition propertyDef, String value) { 1706 switch (propertyDef) { 1707 case Content: 1708 break; 1709 default: 1710 super.setProperty(propertyDef, value); 1711 } 1712 } 1713 } 1714 1715 public String getDescription() { 1716 return description; 1717 } 1718 1719 static class DiscoverPropertiesRowset extends Rowset { 1720 private final RestrictionTest propertyNameRT; 1721 1722 DiscoverPropertiesRowset(XmlaRequest request, XmlaHandler handler) { 1723 super(DISCOVER_PROPERTIES, request, handler); 1724 propertyNameRT = getRestrictionTest(PropertyName); 1725 } 1726 1727 private static final Column PropertyName = 1728 new Column( 1729 "PropertyName", 1730 Type.StringSometimesArray, 1731 null, 1732 Column.RESTRICTION, 1733 Column.REQUIRED, 1734 "The name of the property."); 1735 private static final Column PropertyDescription = 1736 new Column( 1737 "PropertyDescription", 1738 Type.String, 1739 null, 1740 Column.NOT_RESTRICTION, 1741 Column.REQUIRED, 1742 "A localizable text description of the property."); 1743 private static final Column PropertyType = 1744 new Column( 1745 "PropertyType", 1746 Type.String, 1747 null, 1748 Column.NOT_RESTRICTION, 1749 Column.REQUIRED, 1750 "The XML data type of the property."); 1751 private static final Column PropertyAccessType = 1752 new Column( 1753 "PropertyAccessType", 1754 Type.EnumString, 1755 Enumeration.Access.enumeration, 1756 Column.NOT_RESTRICTION, 1757 Column.REQUIRED, 1758 "Access for the property. The value can be Read, Write, or ReadWrite."); 1759 private static final Column IsRequired = 1760 new Column( 1761 "IsRequired", 1762 Type.Boolean, 1763 null, 1764 Column.NOT_RESTRICTION, 1765 Column.REQUIRED, 1766 "True if a property is required, false if it is not required."); 1767 private static final Column Value = 1768 new Column( 1769 "Value", 1770 Type.String, 1771 null, 1772 Column.NOT_RESTRICTION, 1773 Column.REQUIRED, 1774 "The current value of the property."); 1775 1776 public void populate( 1777 XmlaResponse response, 1778 List<Row> rows) 1779 throws XmlaException 1780 { 1781 for (PropertyDefinition propertyDefinition : 1782 PropertyDefinition.class.getEnumConstants()) { 1783 if (!propertyNameRT.passes(propertyDefinition.name())) { 1784 continue; 1785 } 1786 Row row = new Row(); 1787 row.set(PropertyName.name, propertyDefinition.name()); 1788 row.set(PropertyDescription.name, propertyDefinition.description); 1789 row.set(PropertyType.name, propertyDefinition.type.getName()); 1790 row.set(PropertyAccessType.name, propertyDefinition.access); 1791 row.set(IsRequired.name, false); 1792 row.set(Value.name, propertyDefinition.value); 1793 addRow(row, rows); 1794 } 1795 } 1796 1797 protected void setProperty(PropertyDefinition propertyDef, String value) { 1798 switch (propertyDef) { 1799 case Content: 1800 break; 1801 default: 1802 super.setProperty(propertyDef, value); 1803 } 1804 } 1805 } 1806 1807 static class DiscoverEnumeratorsRowset extends Rowset { 1808 DiscoverEnumeratorsRowset(XmlaRequest request, XmlaHandler handler) { 1809 super(DISCOVER_ENUMERATORS, request, handler); 1810 } 1811 1812 private static final Column EnumName = 1813 new Column( 1814 "EnumName", 1815 Type.StringArray, 1816 null, 1817 Column.RESTRICTION, 1818 Column.REQUIRED, 1819 "The name of the enumerator that contains a set of values."); 1820 private static final Column EnumDescription = 1821 new Column( 1822 "EnumDescription", 1823 Type.String, 1824 null, 1825 Column.NOT_RESTRICTION, 1826 Column.OPTIONAL, 1827 "A localizable description of the enumerator."); 1828 private static final Column EnumType = 1829 new Column( 1830 "EnumType", 1831 Type.String, 1832 null, 1833 Column.NOT_RESTRICTION, 1834 Column.REQUIRED, 1835 "The data type of the Enum values."); 1836 private static final Column ElementName = 1837 new Column( 1838 "ElementName", 1839 Type.String, 1840 null, 1841 Column.NOT_RESTRICTION, 1842 Column.REQUIRED, 1843 "The name of one of the value elements in the enumerator set.\n" + "Example: TDP"); 1844 private static final Column ElementDescription = 1845 new Column( 1846 "ElementDescription", 1847 Type.String, 1848 null, 1849 Column.NOT_RESTRICTION, 1850 Column.OPTIONAL, 1851 "A localizable description of the element (optional)."); 1852 private static final Column ElementValue = 1853 new Column( 1854 "ElementValue", 1855 Type.String, 1856 null, 1857 Column.NOT_RESTRICTION, 1858 Column.OPTIONAL, 1859 "The value of the element.\n" + "Example: 01"); 1860 1861 public void populate( 1862 XmlaResponse response, 1863 List<Row> rows) 1864 throws XmlaException 1865 { 1866 List<Enumeration> enumerators = getEnumerators(); 1867 for (Enumeration enumerator : enumerators) { 1868 final String[] valueNames = enumerator.getNames(); 1869 for (String valueName : valueNames) { 1870 final Enum<?> value = enumerator.getValue(valueName, true); 1871 Row row = new Row(); 1872 row.set(EnumName.name, enumerator.name); 1873 row.set(EnumDescription.name, enumerator.description); 1874 1875 // Note: SQL Server always has EnumType string 1876 // Need type of element of array, not the array 1877 // it self. 1878 row.set(EnumType.name, "string"); 1879 1880 String name = 1881 value instanceof Enumeration.EnumWithName ? 1882 ((Enumeration.EnumWithName) value).userName() : 1883 value.name(); 1884 row.set(ElementName.name, name); 1885 1886 if (value instanceof Enumeration.EnumWithDesc) { 1887 String description = 1888 ((Enumeration.EnumWithDesc) value).getDescription(); 1889 row.set(ElementDescription.name, description); 1890 } 1891 1892 switch (enumerator.type) { 1893 case String: 1894 case StringArray: 1895 // these don't have ordinals 1896 break; 1897 default: 1898 int ordinal = 1899 value instanceof Enumeration.EnumWithOrdinal ? 1900 ((Enumeration.EnumWithOrdinal) value).userOrdinal() : 1901 value.ordinal(); 1902 row.set(ElementValue.name, ordinal); 1903 break; 1904 } 1905 addRow(row, rows); 1906 } 1907 } 1908 } 1909 1910 private static List<Enumeration> getEnumerators() { 1911 SortedSet<Enumeration> enumeratorSet = new TreeSet<Enumeration>( 1912 new Comparator<Enumeration>() { 1913 public int compare(Enumeration o1, Enumeration o2) { 1914 return o1.name.compareTo(o2.name); 1915 } 1916 } 1917 ); 1918 for (RowsetDefinition rowsetDefinition : RowsetDefinition.class.getEnumConstants()) { 1919 for (Column column : rowsetDefinition.columnDefinitions) { 1920 if (column.enumeration != null) { 1921 enumeratorSet.add(column.enumeration); 1922 } 1923 } 1924 } 1925 return new ArrayList<Enumeration>(enumeratorSet); 1926 } 1927 1928 protected void setProperty(PropertyDefinition propertyDef, String value) { 1929 switch (propertyDef) { 1930 case Content: 1931 break; 1932 default: 1933 super.setProperty(propertyDef, value); 1934 } 1935 } 1936 } 1937 1938 static class DiscoverKeywordsRowset extends Rowset { 1939 DiscoverKeywordsRowset(XmlaRequest request, XmlaHandler handler) { 1940 super(DISCOVER_KEYWORDS, request, handler); 1941 } 1942 1943 private static final Column Keyword = 1944 new Column( 1945 "Keyword", 1946 Type.StringSometimesArray, 1947 null, 1948 Column.RESTRICTION, 1949 Column.REQUIRED, 1950 "A list of all the keywords reserved by a provider.\n" + 1951 "Example: AND"); 1952 1953 public void populate( 1954 XmlaResponse response, 1955 List<Row> rows) 1956 throws XmlaException 1957 { 1958 MondrianServer mondrianServer = MondrianServer.forConnection(null); 1959 for (String keyword : mondrianServer.getKeywords()) { 1960 Row row = new Row(); 1961 row.set(Keyword.name, keyword); 1962 addRow(row, rows); 1963 } 1964 } 1965 1966 protected void setProperty( 1967 PropertyDefinition propertyDef, 1968 String value) 1969 { 1970 switch (propertyDef) { 1971 case Content: 1972 break; 1973 default: 1974 super.setProperty(propertyDef, value); 1975 } 1976 } 1977 } 1978 1979 static class DiscoverLiteralsRowset extends Rowset { 1980 DiscoverLiteralsRowset(XmlaRequest request, XmlaHandler handler) { 1981 super(DISCOVER_LITERALS, request, handler); 1982 } 1983 1984 private static final Column LiteralName = new Column( 1985 "LiteralName", 1986 Type.StringSometimesArray, 1987 null, 1988 Column.RESTRICTION, 1989 Column.REQUIRED, 1990 "The name of the literal described in the row.\n" + "Example: DBLITERAL_LIKE_PERCENT"); 1991 1992 private static final Column LiteralValue = new Column( 1993 "LiteralValue", 1994 Type.String, 1995 null, 1996 Column.NOT_RESTRICTION, 1997 Column.OPTIONAL, 1998 "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 \"%\"."); 1999 2000 private static final Column LiteralInvalidChars = new Column( 2001 "LiteralInvalidChars", 2002 Type.String, 2003 null, 2004 Column.NOT_RESTRICTION, 2005 Column.OPTIONAL, 2006 "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\"."); 2007 2008 private static final Column LiteralInvalidStartingChars = new Column( 2009 "LiteralInvalidStartingChars", 2010 Type.String, 2011 null, 2012 Column.NOT_RESTRICTION, 2013 Column.OPTIONAL, 2014 "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."); 2015 2016 private static final Column LiteralMaxLength = new Column( 2017 "LiteralMaxLength", 2018 Type.Integer, 2019 null, 2020 Column.NOT_RESTRICTION, 2021 Column.OPTIONAL, 2022 "The maximum number of characters in the literal. If there is no maximum or the maximum is unknown, the value is ?1."); 2023 2024 public void populate( 2025 XmlaResponse response, 2026 List<Row> rows) 2027 throws XmlaException 2028 { 2029 populate(Enumeration.Literal.class, rows); 2030 } 2031 2032 protected void setProperty( 2033 PropertyDefinition propertyDef, 2034 String value) 2035 { 2036 switch (propertyDef) { 2037 case Content: 2038 break; 2039 default: 2040 super.setProperty(propertyDef, value); 2041 } 2042 } 2043 } 2044 2045 static class DbschemaCatalogsRowset extends Rowset { 2046 private final RestrictionTest catalogNameRT; 2047 2048 DbschemaCatalogsRowset(XmlaRequest request, XmlaHandler handler) { 2049 super(DBSCHEMA_CATALOGS, request, handler); 2050 catalogNameRT = getRestrictionTest(CatalogName); 2051 } 2052 2053 private static final Column CatalogName = 2054 new Column( 2055 "CATALOG_NAME", 2056 Type.String, 2057 null, 2058 Column.RESTRICTION, 2059 Column.REQUIRED, 2060 "Catalog name. Cannot be NULL."); 2061 private static final Column Description = 2062 new Column( 2063 "DESCRIPTION", 2064 Type.String, 2065 null, 2066 Column.NOT_RESTRICTION, 2067 Column.REQUIRED, 2068 "Human-readable description of the catalog."); 2069 private static final Column Roles = 2070 new Column( 2071 "ROLES", 2072 Type.String, 2073 null, 2074 Column.NOT_RESTRICTION, 2075 Column.REQUIRED, 2076 "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."); 2077 private static final Column DateModified = 2078 new Column( 2079 "DATE_MODIFIED", 2080 Type.DateTime, 2081 null, 2082 Column.NOT_RESTRICTION, 2083 Column.OPTIONAL, 2084 "The date that the catalog was last modified."); 2085 2086 public void populate( 2087 XmlaResponse response, 2088 List<Row> rows) 2089 throws XmlaException 2090 { 2091 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 2092 DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs; 2093 String roleName = request.getRoleName(); 2094 Role role = request.getRole(); 2095 2096 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 2097 if (dsCatalog == null || dsCatalog.definition == null) { 2098 continue; 2099 } 2100 Connection connection = 2101 handler.getConnection(dsCatalog, role, roleName); 2102 if (connection == null) { 2103 continue; 2104 } 2105 if (!catalogNameRT.passes(dsCatalog.name)) { 2106 continue; 2107 } 2108 final Schema schema = connection.getSchema(); 2109 2110 Row row = new Row(); 2111 row.set(CatalogName.name, dsCatalog.name); 2112 2113 // TODO: currently schema grammar does not support a description 2114 row.set(Description.name, "No description available"); 2115 2116 // get Role names 2117 // TODO: this returns ALL roles, no the current user's roles 2118 StringBuilder buf = new StringBuilder(100); 2119 serialize(buf, ((RolapSchema) schema).roleNames()); 2120 row.set(Roles.name, buf.toString()); 2121 2122 // TODO: currently schema grammar does not support modify date 2123 // so we return just some date for now. 2124 if (false) { 2125 row.set(DateModified.name, dateModified); 2126 } 2127 addRow(row, rows); 2128 } 2129 } 2130 2131 protected void setProperty(PropertyDefinition propertyDef, String value) { 2132 switch (propertyDef) { 2133 case Content: 2134 break; 2135 default: 2136 super.setProperty(propertyDef, value); 2137 } 2138 } 2139 } 2140 2141 static class DbschemaColumnsRowset extends Rowset { 2142 private final RestrictionTest tableCatalogRT; 2143 private final RestrictionTest tableNameRT; 2144 private final RestrictionTest columnNameRT; 2145 2146 DbschemaColumnsRowset(XmlaRequest request, XmlaHandler handler) { 2147 super(DBSCHEMA_COLUMNS, request, handler); 2148 tableCatalogRT = getRestrictionTest(TableCatalog); 2149 tableNameRT = getRestrictionTest(TableName); 2150 columnNameRT = getRestrictionTest(ColumnName); 2151 } 2152 2153 private static final Column TableCatalog = 2154 new Column( 2155 "TABLE_CATALOG", 2156 Type.String, 2157 null, 2158 Column.RESTRICTION, 2159 Column.REQUIRED, 2160 "The name of the Database."); 2161 private static final Column TableSchema = 2162 new Column( 2163 "TABLE_SCHEMA", 2164 Type.String, 2165 null, 2166 Column.RESTRICTION, 2167 Column.OPTIONAL, 2168 null); 2169 private static final Column TableName = 2170 new Column( 2171 "TABLE_NAME", 2172 Type.String, 2173 null, 2174 Column.RESTRICTION, 2175 Column.REQUIRED, 2176 "The name of the cube."); 2177 private static final Column ColumnName = 2178 new Column( 2179 "COLUMN_NAME", 2180 Type.String, 2181 null, 2182 Column.RESTRICTION, 2183 Column.REQUIRED, 2184 "The name of the attribute hierarchy or measure."); 2185 private static final Column OrdinalPosition = 2186 new Column( 2187 "ORDINAL_POSITION", 2188 Type.UnsignedInteger, 2189 null, 2190 Column.NOT_RESTRICTION, 2191 Column.REQUIRED, 2192 "The position of the column, beginning with 1."); 2193 private static final Column ColumnHasDefault = 2194 new Column( 2195 "COLUMN_HAS_DEFAULT", 2196 Type.Boolean, 2197 null, 2198 Column.NOT_RESTRICTION, 2199 Column.OPTIONAL, 2200 "Not supported."); 2201 /* 2202 * A bitmask indicating the information stored in 2203 * DBCOLUMNFLAGS in OLE DB. 2204 * 1 = Bookmark 2205 * 2 = Fixed length 2206 * 4 = Nullable 2207 * 8 = Row versioning 2208 * 16 = Updateable column 2209 * 2210 * And, of course, MS SQL Server sometimes has the value of 80!! 2211 */ 2212 private static final Column ColumnFlags = 2213 new Column( 2214 "COLUMN_FLAGS", 2215 Type.UnsignedInteger, 2216 null, 2217 Column.NOT_RESTRICTION, 2218 Column.REQUIRED, 2219 "A DBCOLUMNFLAGS bitmask indicating column properties."); 2220 private static final Column IsNullable = 2221 new Column( 2222 "IS_NULLABLE", 2223 Type.Boolean, 2224 null, 2225 Column.NOT_RESTRICTION, 2226 Column.REQUIRED, 2227 "Always returns false."); 2228 private static final Column DataType = 2229 new Column( 2230 "DATA_TYPE", 2231 Type.UnsignedShort, 2232 null, 2233 Column.NOT_RESTRICTION, 2234 Column.REQUIRED, 2235 "The data type of the column. Returns a string for dimension columns and a variant for measures."); 2236 private static final Column CharacterMaximumLength = 2237 new Column( 2238 "CHARACTER_MAXIMUM_LENGTH", 2239 Type.UnsignedInteger, 2240 null, 2241 Column.NOT_RESTRICTION, 2242 Column.OPTIONAL, 2243 "The maximum possible length of a value within the column."); 2244 private static final Column CharacterOctetLength = 2245 new Column( 2246 "CHARACTER_OCTET_LENGTH", 2247 Type.UnsignedInteger, 2248 null, 2249 Column.NOT_RESTRICTION, 2250 Column.OPTIONAL, 2251 "The maximum possible length of a value within the column, in bytes, for character or binary columns."); 2252 private static final Column NumericPrecision = 2253 new Column( 2254 "NUMERIC_PRECISION", 2255 Type.UnsignedShort, 2256 null, 2257 Column.NOT_RESTRICTION, 2258 Column.OPTIONAL, 2259 "The maximum precision of the column for numeric data types other than DBTYPE_VARNUMERIC."); 2260 private static final Column NumericScale = 2261 new Column( 2262 "NUMERIC_SCALE", 2263 Type.Short, 2264 null, 2265 Column.NOT_RESTRICTION, 2266 Column.OPTIONAL, 2267 "The number of digits to the right of the decimal point for DBTYPE_DECIMAL, DBTYPE_NUMERIC, DBTYPE_VARNUMERIC. Otherwise, this is NULL."); 2268 2269 public void populate( 2270 XmlaResponse response, 2271 List<Row> rows) 2272 throws XmlaException 2273 { 2274 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 2275 DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs; 2276 String roleName = request.getRoleName(); 2277 Role role = request.getRole(); 2278 2279 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 2280 if (dsCatalog == null || dsCatalog.definition == null) { 2281 continue; 2282 } 2283 Connection connection = 2284 handler.getConnection(dsCatalog, role, roleName); 2285 if (connection == null) { 2286 continue; 2287 } 2288 final Schema schema = connection.getSchema(); 2289 String catalogName = dsCatalog.name; 2290 if (!tableCatalogRT.passes(catalogName)) { 2291 continue; 2292 } 2293 2294 int ordinalPosition = 1; 2295 Row row; 2296 2297 for (Cube cube1 : sortedCubes(schema)) { 2298 RolapCube cube = (RolapCube) cube1; 2299 SchemaReader schemaReader = 2300 cube.getSchemaReader( 2301 connection.getRole()); 2302 String cubeName = cube.getName(); 2303 if (!tableNameRT.passes(cubeName)) { 2304 continue; 2305 } 2306 for (Dimension dimension : cube.getDimensions()) { 2307 Hierarchy[] hierarchies = dimension.getHierarchies(); 2308 for (Hierarchy hierarchy : hierarchies) { 2309 ordinalPosition = populateHierarchy( 2310 schemaReader, cube, (HierarchyBase) hierarchy, 2311 ordinalPosition, rows); 2312 } 2313 } 2314 2315 List<RolapMember> rms = cube.getMeasuresMembers(); 2316 for (int k = 1; k < rms.size(); k++) { 2317 RolapMember member = rms.get(k); 2318 2319 // null == true for regular cubes 2320 // virtual cubes do not set the visible property 2321 // on its measures so it might be null. 2322 Boolean visible = (Boolean) 2323 member.getPropertyValue(Property.VISIBLE.name); 2324 if (visible == null) { 2325 visible = true; 2326 } 2327 if (!EMIT_INVISIBLE_MEMBERS && !visible) { 2328 continue; 2329 } 2330 2331 String memberName = member.getName(); 2332 if (!columnNameRT.passes("Measures:" + memberName)) { 2333 continue; 2334 } 2335 2336 row = new Row(); 2337 row.set(TableCatalog.name, catalogName); 2338 row.set(TableName.name, cubeName); 2339 row.set(ColumnName.name, "Measures:" + memberName); 2340 row.set(OrdinalPosition.name, ordinalPosition++); 2341 row.set(ColumnHasDefault.name, false); 2342 row.set(ColumnFlags.name, 0); 2343 row.set(IsNullable.name, false); 2344 // TODO: here is where one tries to determine the 2345 // type of the column - since these are all 2346 // Measures, aggregate Measures??, maybe they 2347 // are all numeric? (or currency) 2348 row.set(DataType.name, DBType.R8.userOrdinal); 2349 // TODO: 16/255 seems to be what MS SQL Server 2350 // always returns. 2351 row.set(NumericPrecision.name, 16); 2352 row.set(NumericScale.name, 255); 2353 addRow(row, rows); 2354 } 2355 } 2356 } 2357 } 2358 2359 private int populateHierarchy( 2360 SchemaReader schemaReader, 2361 RolapCube cube, 2362 HierarchyBase hierarchy, 2363 int ordinalPosition, 2364 List<Row> rows) 2365 { 2366 // Access control 2367 if (!canAccess(schemaReader, hierarchy)) { 2368 return ordinalPosition; 2369 } 2370 String schemaName = cube.getSchema().getName(); 2371 String cubeName = cube.getName(); 2372 String hierarchyName = hierarchy.getName(); 2373 2374 if (hierarchy.hasAll()) { 2375 Row row = new Row(); 2376 row.set(TableCatalog.name, schemaName); 2377 row.set(TableName.name, cubeName); 2378 row.set(ColumnName.name, hierarchyName + ":(All)!NAME"); 2379 row.set(OrdinalPosition.name, ordinalPosition++); 2380 row.set(ColumnHasDefault.name, false); 2381 row.set(ColumnFlags.name, 0); 2382 row.set(IsNullable.name, false); 2383 // names are always WSTR 2384 row.set(DataType.name, DBType.WSTR.userOrdinal); 2385 row.set(CharacterMaximumLength.name, 0); 2386 row.set(CharacterOctetLength.name, 0); 2387 addRow(row, rows); 2388 2389 row = new Row(); 2390 row.set(TableCatalog.name, schemaName); 2391 row.set(TableName.name, cubeName); 2392 row.set(ColumnName.name, hierarchyName + ":(All)!UNIQUE_NAME"); 2393 row.set(OrdinalPosition.name, ordinalPosition++); 2394 row.set(ColumnHasDefault.name, false); 2395 row.set(ColumnFlags.name, 0); 2396 row.set(IsNullable.name, false); 2397 // names are always WSTR 2398 row.set(DataType.name, DBType.WSTR.userOrdinal); 2399 row.set(CharacterMaximumLength.name, 0); 2400 row.set(CharacterOctetLength.name, 0); 2401 addRow(row, rows); 2402 2403 if (false) { 2404 // TODO: SQLServer outputs this hasall KEY column name - 2405 // don't know what it's for 2406 row = new Row(); 2407 row.set(TableCatalog.name, schemaName); 2408 row.set(TableName.name, cubeName); 2409 row.set(ColumnName.name, hierarchyName + ":(All)!KEY"); 2410 row.set(OrdinalPosition.name, ordinalPosition++); 2411 row.set(ColumnHasDefault.name, false); 2412 row.set(ColumnFlags.name, 0); 2413 row.set(IsNullable.name, false); 2414 // names are always BOOL 2415 row.set(DataType.name, DBType.BOOL.userOrdinal); 2416 row.set(NumericPrecision.name, 255); 2417 row.set(NumericScale.name, 255); 2418 addRow(row, rows); 2419 } 2420 } 2421 2422 for (Level level : schemaReader.getHierarchyLevels(hierarchy)) { 2423 ordinalPosition = populateLevel( 2424 cube, hierarchy, level, ordinalPosition, rows); 2425 } 2426 return ordinalPosition; 2427 } 2428 2429 private int populateLevel( 2430 Cube cube, 2431 HierarchyBase hierarchy, 2432 Level level, 2433 int ordinalPosition, 2434 List<Row> rows) 2435 { 2436 String schemaName = cube.getSchema().getName(); 2437 String cubeName = cube.getName(); 2438 String hierarchyName = hierarchy.getName(); 2439 String levelName = level.getName(); 2440 2441 Row row = new Row(); 2442 row.set(TableCatalog.name, schemaName); 2443 row.set(TableName.name, cubeName); 2444 row.set(ColumnName.name, 2445 hierarchyName + ':' + levelName + "!NAME"); 2446 row.set(OrdinalPosition.name, ordinalPosition++); 2447 row.set(ColumnHasDefault.name, false); 2448 row.set(ColumnFlags.name, 0); 2449 row.set(IsNullable.name, false); 2450 // names are always WSTR 2451 row.set(DataType.name, DBType.WSTR.userOrdinal); 2452 row.set(CharacterMaximumLength.name, 0); 2453 row.set(CharacterOctetLength.name, 0); 2454 addRow(row, rows); 2455 2456 row = new Row(); 2457 row.set(TableCatalog.name, schemaName); 2458 row.set(TableName.name, cubeName); 2459 row.set(ColumnName.name, 2460 hierarchyName + ':' + levelName + "!UNIQUE_NAME"); 2461 row.set(OrdinalPosition.name, ordinalPosition++); 2462 row.set(ColumnHasDefault.name, false); 2463 row.set(ColumnFlags.name, 0); 2464 row.set(IsNullable.name, false); 2465 // names are always WSTR 2466 row.set(DataType.name, DBType.WSTR.userOrdinal); 2467 row.set(CharacterMaximumLength.name, 0); 2468 row.set(CharacterOctetLength.name, 0); 2469 addRow(row, rows); 2470 2471 /* 2472 TODO: see above 2473 row = new Row(); 2474 row.set(TableCatalog.name, schemaName); 2475 row.set(TableName.name, cubeName); 2476 row.set(ColumnName.name, 2477 hierarchyName + ":" + levelName + "!KEY"); 2478 row.set(OrdinalPosition.name, ordinalPosition++); 2479 row.set(ColumnHasDefault.name, false); 2480 row.set(ColumnFlags.name, 0); 2481 row.set(IsNullable.name, false); 2482 // names are always BOOL 2483 row.set(DataType.name, DBType.BOOL.ordinal()); 2484 row.set(NumericPrecision.name, 255); 2485 row.set(NumericScale.name, 255); 2486 addRow(row, rows); 2487 */ 2488 Property[] props = level.getProperties(); 2489 for (Property prop : props) { 2490 String propName = prop.getName(); 2491 2492 row = new Row(); 2493 row.set(TableCatalog.name, schemaName); 2494 row.set(TableName.name, cubeName); 2495 row.set(ColumnName.name, 2496 hierarchyName + ':' + levelName + '!' + propName); 2497 row.set(OrdinalPosition.name, ordinalPosition++); 2498 row.set(ColumnHasDefault.name, false); 2499 row.set(ColumnFlags.name, 0); 2500 row.set(IsNullable.name, false); 2501 2502 DBType dbType = getDBTypeFromProperty(prop); 2503 row.set(DataType.name, dbType.userOrdinal); 2504 2505 switch (prop.getType()) { 2506 case TYPE_STRING: 2507 row.set(CharacterMaximumLength.name, 0); 2508 row.set(CharacterOctetLength.name, 0); 2509 break; 2510 case TYPE_NUMERIC: 2511 // TODO: 16/255 seems to be what MS SQL Server 2512 // always returns. 2513 row.set(NumericPrecision.name, 16); 2514 row.set(NumericScale.name, 255); 2515 break; 2516 case TYPE_BOOLEAN: 2517 row.set(NumericPrecision.name, 255); 2518 row.set(NumericScale.name, 255); 2519 break; 2520 case TYPE_OTHER: 2521 // TODO: what type is it really, its 2522 // not a string 2523 row.set(CharacterMaximumLength.name, 0); 2524 row.set(CharacterOctetLength.name, 0); 2525 break; 2526 } 2527 addRow(row, rows); 2528 } 2529 return ordinalPosition; 2530 } 2531 2532 protected void setProperty(PropertyDefinition propertyDef, String value) { 2533 switch (propertyDef) { 2534 case Content: 2535 break; 2536 default: 2537 super.setProperty(propertyDef, value); 2538 } 2539 } 2540 } 2541 2542 static class DbschemaProviderTypesRowset extends Rowset { 2543 private final RestrictionTest dataTypeRT; 2544 2545 DbschemaProviderTypesRowset(XmlaRequest request, XmlaHandler handler) { 2546 super(DBSCHEMA_PROVIDER_TYPES, request, handler); 2547 dataTypeRT = getRestrictionTest(DataType); 2548 } 2549 2550 /* 2551 DATA_TYPE DBTYPE_UI2 2552 BEST_MATCH DBTYPE_BOOL 2553 Column(String name, Type type, Enumeration enumeratedType, 2554 boolean restriction, boolean nullable, String description) 2555 */ 2556 /* 2557 * These are the columns returned by SQL Server. 2558 */ 2559 private static final Column TypeName = 2560 new Column( 2561 "TYPE_NAME", 2562 Type.String, 2563 null, 2564 Column.NOT_RESTRICTION, 2565 Column.REQUIRED, 2566 "The provider-specific data type name."); 2567 private static final Column DataType = 2568 new Column( 2569 "DATA_TYPE", 2570 Type.UnsignedShort, 2571 null, 2572 Column.RESTRICTION, 2573 Column.REQUIRED, 2574 "The indicator of the data type."); 2575 private static final Column ColumnSize = 2576 new Column( 2577 "COLUMN_SIZE", 2578 Type.UnsignedInteger, 2579 null, 2580 Column.NOT_RESTRICTION, 2581 Column.REQUIRED, 2582 "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."); 2583 private static final Column LiteralPrefix = 2584 new Column( 2585 "LITERAL_PREFIX", 2586 Type.String, 2587 null, 2588 Column.NOT_RESTRICTION, 2589 Column.OPTIONAL, 2590 "The character or characters used to prefix a literal of this type in a text command."); 2591 private static final Column LiteralSuffix = 2592 new Column( 2593 "LITERAL_SUFFIX", 2594 Type.String, 2595 null, 2596 Column.NOT_RESTRICTION, 2597 Column.OPTIONAL, 2598 "The character or characters used to suffix a literal of this type in a text command."); 2599 private static final Column IsNullable = 2600 new Column( 2601 "IS_NULLABLE", 2602 Type.Boolean, 2603 null, 2604 Column.NOT_RESTRICTION, 2605 Column.OPTIONAL, 2606 "A Boolean that indicates whether the data type is nullable. NULL-- indicates that it is not known whether the data type is nullable."); 2607 private static final Column CaseSensitive = 2608 new Column( 2609 "CASE_SENSITIVE", 2610 Type.Boolean, 2611 null, 2612 Column.NOT_RESTRICTION, 2613 Column.OPTIONAL, 2614 "A Boolean that indicates whether the data type is a characters type and case-sensitive."); 2615 private static final Column Searchable = 2616 new Column( 2617 "SEARCHABLE", 2618 Type.UnsignedInteger, 2619 null, 2620 Column.NOT_RESTRICTION, 2621 Column.OPTIONAL, 2622 "An integer indicating how the data type can be used in searches if the provider supports ICommandText; otherwise, NULL."); 2623 private static final Column UnsignedAttribute = 2624 new Column( 2625 "UNSIGNED_ATTRIBUTE", 2626 Type.Boolean, 2627 null, 2628 Column.NOT_RESTRICTION, 2629 Column.OPTIONAL, 2630 "A Boolean that indicates whether the data type is unsigned."); 2631 private static final Column FixedPrecScale = 2632 new Column( 2633 "FIXED_PREC_SCALE", 2634 Type.Boolean, 2635 null, 2636 Column.NOT_RESTRICTION, 2637 Column.OPTIONAL, 2638 "A Boolean that indicates whether the data type has a fixed precision and scale."); 2639 private static final Column AutoUniqueValue = 2640 new Column( 2641 "AUTO_UNIQUE_VALUE", 2642 Type.Boolean, 2643 null, 2644 Column.NOT_RESTRICTION, 2645 Column.OPTIONAL, 2646 "A Boolean that indicates whether the data type is autoincrementing."); 2647 private static final Column IsLong = 2648 new Column( 2649 "IS_LONG", 2650 Type.Boolean, 2651 null, 2652 Column.NOT_RESTRICTION, 2653 Column.OPTIONAL, 2654 "A Boolean that indicates whether the data type is a binary large object (BLOB) and has very long data."); 2655 private static final Column BestMatch = 2656 new Column( 2657 "BEST_MATCH", 2658 Type.Boolean, 2659 null, 2660 Column.RESTRICTION, 2661 Column.OPTIONAL, 2662 "A Boolean that indicates whether the data type is a best match."); 2663 2664 public void populate( 2665 XmlaResponse response, 2666 List<Row> rows) 2667 throws XmlaException 2668 { 2669 // Identifies the (base) data types supported by the data provider. 2670 Row row; 2671 2672 // i4 2673 Integer dt = DBType.I4.userOrdinal; 2674 if (dataTypeRT.passes(dt)) { 2675 row = new Row(); 2676 row.set(TypeName.name, DBType.I4.userName); 2677 row.set(DataType.name, dt); 2678 row.set(ColumnSize.name, 8); 2679 row.set(IsNullable.name, true); 2680 row.set(Searchable.name, null); 2681 row.set(UnsignedAttribute.name, false); 2682 row.set(FixedPrecScale.name, false); 2683 row.set(AutoUniqueValue.name, false); 2684 row.set(IsLong.name, false); 2685 row.set(BestMatch.name, true); 2686 addRow(row, rows); 2687 } 2688 2689 // R8 2690 dt = DBType.R8.userOrdinal; 2691 if (dataTypeRT.passes(dt)) { 2692 row = new Row(); 2693 row.set(TypeName.name, DBType.R8.userName); 2694 row.set(DataType.name, dt); 2695 row.set(ColumnSize.name, 16); 2696 row.set(IsNullable.name, true); 2697 row.set(Searchable.name, null); 2698 row.set(UnsignedAttribute.name, false); 2699 row.set(FixedPrecScale.name, false); 2700 row.set(AutoUniqueValue.name, false); 2701 row.set(IsLong.name, false); 2702 row.set(BestMatch.name, true); 2703 addRow(row, rows); 2704 } 2705 2706 // CY 2707 dt = DBType.CY.userOrdinal; 2708 if (dataTypeRT.passes(dt)) { 2709 row = new Row(); 2710 row.set(TypeName.name, DBType.CY.userName); 2711 row.set(DataType.name, dt); 2712 row.set(ColumnSize.name, 8); 2713 row.set(IsNullable.name, true); 2714 row.set(Searchable.name, null); 2715 row.set(UnsignedAttribute.name, false); 2716 row.set(FixedPrecScale.name, false); 2717 row.set(AutoUniqueValue.name, false); 2718 row.set(IsLong.name, false); 2719 row.set(BestMatch.name, true); 2720 addRow(row, rows); 2721 } 2722 2723 // BOOL 2724 dt = DBType.BOOL.userOrdinal; 2725 if (dataTypeRT.passes(dt)) { 2726 row = new Row(); 2727 row.set(TypeName.name, DBType.BOOL.userName); 2728 row.set(DataType.name, dt); 2729 row.set(ColumnSize.name, 1); 2730 row.set(IsNullable.name, true); 2731 row.set(Searchable.name, null); 2732 row.set(UnsignedAttribute.name, false); 2733 row.set(FixedPrecScale.name, false); 2734 row.set(AutoUniqueValue.name, false); 2735 row.set(IsLong.name, false); 2736 row.set(BestMatch.name, true); 2737 addRow(row, rows); 2738 } 2739 2740 // I8 2741 dt = DBType.I8.userOrdinal; 2742 if (dataTypeRT.passes(dt)) { 2743 row = new Row(); 2744 row.set(TypeName.name, DBType.I8.userName); 2745 row.set(DataType.name, dt); 2746 row.set(ColumnSize.name, 16); 2747 row.set(IsNullable.name, true); 2748 row.set(Searchable.name, null); 2749 row.set(UnsignedAttribute.name, false); 2750 row.set(FixedPrecScale.name, false); 2751 row.set(AutoUniqueValue.name, false); 2752 row.set(IsLong.name, false); 2753 row.set(BestMatch.name, true); 2754 addRow(row, rows); 2755 } 2756 2757 // WSTR 2758 dt = DBType.WSTR.userOrdinal; 2759 if (dataTypeRT.passes(dt)) { 2760 row = new Row(); 2761 row.set(TypeName.name, DBType.WSTR.userName); 2762 row.set(DataType.name, dt); 2763 // how big are the string columns in the db 2764 row.set(ColumnSize.name, 255); 2765 row.set(LiteralPrefix.name, "\""); 2766 row.set(LiteralSuffix.name, "\""); 2767 row.set(IsNullable.name, true); 2768 row.set(CaseSensitive.name, false); 2769 row.set(Searchable.name, null); 2770 row.set(FixedPrecScale.name, false); 2771 row.set(AutoUniqueValue.name, false); 2772 row.set(IsLong.name, false); 2773 row.set(BestMatch.name, true); 2774 addRow(row, rows); 2775 } 2776 } 2777 2778 protected void setProperty(PropertyDefinition propertyDef, String value) { 2779 switch (propertyDef) { 2780 case Content: 2781 break; 2782 default: 2783 super.setProperty(propertyDef, value); 2784 } 2785 } 2786 } 2787 2788 static class DbschemaSchemataRowset extends Rowset { 2789 private final RestrictionTest catalogNameRT; 2790 2791 DbschemaSchemataRowset(XmlaRequest request, XmlaHandler handler) { 2792 super(DBSCHEMA_SCHEMATA, request, handler); 2793 catalogNameRT = getRestrictionTest(CatalogName); 2794 } 2795 2796 /* 2797 * These are the columns returned by SQL Server. 2798 */ 2799 private static final Column CatalogName = 2800 new Column( 2801 "CATALOG_NAME", 2802 Type.String, 2803 null, 2804 Column.RESTRICTION, 2805 Column.REQUIRED, 2806 "The provider-specific data type name."); 2807 private static final Column SchemaName = 2808 new Column( 2809 "SCHEMA_NAME", 2810 Type.String, 2811 null, 2812 Column.RESTRICTION, 2813 Column.REQUIRED, 2814 "The indicator of the data type."); 2815 private static final Column SchemaOwner = 2816 new Column( 2817 "SCHEMA_OWNER", 2818 Type.String, 2819 null, 2820 Column.RESTRICTION, 2821 Column.REQUIRED, 2822 "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."); 2823 2824 public void populate( 2825 XmlaResponse response, 2826 List<Row> rows) 2827 throws XmlaException 2828 { 2829 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 2830 DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs; 2831 String roleName = request.getRoleName(); 2832 Role role = request.getRole(); 2833 2834 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 2835 if (dsCatalog == null || dsCatalog.definition == null) { 2836 continue; 2837 } 2838 Connection connection = 2839 handler.getConnection(dsCatalog, role, roleName); 2840 if (connection == null) { 2841 continue; 2842 } 2843 if (!catalogNameRT.passes(dsCatalog.name)) { 2844 continue; 2845 } 2846 final Schema schema = connection.getSchema(); 2847 Row row = new Row(); 2848 row.set(CatalogName.name, dsCatalog.name); 2849 row.set(SchemaName.name, schema.getName()); 2850 row.set(SchemaOwner.name, ""); 2851 addRow(row, rows); 2852 } 2853 } 2854 2855 protected void setProperty(PropertyDefinition propertyDef, String value) { 2856 switch (propertyDef) { 2857 case Content: 2858 break; 2859 default: 2860 super.setProperty(propertyDef, value); 2861 } 2862 } 2863 } 2864 2865 static class DbschemaTablesRowset extends Rowset { 2866 private final RestrictionTest tableCatalogRT; 2867 private final RestrictionTest tableNameRT; 2868 private final RestrictionTest tableTypeRT; 2869 2870 DbschemaTablesRowset(XmlaRequest request, XmlaHandler handler) { 2871 super(DBSCHEMA_TABLES, request, handler); 2872 tableCatalogRT = getRestrictionTest(TableCatalog); 2873 tableNameRT = getRestrictionTest(TableName); 2874 tableTypeRT = getRestrictionTest(TableType); 2875 } 2876 2877 private static final Column TableCatalog = 2878 new Column( 2879 "TABLE_CATALOG", 2880 Type.String, 2881 null, 2882 Column.RESTRICTION, 2883 Column.REQUIRED, 2884 "The name of the catalog to which this object belongs."); 2885 private static final Column TableSchema = 2886 new Column( 2887 "TABLE_SCHEMA", 2888 Type.String, 2889 null, 2890 Column.RESTRICTION, 2891 Column.OPTIONAL, 2892 "The name of the cube to which this object belongs."); 2893 private static final Column TableName = 2894 new Column( 2895 "TABLE_NAME", 2896 Type.String, 2897 null, 2898 Column.RESTRICTION, 2899 Column.REQUIRED, 2900 "The name of the object, if TABLE_TYPE is TABLE."); 2901 private static final Column TableType = 2902 new Column( 2903 "TABLE_TYPE", 2904 Type.String, 2905 null, 2906 Column.RESTRICTION, 2907 Column.REQUIRED, 2908 "The type of the table. TABLE indicates the object is a measure group. SYSTEM TABLE indicates the object is a dimension."); 2909 2910 private static final Column TableGuid = 2911 new Column( 2912 "TABLE_GUID", 2913 Type.UUID, 2914 null, 2915 Column.NOT_RESTRICTION, 2916 Column.OPTIONAL, 2917 "Not supported."); 2918 private static final Column Description = 2919 new Column( 2920 "DESCRIPTION", 2921 Type.String, 2922 null, 2923 Column.NOT_RESTRICTION, 2924 Column.OPTIONAL, 2925 "A human-readable description of the object."); 2926 private static final Column TablePropId = 2927 new Column( 2928 "TABLE_PROPID", 2929 Type.UnsignedInteger, 2930 null, 2931 Column.NOT_RESTRICTION, 2932 Column.OPTIONAL, 2933 "Not supported."); 2934 private static final Column DateCreated = 2935 new Column( 2936 "DATE_CREATED", 2937 Type.DateTime, 2938 null, 2939 Column.NOT_RESTRICTION, 2940 Column.OPTIONAL, 2941 "Not supported."); 2942 private static final Column DateModified = 2943 new Column( 2944 "DATE_MODIFIED", 2945 Type.DateTime, 2946 null, 2947 Column.NOT_RESTRICTION, 2948 Column.OPTIONAL, 2949 "The date the object was last modified."); 2950 2951 /* 2952 private static final Column TableOlapType = 2953 new Column( 2954 "TABLE_OLAP_TYPE", 2955 Type.String, 2956 null, 2957 Column.RESTRICTION, 2958 Column.OPTIONAL, 2959 "The OLAP type of the object. MEASURE_GROUP indicates the object is a measure group. CUBE_DIMENSION indicated the object is a dimension."); 2960 */ 2961 2962 public void populate( 2963 XmlaResponse response, 2964 List<Row> rows) 2965 throws XmlaException 2966 { 2967 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 2968 DataSourcesConfig.Catalog[] catalogs = 2969 handler.getCatalogs(request, ds); 2970 String roleName = request.getRoleName(); 2971 Role role = request.getRole(); 2972 2973 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 2974 if (dsCatalog == null || dsCatalog.definition == null) { 2975 continue; 2976 } 2977 Connection connection = 2978 handler.getConnection(dsCatalog, role, roleName); 2979 if (connection == null) { 2980 continue; 2981 } 2982 final Schema schema = connection.getSchema(); 2983 String catalogName = dsCatalog.name; 2984 if (!tableCatalogRT.passes(catalogName)) { 2985 continue; 2986 } 2987 2988 //final String schemaName = schema.getName(); 2989 2990 Row row; 2991 for (Cube cube1 : sortedCubes(schema)) { 2992 RolapCube cube = (RolapCube) cube1; 2993 String cubeName = cube.getName(); 2994 2995 if (!tableNameRT.passes(cubeName)) { 2996 continue; 2997 } 2998 SchemaReader schemaReader = 2999 cube.getSchemaReader( 3000 connection.getRole()); 3001 3002 String desc = cube.getDescription(); 3003 if (desc == null) { 3004 //TODO: currently this is always null 3005 desc = catalogName + " - " + cubeName + " Cube"; 3006 } 3007 3008 3009 if (tableTypeRT.passes("TABLE")) { 3010 row = new Row(); 3011 row.set(TableCatalog.name, catalogName); 3012 row.set(TableName.name, cubeName); 3013 row.set(TableType.name, "TABLE"); 3014 row.set(Description.name, desc); 3015 if (false) { 3016 row.set(DateModified.name, dateModified); 3017 } 3018 addRow(row, rows); 3019 } 3020 3021 3022 if (tableTypeRT.passes("SYSTEM TABLE")) { 3023 for (Dimension dimension : cube.getDimensions()) { 3024 if (dimension.isMeasures()) { 3025 continue; 3026 } 3027 Hierarchy[] hierarchies = 3028 dimension.getHierarchies(); 3029 for (Hierarchy hierarchy1 : hierarchies) { 3030 HierarchyBase hierarchy = 3031 (HierarchyBase) hierarchy1; 3032 populateHierarchy(schemaReader, cube, 3033 hierarchy, rows); 3034 } 3035 } 3036 } 3037 } 3038 } 3039 } 3040 3041 private void populateHierarchy( 3042 SchemaReader schemaReader, 3043 RolapCube cube, 3044 HierarchyBase hierarchy, 3045 List<Row> rows) 3046 { 3047 // Access control 3048 if (!canAccess(schemaReader, hierarchy)) { 3049 return; 3050 } 3051 /* 3052 String schemaName = cube.getSchema().getName(); 3053 String cubeName = cube.getName(); 3054 String hierarchyName = hierarchy.getName(); 3055 3056 String desc = hierarchy.getDescription(); 3057 if (desc == null) { 3058 //TODO: currently this is always null 3059 desc = schemaName + 3060 " - " + 3061 cubeName + 3062 " Cube - " + 3063 hierarchyName + 3064 " Hierarchy"; 3065 } 3066 3067 if (hierarchy.hasAll()) { 3068 String tableName = cubeName + 3069 ':' + hierarchyName + ':' + "(All)"; 3070 3071 Row row = new Row(); 3072 row.set(TableCatalog.name, schemaName); 3073 row.set(TableName.name, tableName); 3074 row.set(TableType.name, "SYSTEM TABLE"); 3075 row.set(Description.name, desc); 3076 row.set(DateModified.name, dateModified); 3077 addRow(row, rows); 3078 } 3079 */ 3080 Level[] levels = hierarchy.getLevels(); 3081 for (Level level : levels) { 3082 populateLevel(cube, hierarchy, level, rows); 3083 } 3084 } 3085 3086 private void populateLevel( 3087 RolapCube cube, 3088 HierarchyBase hierarchy, 3089 Level level, 3090 List<Row> rows) 3091 { 3092 String schemaName = cube.getSchema().getName(); 3093 String cubeName = cube.getName(); 3094 String hierarchyName = hierarchy.getName(); 3095 String levelName = level.getName(); 3096 3097 String tableName = cubeName + 3098 ':' + hierarchyName + ':' + levelName; 3099 3100 String desc = level.getDescription(); 3101 if (desc == null) { 3102 //TODO: currently this is always null 3103 desc = schemaName + 3104 " - " + 3105 cubeName + 3106 " Cube - " + 3107 hierarchyName + 3108 " Hierarchy - " + 3109 levelName + 3110 " Level"; 3111 } 3112 3113 Row row = new Row(); 3114 row.set(TableCatalog.name, schemaName); 3115 row.set(TableName.name, tableName); 3116 row.set(TableType.name, "SYSTEM TABLE"); 3117 row.set(Description.name, desc); 3118 if (false) { 3119 row.set(DateModified.name, dateModified); 3120 } 3121 addRow(row, rows); 3122 } 3123 3124 protected void setProperty(PropertyDefinition propertyDef, String value) { 3125 switch (propertyDef) { 3126 case Content: 3127 break; 3128 default: 3129 super.setProperty(propertyDef, value); 3130 } 3131 } 3132 } 3133 3134 // TODO: Is this needed???? 3135 static class DbschemaTablesInfoRowset extends Rowset { 3136 DbschemaTablesInfoRowset(XmlaRequest request, XmlaHandler handler) { 3137 super(DBSCHEMA_TABLES_INFO, request, handler); 3138 } 3139 3140 private static final Column TableCatalog = 3141 new Column( 3142 "TABLE_CATALOG", 3143 Type.String, 3144 null, 3145 Column.RESTRICTION, 3146 Column.OPTIONAL, 3147 "Catalog name. NULL if the provider does not support catalogs."); 3148 private static final Column TableSchema = 3149 new Column( 3150 "TABLE_SCHEMA", 3151 Type.String, 3152 null, 3153 Column.RESTRICTION, 3154 Column.OPTIONAL, 3155 "Unqualified schema name. NULL if the provider does not support schemas."); 3156 private static final Column TableName = 3157 new Column( 3158 "TABLE_NAME", 3159 Type.String, 3160 null, 3161 Column.RESTRICTION, 3162 Column.REQUIRED, 3163 "Table name."); 3164 private static final Column TableType = 3165 new Column( 3166 "TABLE_TYPE", 3167 Type.String, 3168 null, 3169 Column.RESTRICTION, 3170 Column.REQUIRED, 3171 "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"); 3172 private static final Column TableGuid = 3173 new Column( 3174 "TABLE_GUID", 3175 Type.UUID, 3176 null, 3177 Column.NOT_RESTRICTION, 3178 Column.OPTIONAL, 3179 "GUID that uniquely identifies the table. Providers that do not use GUIDs to identify tables should return NULL in this column."); 3180 3181 private static final Column Bookmarks = 3182 new Column( 3183 "BOOKMARKS", 3184 Type.Boolean, 3185 null, 3186 Column.NOT_RESTRICTION, 3187 Column.REQUIRED, 3188 "Whether this table supports bookmarks. Allways is false."); 3189 private static final Column BookmarkType = 3190 new Column( 3191 "BOOKMARK_TYPE", 3192 Type.Integer, 3193 null, 3194 Column.NOT_RESTRICTION, 3195 Column.OPTIONAL, 3196 "Default bookmark type supported on this table."); 3197 private static final Column BookmarkDataType = 3198 new Column( 3199 "BOOKMARK_DATATYPE", 3200 Type.UnsignedShort, 3201 null, 3202 Column.NOT_RESTRICTION, 3203 Column.OPTIONAL, 3204 "The indicator of the bookmark's native data type."); 3205 private static final Column BookmarkMaximumLength = 3206 new Column( 3207 "BOOKMARK_MAXIMUM_LENGTH", 3208 Type.UnsignedInteger, 3209 null, 3210 Column.NOT_RESTRICTION, 3211 Column.OPTIONAL, 3212 "Maximum length of the bookmark in bytes."); 3213 private static final Column BookmarkInformation = 3214 new Column( 3215 "BOOKMARK_INFORMATION", 3216 Type.UnsignedInteger, 3217 null, 3218 Column.NOT_RESTRICTION, 3219 Column.OPTIONAL, 3220 "A bitmask specifying additional information about bookmarks over the rowset. "); 3221 private static final Column TableVersion = 3222 new Column( 3223 "TABLE_VERSION", 3224 Type.Long, 3225 null, 3226 Column.NOT_RESTRICTION, 3227 Column.OPTIONAL, 3228 "Version number for this table or NULL if the provider does not support returning table version information."); 3229 private static final Column Cardinality = 3230 new Column( 3231 "CARDINALITY", 3232 Type.UnsignedLong, 3233 null, 3234 Column.NOT_RESTRICTION, 3235 Column.REQUIRED, 3236 "Cardinality (number of rows) of the table."); 3237 private static final Column Description = 3238 new Column( 3239 "DESCRIPTION", 3240 Type.String, 3241 null, 3242 Column.NOT_RESTRICTION, 3243 Column.OPTIONAL, 3244 "Human-readable description of the table."); 3245 private static final Column TablePropId = 3246 new Column( 3247 "TABLE_PROPID", 3248 Type.UnsignedInteger, 3249 null, 3250 Column.NOT_RESTRICTION, 3251 Column.OPTIONAL, 3252 "Property ID of the table. Return null."); 3253 3254 public void populate( 3255 XmlaResponse response, 3256 List<Row> rows) 3257 throws XmlaException 3258 { 3259 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 3260 DataSourcesConfig.Catalog[] catalogs = 3261 handler.getCatalogs(request, ds); 3262 String roleName = request.getRoleName(); 3263 Role role = request.getRole(); 3264 3265 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 3266 if (dsCatalog == null || dsCatalog.definition == null) { 3267 continue; 3268 } 3269 Connection connection = 3270 handler.getConnection(dsCatalog, role, roleName); 3271 if (connection == null) { 3272 continue; 3273 } 3274 final Schema schema = connection.getSchema(); 3275 String catalogName = dsCatalog.name; 3276 //final String catalogName = schema.getName(); 3277 3278 //TODO: Is this cubes or tables? SQL Server returns what 3279 // in foodmart are cube names for TABLE_NAME 3280 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/oledb/htm/oledbtables_info_rowset.asp 3281 for (Cube cube1 : sortedCubes(schema)) { 3282 RolapCube cube = (RolapCube) cube1; 3283 String cubeName = cube.getName(); 3284 String desc = cube.getDescription(); 3285 if (desc == null) { 3286 //TODO: currently this is always null 3287 desc = catalogName + " - " + cubeName + " Cube"; 3288 } 3289 //TODO: SQL Server returns 1000000 for all tables 3290 int cardinality = 1000000; 3291 String version = "null"; 3292 3293 Row row = new Row(); 3294 row.set(TableCatalog.name, catalogName); 3295 row.set(TableName.name, cubeName); 3296 row.set(TableType.name, "TABLE"); 3297 row.set(Bookmarks.name, false); 3298 row.set(TableVersion.name, version); 3299 row.set(Cardinality.name, cardinality); 3300 row.set(Description.name, desc); 3301 addRow(row, rows); 3302 } 3303 } 3304 } 3305 3306 protected void setProperty(PropertyDefinition propertyDef, String value) { 3307 switch (propertyDef) { 3308 case Content: 3309 break; 3310 default: 3311 super.setProperty(propertyDef, value); 3312 } 3313 } 3314 } 3315 3316 static class MdschemaActionsRowset extends Rowset { 3317 MdschemaActionsRowset(XmlaRequest request, XmlaHandler handler) { 3318 super(MDSCHEMA_ACTIONS, request, handler); 3319 } 3320 3321 private static final Column SchemaName = 3322 new Column( 3323 "SCHEMA_NAME", 3324 Type.String, 3325 null, 3326 Column.RESTRICTION, 3327 Column.OPTIONAL, 3328 "The name of the schema to which this action belongs."); 3329 private static final Column CubeName = 3330 new Column( 3331 "CUBE_NAME", 3332 Type.String, 3333 null, 3334 Column.RESTRICTION, 3335 Column.REQUIRED, 3336 "The name of the cube to which this action belongs."); 3337 private static final Column ActionName = 3338 new Column( 3339 "ACTION_NAME", 3340 Type.String, 3341 null, 3342 Column.RESTRICTION, 3343 Column.REQUIRED, 3344 "The name of the action."); 3345 private static final Column Coordinate = 3346 new Column( 3347 "COORDINATE", 3348 Type.String, 3349 null, 3350 Column.RESTRICTION, 3351 Column.REQUIRED, 3352 null); 3353 private static final Column CoordinateType = 3354 new Column( 3355 "COORDINATE_TYPE", 3356 Type.Integer, 3357 null, 3358 Column.RESTRICTION, 3359 Column.REQUIRED, 3360 null); 3361 /* 3362 TODO: optional columns 3363 ACTION_TYPE 3364 INVOCATION 3365 CUBE_SOURCE 3366 */ 3367 3368 public void populate( 3369 XmlaResponse response, 3370 List<Row> rows) 3371 throws XmlaException 3372 { 3373 // mondrian doesn't support actions. It's not an error to ask for 3374 // them, there just aren't any 3375 } 3376 } 3377 3378 // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapcubes_rowset.asp 3379 static class MdschemaCubesRowset extends Rowset { 3380 private final RestrictionTest catalogNameRT; 3381 private final RestrictionTest schemaNameRT; 3382 private final RestrictionTest cubeNameRT; 3383 3384 MdschemaCubesRowset(XmlaRequest request, XmlaHandler handler) { 3385 super(MDSCHEMA_CUBES, request, handler); 3386 catalogNameRT = getRestrictionTest(CatalogName); 3387 schemaNameRT = getRestrictionTest(SchemaName); 3388 cubeNameRT = getRestrictionTest(CubeName); 3389 } 3390 3391 private static final String MD_CUBTYPE_CUBE = "CUBE"; 3392 private static final String MD_CUBTYPE_VIRTUAL_CUBE = "VIRTUAL CUBE"; 3393 3394 private static final Column CatalogName = 3395 new Column( 3396 "CATALOG_NAME", 3397 Type.String, 3398 null, 3399 Column.RESTRICTION, 3400 Column.OPTIONAL, 3401 "The name of the catalog to which this cube belongs."); 3402 private static final Column SchemaName = 3403 new Column( 3404 "SCHEMA_NAME", 3405 Type.String, 3406 null, 3407 Column.RESTRICTION, 3408 Column.OPTIONAL, 3409 "The name of the schema to which this cube belongs."); 3410 private static final Column CubeName = 3411 new Column( 3412 "CUBE_NAME", 3413 Type.String, 3414 null, 3415 Column.RESTRICTION, 3416 Column.REQUIRED, 3417 "Name of the cube."); 3418 private static final Column CubeType = 3419 new Column( 3420 "CUBE_TYPE", 3421 Type.String, 3422 null, 3423 Column.RESTRICTION, 3424 Column.REQUIRED, 3425 "Cube type."); 3426 private static final Column CubeGuid = 3427 new Column( 3428 "CUBE_GUID", 3429 Type.UUID, 3430 null, 3431 Column.NOT_RESTRICTION, 3432 Column.OPTIONAL, 3433 "Cube type."); 3434 private static final Column CreatedOn = 3435 new Column( 3436 "CREATED_ON", 3437 Type.DateTime, 3438 null, 3439 Column.NOT_RESTRICTION, 3440 Column.OPTIONAL, 3441 "Date and time of cube creation."); 3442 private static final Column LastSchemaUpdate = 3443 new Column( 3444 "LAST_SCHEMA_UPDATE", 3445 Type.DateTime, 3446 null, 3447 Column.NOT_RESTRICTION, 3448 Column.OPTIONAL, 3449 "Date and time of last schema update."); 3450 private static final Column SchemaUpdatedBy = 3451 new Column( 3452 "SCHEMA_UPDATED_BY", 3453 Type.String, 3454 null, 3455 Column.NOT_RESTRICTION, 3456 Column.OPTIONAL, 3457 "User ID of the person who last updated the schema."); 3458 private static final Column LastDataUpdate = 3459 new Column( 3460 "LAST_DATA_UPDATE", 3461 Type.DateTime, 3462 null, 3463 Column.NOT_RESTRICTION, 3464 Column.OPTIONAL, 3465 "Date and time of last data update."); 3466 private static final Column DataUpdatedBy = 3467 new Column( 3468 "DATA_UPDATED_BY", 3469 Type.String, 3470 null, 3471 Column.NOT_RESTRICTION, 3472 Column.OPTIONAL, 3473 "User ID of the person who last updated the data. "); 3474 private static final Column IsDrillthroughEnabled = 3475 new Column( 3476 "IS_DRILLTHROUGH_ENABLED", 3477 Type.Boolean, 3478 null, 3479 Column.NOT_RESTRICTION, 3480 Column.REQUIRED, 3481 "Describes whether DRILLTHROUGH can be performed on the members of a cube"); 3482 private static final Column IsWriteEnabled = 3483 new Column( 3484 "IS_WRITE_ENABLED", 3485 Type.Boolean, 3486 null, 3487 Column.NOT_RESTRICTION, 3488 Column.REQUIRED, 3489 "Describes whether a cube is write-enabled"); 3490 private static final Column IsLinkable = 3491 new Column( 3492 "IS_LINKABLE", 3493 Type.Boolean, 3494 null, 3495 Column.NOT_RESTRICTION, 3496 Column.REQUIRED, 3497 "Describes whether a cube can be used in a linked cube"); 3498 private static final Column IsSqlEnabled = 3499 new Column( 3500 "IS_SQL_ENABLED", 3501 Type.Boolean, 3502 null, 3503 Column.NOT_RESTRICTION, 3504 Column.REQUIRED, 3505 "Describes whether or not SQL can be used on the cube"); 3506 private static final Column Description = 3507 new Column( 3508 "DESCRIPTION", 3509 Type.String, 3510 null, 3511 Column.NOT_RESTRICTION, 3512 Column.OPTIONAL, 3513 "A user-friendly description of the dimension."); 3514 3515 public void populate( 3516 XmlaResponse response, 3517 List<Row> rows) 3518 throws XmlaException 3519 { 3520 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 3521 DataSourcesConfig.Catalog[] catalogs = 3522 handler.getCatalogs(request, ds); 3523 String roleName = request.getRoleName(); 3524 Role role = request.getRole(); 3525 3526 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 3527 if (dsCatalog == null || dsCatalog.definition == null) { 3528 continue; 3529 } 3530 Connection connection = 3531 handler.getConnection(dsCatalog, role, roleName); 3532 if (connection == null) { 3533 continue; 3534 } 3535 String catalogName = dsCatalog.name; 3536 if (!catalogNameRT.passes(catalogName)) { 3537 continue; 3538 } 3539 3540 final Schema schema = connection.getSchema(); 3541 if (!schemaNameRT.passes(schema.getName())) { 3542 continue; 3543 } 3544 for (Cube cube : sortedCubes(schema)) { 3545 // Access control 3546 if (!canAccess(schema.getSchemaReader(), cube)) { 3547 continue; 3548 } 3549 if (!cubeNameRT.passes(cube.getName())) { 3550 continue; 3551 } 3552 3553 String desc = cube.getDescription(); 3554 if (desc == null) { 3555 desc = catalogName + 3556 " Schema - " + 3557 cube.getName() + 3558 " Cube"; 3559 } 3560 3561 Row row = new Row(); 3562 row.set(CatalogName.name, catalogName); 3563 row.set(SchemaName.name, schema.getName()); 3564 row.set(CubeName.name, cube.getName()); 3565 row.set(CubeType.name, 3566 ((RolapCube) cube).isVirtual() 3567 ? MD_CUBTYPE_VIRTUAL_CUBE : MD_CUBTYPE_CUBE); 3568 //row.set(CubeGuid.name, ""); 3569 //row.set(CreatedOn.name, ""); 3570 //row.set(LastSchemaUpdate.name, ""); 3571 //row.set(SchemaUpdatedBy.name, ""); 3572 //row.set(LastDataUpdate.name, ""); 3573 //row.set(DataUpdatedBy.name, ""); 3574 row.set(IsDrillthroughEnabled.name, true); 3575 row.set(IsWriteEnabled.name, false); 3576 row.set(IsLinkable.name, false); 3577 row.set(IsSqlEnabled.name, false); 3578 row.set(Description.name, desc); 3579 Format formatter = 3580 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 3581 String formattedDate = 3582 formatter.format(schema.getSchemaLoadDate()); 3583 row.set(LastSchemaUpdate.name, formattedDate); 3584 addRow(row, rows); 3585 } 3586 } 3587 } 3588 3589 protected void setProperty(PropertyDefinition propertyDef, String value) { 3590 switch (propertyDef) { 3591 case Content: 3592 break; 3593 default: 3594 super.setProperty(propertyDef, value); 3595 } 3596 } 3597 } 3598 3599 // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapdimensions_rowset.asp 3600 static class MdschemaDimensionsRowset extends Rowset { 3601 private final RestrictionTest catalogRT; 3602 private final RestrictionTest schemaNameRT; 3603 private final RestrictionTest cubeNameRT; 3604 private final RestrictionTest dimensionUniqueNameRT; 3605 private final RestrictionTest dimensionNameRT; 3606 3607 MdschemaDimensionsRowset(XmlaRequest request, XmlaHandler handler) { 3608 super(MDSCHEMA_DIMENSIONS, request, handler); 3609 catalogRT = getRestrictionTest(CatalogName); 3610 schemaNameRT = getRestrictionTest(SchemaName); 3611 cubeNameRT = getRestrictionTest(CubeName); 3612 dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName); 3613 dimensionNameRT = getRestrictionTest(DimensionName); 3614 } 3615 3616 public static final int MD_DIMTYPE_OTHER = 3; 3617 public static final int MD_DIMTYPE_MEASURE = 2; 3618 public static final int MD_DIMTYPE_TIME = 1; 3619 3620 private static final Column CatalogName = 3621 new Column( 3622 "CATALOG_NAME", 3623 Type.String, 3624 null, 3625 Column.RESTRICTION, 3626 Column.OPTIONAL, 3627 "The name of the database."); 3628 private static final Column SchemaName = 3629 new Column( 3630 "SCHEMA_NAME", 3631 Type.String, 3632 null, 3633 Column.RESTRICTION, 3634 Column.OPTIONAL, 3635 "Not supported."); 3636 private static final Column CubeName = 3637 new Column( 3638 "CUBE_NAME", 3639 Type.String, 3640 null, 3641 Column.RESTRICTION, 3642 Column.REQUIRED, 3643 "The name of the cube."); 3644 private static final Column DimensionName = 3645 new Column( 3646 "DIMENSION_NAME", 3647 Type.String, 3648 null, 3649 Column.RESTRICTION, 3650 Column.REQUIRED, 3651 "The name of the dimension. "); 3652 private static final Column DimensionUniqueName = 3653 new Column( 3654 "DIMENSION_UNIQUE_NAME", 3655 Type.String, 3656 null, 3657 Column.RESTRICTION, 3658 Column.REQUIRED, 3659 "The unique name of the dimension."); 3660 private static final Column DimensionGuid = 3661 new Column( 3662 "DIMENSION_GUID", 3663 Type.UUID, 3664 null, 3665 Column.NOT_RESTRICTION, 3666 Column.OPTIONAL, 3667 "Not supported."); 3668 private static final Column DimensionCaption = 3669 new Column( 3670 "DIMENSION_CAPTION", 3671 Type.String, 3672 null, 3673 Column.NOT_RESTRICTION, 3674 Column.REQUIRED, 3675 "The caption of the dimension."); 3676 private static final Column DimensionOrdinal = 3677 new Column( 3678 "DIMENSION_ORDINAL", 3679 Type.UnsignedInteger, 3680 null, 3681 Column.NOT_RESTRICTION, 3682 Column.REQUIRED, 3683 "The position of the dimension within the cube."); 3684 /* 3685 * SQL Server returns values: 3686 * MD_DIMTYPE_TIME (1) 3687 * MD_DIMTYPE_MEASURE (2) 3688 * MD_DIMTYPE_OTHER (3) 3689 */ 3690 private static final Column DimensionType = 3691 new Column( 3692 "DIMENSION_TYPE", 3693 Type.Short, 3694 null, 3695 Column.NOT_RESTRICTION, 3696 Column.REQUIRED, 3697 "The type of the dimension."); 3698 private static final Column DimensionCardinality = 3699 new Column( 3700 "DIMENSION_CARDINALITY", 3701 Type.UnsignedInteger, 3702 null, 3703 Column.NOT_RESTRICTION, 3704 Column.REQUIRED, 3705 "The number of members in the key attribute."); 3706 private static final Column DefaultHierarchy = 3707 new Column( 3708 "DEFAULT_HIERARCHY", 3709 Type.String, 3710 null, 3711 Column.NOT_RESTRICTION, 3712 Column.REQUIRED, 3713 "A hierarchy from the dimension. Preserved for backwards compatibility."); 3714 private static final Column Description = 3715 new Column( 3716 "DESCRIPTION", 3717 Type.String, 3718 null, 3719 Column.NOT_RESTRICTION, 3720 Column.OPTIONAL, 3721 "A user-friendly description of the dimension."); 3722 private static final Column IsVirtual = 3723 new Column( 3724 "IS_VIRTUAL", 3725 Type.Boolean, 3726 null, 3727 Column.NOT_RESTRICTION, 3728 Column.OPTIONAL, 3729 "Always FALSE."); 3730 private static final Column IsReadWrite = 3731 new Column("IS_READWRITE", 3732 Type.Boolean, 3733 null, 3734 Column.NOT_RESTRICTION, 3735 Column.OPTIONAL, 3736 "A Boolean that indicates whether the dimension is write-enabled."); 3737 /* 3738 * SQL Server returns values: 0 or 1 3739 */ 3740 private static final Column DimensionUniqueSettings = 3741 new Column( 3742 "DIMENSION_UNIQUE_SETTINGS", 3743 Type.Integer, 3744 null, 3745 Column.NOT_RESTRICTION, 3746 Column.OPTIONAL, 3747 "A bitmap that specifies which columns contain unique values if the dimension contains only members with unique names."); 3748 private static final Column DimensionMasterUniqueName = 3749 new Column( 3750 "DIMENSION_MASTER_UNIQUE_NAME", 3751 Type.String, 3752 null, 3753 Column.NOT_RESTRICTION, 3754 Column.OPTIONAL, 3755 "Always NULL."); 3756 private static final Column DimensionIsVisible = 3757 new Column( 3758 "DIMENSION_IS_VISIBLE", 3759 Type.Boolean, 3760 null, 3761 Column.NOT_RESTRICTION, 3762 Column.OPTIONAL, 3763 "Always TRUE."); 3764 3765 public void populate( 3766 XmlaResponse response, 3767 List<Row> rows) 3768 throws XmlaException 3769 { 3770 DataSourcesConfig.DataSource ds = 3771 handler.getDataSource(request); 3772 DataSourcesConfig.Catalog[] catalogs = 3773 handler.getCatalogs(request, ds); 3774 String roleName = request.getRoleName(); 3775 Role role = request.getRole(); 3776 3777 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 3778 if (dsCatalog == null || dsCatalog.definition == null) { 3779 continue; 3780 } 3781 String catalogName = dsCatalog.name; 3782 if (!catalogRT.passes(catalogName)) { 3783 continue; 3784 } 3785 3786 Connection connection = 3787 handler.getConnection(dsCatalog, role, roleName); 3788 if (connection == null) { 3789 continue; 3790 } 3791 populateCatalog(connection, catalogName, rows); 3792 } 3793 } 3794 3795 protected void populateCatalog( 3796 Connection connection, 3797 String catalogName, 3798 List<Row> rows) 3799 throws XmlaException 3800 { 3801 Schema schema = connection.getSchema(); 3802 if (!schemaNameRT.passes(schema.getName())) { 3803 return; 3804 } 3805 for (Cube cube : sortedCubes(schema)) { 3806 if (!cubeNameRT.passes(cube.getName())) { 3807 continue; 3808 } 3809 SchemaReader schemaReader = 3810 cube.getSchemaReader( 3811 connection.getRole()); 3812 populateCube(schemaReader, catalogName, cube, rows); 3813 } 3814 } 3815 3816 protected void populateCube( 3817 SchemaReader schemaReader, 3818 String catalogName, 3819 Cube cube, 3820 List<Row> rows) 3821 throws XmlaException 3822 { 3823 for (Dimension dimension : cube.getDimensions()) { 3824 String name = dimension.getName(); 3825 String unique = dimension.getUniqueName(); 3826 if (dimensionNameRT.passes(name) && 3827 dimensionUniqueNameRT.passes(unique)) { 3828 populateDimension(schemaReader, catalogName, 3829 cube, dimension, rows); 3830 } 3831 } 3832 } 3833 3834 protected void populateDimension( 3835 SchemaReader schemaReader, 3836 String catalogName, 3837 Cube cube, 3838 Dimension dimension, 3839 List<Row> rows) 3840 throws XmlaException 3841 { 3842 // Access control 3843 if (!canAccess(schemaReader, dimension)) { 3844 return; 3845 } 3846 3847 String desc = dimension.getDescription(); 3848 if (desc == null) { 3849 desc = cube.getName() + 3850 " Cube - " + 3851 dimension.getName() + 3852 " Dimension"; 3853 } 3854 3855 Row row = new Row(); 3856 row.set(CatalogName.name, catalogName); 3857 row.set(SchemaName.name, cube.getSchema().getName()); 3858 row.set(CubeName.name, cube.getName()); 3859 row.set(DimensionName.name, dimension.getName()); 3860 row.set(DimensionUniqueName.name, dimension.getUniqueName()); 3861 row.set(DimensionCaption.name, dimension.getCaption()); 3862 row.set(DimensionOrdinal.name, dimension.getOrdinal(cube)); 3863 row.set(DimensionType.name, getDimensionType(dimension)); 3864 3865 //Is this the number of primaryKey members there are?? 3866 // According to microsoft this is: 3867 // "The number of members in the key attribute." 3868 // There may be a better way of doing this but 3869 // this is what I came up with. Note that I need to 3870 // add '1' to the number inorder for it to match 3871 // match what microsoft SQL Server is producing. 3872 // The '1' might have to do with whether or not the 3873 // hierarchy has a 'all' member or not - don't know yet. 3874 // large data set total for Orders cube 0m42.923s 3875 Hierarchy firstHierarchy = dimension.getHierarchies()[0]; 3876 Level[] levels = firstHierarchy.getLevels(); 3877 Level lastLevel = levels[levels.length - 1]; 3878 3879 3880 3881 /* 3882 if override config setting is set 3883 if approxRowCount has a value 3884 use it 3885 else 3886 do default 3887 */ 3888 3889 // Added by TWI to returned cached row numbers 3890 int n = schemaReader.getLevelCardinality(lastLevel, true, true); 3891 row.set(DimensionCardinality.name, n + 1); 3892 3893 // TODO: I think that this is just the dimension name 3894 row.set(DefaultHierarchy.name, dimension.getUniqueName()); 3895 row.set(Description.name, desc); 3896 row.set(IsVirtual.name, false); 3897 // SQL Server always returns false 3898 row.set(IsReadWrite.name, false); 3899 // TODO: don't know what to do here 3900 // Are these the levels with uniqueMembers == true? 3901 // How are they mapped to specific column numbers? 3902 row.set(DimensionUniqueSettings.name, 0); 3903 row.set(DimensionIsVisible.name, true); 3904 3905 addRow(row, rows); 3906 } 3907 3908 protected void setProperty(PropertyDefinition propertyDef, String value) { 3909 switch (propertyDef) { 3910 case Content: 3911 break; 3912 default: 3913 super.setProperty(propertyDef, value); 3914 } 3915 } 3916 } 3917 3918 static int getDimensionType(Dimension dim) { 3919 if (dim.isMeasures()) { 3920 return MdschemaDimensionsRowset.MD_DIMTYPE_MEASURE; 3921 } else if (DimensionType.TimeDimension.equals(dim.getDimensionType())) { 3922 return MdschemaDimensionsRowset.MD_DIMTYPE_TIME; 3923 } else { 3924 return MdschemaDimensionsRowset.MD_DIMTYPE_OTHER; 3925 } 3926 } 3927 3928 static class MdschemaFunctionsRowset extends Rowset { 3929 /** 3930 * http://www.csidata.com/custserv/onlinehelp/VBSdocs/vbs57.htm 3931 */ 3932 enum VarType { 3933 Empty("Uninitialized (default)"), 3934 Null("Contains no valid data"), 3935 Integer("Integer subtype"), 3936 Long("Long subtype"), 3937 Single("Single subtype"), 3938 Double("Double subtype"), 3939 Currency("Currency subtype"), 3940 Date("Date subtype"), 3941 String("String subtype"), 3942 Object("Object subtype"), 3943 Error("Error subtype"), 3944 Boolean("Boolean subtype"), 3945 Variant("Variant subtype"), 3946 DataObject("DataObject subtype"), 3947 Decimal("Decimal subtype"), 3948 Byte("Byte subtype"), 3949 Array("Array subtype"); 3950 3951 static VarType forCategory(int category) { 3952 switch (category) { 3953 case Category.Unknown: 3954 // expression == unknown ??? 3955 // case Category.Expression: 3956 return Empty; 3957 case Category.Array: 3958 return Array; 3959 case Category.Dimension: 3960 case Category.Hierarchy: 3961 case Category.Level: 3962 case Category.Member: 3963 case Category.Set: 3964 case Category.Tuple: 3965 case Category.Cube: 3966 case Category.Value: 3967 return Variant; 3968 case Category.Logical: 3969 return Boolean; 3970 case Category.Numeric: 3971 return Double; 3972 case Category.String: 3973 case Category.Symbol: 3974 case Category.Constant: 3975 return String; 3976 case Category.DateTime: 3977 return Date; 3978 case Category.Integer: 3979 case Category.Mask: 3980 return Integer; 3981 } 3982 // NOTE: this should never happen 3983 return Empty; 3984 } 3985 3986 VarType(String description) { 3987 Util.discard(description); 3988 } 3989 } 3990 3991 private final RestrictionTest functionNameRT; 3992 3993 MdschemaFunctionsRowset(XmlaRequest request, XmlaHandler handler) { 3994 super(MDSCHEMA_FUNCTIONS, request, handler); 3995 functionNameRT = getRestrictionTest(FunctionName); 3996 } 3997 3998 private static final Column FunctionName = 3999 new Column( 4000 "FUNCTION_NAME", 4001 Type.String, 4002 null, 4003 Column.RESTRICTION, 4004 Column.REQUIRED, 4005 "The name of the function."); 4006 private static final Column Description = 4007 new Column( 4008 "DESCRIPTION", 4009 Type.String, 4010 null, 4011 Column.NOT_RESTRICTION, 4012 Column.OPTIONAL, 4013 "A description of the function."); 4014 private static final Column ParameterList = 4015 new Column( 4016 "PARAMETER_LIST", 4017 Type.String, 4018 null, 4019 Column.NOT_RESTRICTION, 4020 Column.OPTIONAL, 4021 "A comma delimited list of parameters."); 4022 private static final Column ReturnType = 4023 new Column( 4024 "RETURN_TYPE", 4025 Type.Integer, 4026 null, 4027 Column.NOT_RESTRICTION, 4028 Column.REQUIRED, 4029 "The VARTYPE of the return data type of the function."); 4030 private static final Column Origin = 4031 new Column( 4032 "ORIGIN", 4033 Type.Integer, 4034 null, 4035 Column.RESTRICTION, 4036 Column.REQUIRED, 4037 "The origin of the function: 1 for MDX functions. 2 for user-defined functions."); 4038 private static final Column InterfaceName = 4039 new Column( 4040 "INTERFACE_NAME", 4041 Type.String, 4042 null, 4043 Column.RESTRICTION, 4044 Column.REQUIRED, 4045 "The name of the interface for user-defined functions"); 4046 private static final Column LibraryName = 4047 new Column( 4048 "LIBRARY_NAME", 4049 Type.String, 4050 null, 4051 Column.RESTRICTION, 4052 Column.OPTIONAL, 4053 "The name of the type library for user-defined functions. NULL for MDX functions."); 4054 private static final Column Caption = 4055 new Column( 4056 "CAPTION", 4057 Type.String, 4058 null, 4059 Column.NOT_RESTRICTION, 4060 Column.OPTIONAL, 4061 "The display caption for the function."); 4062 4063 public void populate( 4064 XmlaResponse response, 4065 List<Row> rows) 4066 throws XmlaException 4067 { 4068 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 4069 DataSourcesConfig.Catalog[] catalogs = 4070 handler.getCatalogs(request, ds); 4071 String roleName = request.getRoleName(); 4072 Role role = request.getRole(); 4073 4074 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 4075 if (dsCatalog == null || dsCatalog.definition == null) { 4076 continue; 4077 } 4078 Connection connection = 4079 handler.getConnection(dsCatalog, role, roleName); 4080 if (connection == null) { 4081 continue; 4082 } 4083 final Schema schema = connection.getSchema(); 4084 FunTable funTable = schema.getFunTable(); 4085 4086 StringBuilder buf = new StringBuilder(50); 4087 List<FunInfo> functions = funTable.getFunInfoList(); 4088 for (FunInfo fi : functions) { 4089 switch (fi.getSyntax()) { 4090 case Empty: 4091 case Internal: 4092 case Parentheses: 4093 continue; 4094 } 4095 if (!functionNameRT.passes(fi.getName())) { 4096 continue; 4097 } 4098 4099 int[][] paramCategories = fi.getParameterCategories(); 4100 int[] returnCategories = fi.getReturnCategories(); 4101 4102 // Convert Windows newlines in 'description' to UNIX format. 4103 String description = fi.getDescription(); 4104 if (description != null) { 4105 description = Util.replace(fi.getDescription(), 4106 "\r", 4107 ""); 4108 } 4109 if ((paramCategories == null) || 4110 (paramCategories.length == 0)) { 4111 Row row = new Row(); 4112 row.set(FunctionName.name, fi.getName()); 4113 row.set(Description.name, description); 4114 row.set(ParameterList.name, "(none)"); 4115 row.set(ReturnType.name, 1); 4116 row.set(Origin.name, 1); 4117 //row.set(LibraryName.name, ""); 4118 // TODO WHAT VALUE should this have 4119 row.set(InterfaceName.name, ""); 4120 row.set(Caption.name, fi.getName()); 4121 addRow(row, rows); 4122 4123 } else { 4124 for (int i = 0; i < paramCategories.length; i++) { 4125 int[] pc = paramCategories[i]; 4126 int returnCategory = returnCategories[i]; 4127 4128 Row row = new Row(); 4129 row.set(FunctionName.name, fi.getName()); 4130 row.set(Description.name, description); 4131 4132 buf.setLength(0); 4133 for (int j = 0; j < pc.length; j++) { 4134 int v = pc[j]; 4135 if (j > 0) { 4136 buf.append(", "); 4137 } 4138 buf.append(Category.instance.getDescription( 4139 v & Category.Mask)); 4140 } 4141 row.set(ParameterList.name, buf.toString()); 4142 4143 VarType varType = VarType.forCategory(returnCategory); 4144 row.set(ReturnType.name, varType.ordinal()); 4145 4146 //TODO: currently FunInfo can not tell us which 4147 // functions are MDX and which are UDFs. 4148 row.set(Origin.name, 1); 4149 4150 // TODO: Name of the type library for UDFs. NULL for MDX 4151 // functions. 4152 //row.set(LibraryName.name, ""); 4153 4154 // TODO: Name of the interface for UDF and Group name 4155 // for the MDX functions. 4156 // TODO WHAT VALUE should this have 4157 row.set(InterfaceName.name, ""); 4158 4159 row.set(Caption.name, fi.getName()); 4160 addRow(row, rows); 4161 } 4162 } 4163 } 4164 } 4165 } 4166 4167 protected void setProperty(PropertyDefinition propertyDef, String value) { 4168 switch (propertyDef) { 4169 case Content: 4170 break; 4171 default: 4172 super.setProperty(propertyDef, value); 4173 } 4174 } 4175 } 4176 4177 static class MdschemaHierarchiesRowset extends Rowset { 4178 private final RestrictionTest catalogRT; 4179 private final RestrictionTest schemaNameRT; 4180 private final RestrictionTest cubeNameRT; 4181 private final RestrictionTest dimensionUniqueNameRT; 4182 private final RestrictionTest hierarchyUniqueNameRT; 4183 private final RestrictionTest hierarchyNameRT; 4184 4185 MdschemaHierarchiesRowset(XmlaRequest request, XmlaHandler handler) { 4186 super(MDSCHEMA_HIERARCHIES, request, handler); 4187 catalogRT = getRestrictionTest(CatalogName); 4188 schemaNameRT = getRestrictionTest(SchemaName); 4189 cubeNameRT = getRestrictionTest(CubeName); 4190 dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName); 4191 hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName); 4192 hierarchyNameRT = getRestrictionTest(HierarchyName); 4193 } 4194 4195 private static final Column CatalogName = 4196 new Column( 4197 "CATALOG_NAME", 4198 Type.String, 4199 null, 4200 Column.RESTRICTION, 4201 Column.OPTIONAL, 4202 "The name of the catalog to which this hierarchy belongs."); 4203 private static final Column SchemaName = 4204 new Column( 4205 "SCHEMA_NAME", 4206 Type.String, 4207 null, 4208 Column.RESTRICTION, 4209 Column.OPTIONAL, 4210 "Not supported"); 4211 private static final Column CubeName = 4212 new Column( 4213 "CUBE_NAME", 4214 Type.String, 4215 null, 4216 Column.RESTRICTION, 4217 Column.REQUIRED, 4218 "The name of the cube to which this hierarchy belongs."); 4219 private static final Column DimensionUniqueName = 4220 new Column( 4221 "DIMENSION_UNIQUE_NAME", 4222 Type.String, 4223 null, 4224 Column.RESTRICTION, 4225 Column.REQUIRED, 4226 "The unique name of the dimension to which this hierarchy belongs. "); 4227 private static final Column HierarchyName = 4228 new Column( 4229 "HIERARCHY_NAME", 4230 Type.String, 4231 null, 4232 Column.RESTRICTION, 4233 Column.REQUIRED, 4234 "The name of the hierarchy. Blank if there is only a single hierarchy in the dimension."); 4235 private static final Column HierarchyUniqueName = 4236 new Column( 4237 "HIERARCHY_UNIQUE_NAME", 4238 Type.String, 4239 null, 4240 Column.RESTRICTION, 4241 Column.REQUIRED, 4242 "The unique name of the hierarchy."); 4243 4244 private static final Column HierarchyGuid = 4245 new Column( 4246 "HIERARCHY_GUID", 4247 Type.UUID, 4248 null, 4249 Column.NOT_RESTRICTION, 4250 Column.OPTIONAL, 4251 "Hierarchy GUID."); 4252 4253 private static final Column HierarchyCaption = 4254 new Column( 4255 "HIERARCHY_CAPTION", 4256 Type.String, 4257 null, 4258 Column.NOT_RESTRICTION, 4259 Column.REQUIRED, 4260 "A label or a caption associated with the hierarchy."); 4261 private static final Column DimensionType = 4262 new Column( 4263 "DIMENSION_TYPE", 4264 Type.Short, 4265 null, 4266 Column.NOT_RESTRICTION, 4267 Column.REQUIRED, 4268 "The type of the dimension. "); 4269 private static final Column HierarchyCardinality = 4270 new Column( 4271 "HIERARCHY_CARDINALITY", 4272 Type.UnsignedInteger, 4273 null, 4274 Column.NOT_RESTRICTION, 4275 Column.REQUIRED, 4276 "The number of members in the hierarchy."); 4277 private static final Column DefaultMember = 4278 new Column( 4279 "DEFAULT_MEMBER", 4280 Type.String, 4281 null, 4282 Column.NOT_RESTRICTION, 4283 Column.OPTIONAL, 4284 "The default member for this hierarchy. "); 4285 private static final Column AllMember = 4286 new Column( 4287 "ALL_MEMBER", 4288 Type.String, 4289 null, 4290 Column.NOT_RESTRICTION, 4291 Column.OPTIONAL, 4292 "The member at the highest level of rollup in the hierarchy."); 4293 private static final Column Description = 4294 new Column( 4295 "DESCRIPTION", 4296 Type.String, 4297 null, 4298 Column.NOT_RESTRICTION, 4299 Column.OPTIONAL, 4300 "A human-readable description of the hierarchy. NULL if no description exists."); 4301 private static final Column Structure = 4302 new Column( 4303 "STRUCTURE", 4304 Type.Short, 4305 null, 4306 Column.NOT_RESTRICTION, 4307 Column.REQUIRED, 4308 "The structure of the hierarchy."); 4309 private static final Column IsVirtual = 4310 new Column( 4311 "IS_VIRTUAL", 4312 Type.Boolean, 4313 null, 4314 Column.NOT_RESTRICTION, 4315 Column.REQUIRED, 4316 "Always returns False."); 4317 private static final Column IsReadWrite = 4318 new Column( 4319 "IS_READWRITE", 4320 Type.Boolean, 4321 null, 4322 Column.NOT_RESTRICTION, 4323 Column.REQUIRED, 4324 "A Boolean that indicates whether the Write Back to dimension column is enabled."); 4325 private static final Column DimensionUniqueSettings = 4326 new Column( 4327 "DIMENSION_UNIQUE_SETTINGS", 4328 Type.Integer, 4329 null, 4330 Column.NOT_RESTRICTION, 4331 Column.REQUIRED, 4332 "Always returns MDDIMENSIONS_MEMBER_KEY_UNIQUE (1)."); 4333 private static final Column DimensionIsVisible = 4334 new Column( 4335 "DIMENSION_IS_VISIBLE", 4336 Type.Boolean, 4337 null, 4338 Column.NOT_RESTRICTION, 4339 Column.REQUIRED, 4340 "Always returns true."); 4341 private static final Column HierarchyOrdinal = 4342 new Column( 4343 "HIERARCHY_ORDINAL", 4344 Type.UnsignedInteger, 4345 null, 4346 Column.NOT_RESTRICTION, 4347 Column.REQUIRED, 4348 "The ordinal number of the hierarchy across all hierarchies of the cube."); 4349 private static final Column DimensionIsShared = 4350 new Column( 4351 "DIMENSION_IS_SHARED", 4352 Type.Boolean, 4353 null, 4354 Column.NOT_RESTRICTION, 4355 Column.REQUIRED, 4356 "Always returns true."); 4357 4358 4359 /* 4360 * NOTE: This is non-standard, where did it come from? 4361 */ 4362 private static final Column ParentChild = 4363 new Column( 4364 "PARENT_CHILD", 4365 Type.Boolean, 4366 null, 4367 Column.NOT_RESTRICTION, 4368 Column.OPTIONAL, 4369 "Is hierarchy a parent."); 4370 4371 public void populate( 4372 XmlaResponse response, 4373 List<Row> rows) 4374 throws XmlaException 4375 { 4376 DataSourcesConfig.DataSource ds = 4377 handler.getDataSource(request); 4378 DataSourcesConfig.Catalog[] catalogs = 4379 handler.getCatalogs(request, ds); 4380 String roleName = request.getRoleName(); 4381 Role role = request.getRole(); 4382 4383 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 4384 if (dsCatalog == null || dsCatalog.definition == null) { 4385 continue; 4386 } 4387 String catalogName = dsCatalog.name; 4388 if (!catalogRT.passes(catalogName)) { 4389 continue; 4390 } 4391 4392 Connection connection = 4393 handler.getConnection(dsCatalog, role, roleName); 4394 if (connection == null) { 4395 continue; 4396 } 4397 populateCatalog(connection, catalogName, rows); 4398 } 4399 } 4400 4401 protected void populateCatalog( 4402 Connection connection, 4403 String catalogName, 4404 List<Row> rows) 4405 throws XmlaException 4406 { 4407 Schema schema = connection.getSchema(); 4408 if (!schemaNameRT.passes(schema.getName())) { 4409 return; 4410 } 4411 for (Cube cube : sortedCubes(schema)) { 4412 if (!cubeNameRT.passes(cube.getName())) { 4413 continue; 4414 } 4415 // RME 4416 //SchemaReader schemaReader = connection.getSchemaReader(); 4417 // want to pick up cube's 4418 SchemaReader schemaReader = cube.getSchemaReader(connection.getRole()); 4419 populateCube(schemaReader, catalogName, cube, rows); 4420 } 4421 } 4422 4423 protected void populateCube( 4424 SchemaReader schemaReader, 4425 String catalogName, 4426 Cube cube, 4427 List<Row> rows) 4428 throws XmlaException 4429 { 4430 int ordinal = 0; 4431 for (Dimension dimension : cube.getDimensions()) { 4432 String unique = dimension.getUniqueName(); 4433 // Must increment ordinal for all dimensions but 4434 // only output some of them. 4435 boolean genOutput = dimensionUniqueNameRT.passes(unique); 4436 ordinal = populateDimension( 4437 genOutput, 4438 schemaReader, catalogName, 4439 cube, dimension, ordinal, rows); 4440 } 4441 } 4442 4443 protected int populateDimension( 4444 boolean genOutput, 4445 SchemaReader schemaReader, 4446 String catalogName, 4447 Cube cube, 4448 Dimension dimension, 4449 int ordinal, 4450 List<Row> rows) 4451 throws XmlaException 4452 { 4453 Hierarchy[] hierarchies = dimension.getHierarchies(); 4454 for (Hierarchy hierarchy : hierarchies) { 4455 if (genOutput) { 4456 String unique = hierarchy.getUniqueName(); 4457 if (hierarchyNameRT.passes(hierarchy.getName()) && 4458 hierarchyUniqueNameRT.passes(unique)) { 4459 populateHierarchy(schemaReader, catalogName, 4460 cube, dimension, (HierarchyBase) hierarchy, 4461 ordinal++, rows); 4462 } else { 4463 ordinal++; 4464 } 4465 } else { 4466 ordinal++; 4467 } 4468 } 4469 return ordinal; 4470 } 4471 4472 protected void populateHierarchy( 4473 SchemaReader schemaReader, 4474 String catalogName, 4475 Cube cube, 4476 Dimension dimension, 4477 HierarchyBase hierarchy, 4478 int ordinal, 4479 List<Row> rows) 4480 throws XmlaException 4481 { 4482 // Access control 4483 if (!canAccess(schemaReader, hierarchy)) { 4484 return; 4485 } 4486 4487 String desc = hierarchy.getDescription(); 4488 if (desc == null) { 4489 desc = cube.getName() + 4490 " Cube - " + 4491 hierarchy.getName() + 4492 " Hierarchy"; 4493 } 4494 4495 Row row = new Row(); 4496 row.set(CatalogName.name, catalogName); 4497 row.set(SchemaName.name, cube.getSchema().getName()); 4498 row.set(CubeName.name, cube.getName()); 4499 row.set(DimensionUniqueName.name, dimension.getUniqueName()); 4500 row.set(HierarchyName.name, hierarchy.getName()); 4501 row.set(HierarchyUniqueName.name, hierarchy.getUniqueName()); 4502 //row.set(HierarchyGuid.name, ""); 4503 4504 row.set(HierarchyCaption.name, hierarchy.getCaption()); 4505 row.set(DimensionType.name, getDimensionType(dimension)); 4506 // The number of members in the hierarchy. Because 4507 // of the presence of multiple hierarchies, this number 4508 // might not be the same as DIMENSION_CARDINALITY. This 4509 // value can be an approximation of the real 4510 // cardinality. Consumers should not assume that this 4511 // value is accurate. 4512 int cardinality = 4513 RolapMember.getHierarchyCardinality(schemaReader, hierarchy); 4514 row.set(HierarchyCardinality.name, cardinality); 4515 4516 row.set(DefaultMember.name, hierarchy.getDefaultMember()); 4517 if (hierarchy.hasAll()) { 4518 row.set(AllMember.name, 4519 Util.makeFqName(hierarchy, hierarchy.getAllMemberName())); 4520 } 4521 row.set(Description.name, desc); 4522 4523 //TODO: only support: 4524 // MD_STRUCTURE_FULLYBALANCED (0) 4525 // MD_STRUCTURE_RAGGEDBALANCED (1) 4526 row.set(Structure.name, hierarchy.isRagged() ? 1 : 0); 4527 4528 row.set(IsVirtual.name, false); 4529 row.set(IsReadWrite.name, false); 4530 4531 // NOTE that SQL Server returns '0' not '1'. 4532 row.set(DimensionUniqueSettings.name, 0); 4533 4534 // always true 4535 row.set(DimensionIsVisible.name, true); 4536 4537 row.set(HierarchyOrdinal.name, ordinal); 4538 4539 // always true 4540 row.set(DimensionIsShared.name, true); 4541 4542 RolapLevel nonAllFirstLevel = 4543 (RolapLevel) hierarchy.getLevels()[ 4544 (hierarchy.hasAll() ? 1 : 0)]; 4545 row.set(ParentChild.name, nonAllFirstLevel.isParentChild()); 4546 addRow(row, rows); 4547 } 4548 4549 protected void setProperty( 4550 PropertyDefinition propertyDef, 4551 String value) 4552 { 4553 switch (propertyDef) { 4554 case Content: 4555 break; 4556 default: 4557 super.setProperty(propertyDef, value); 4558 } 4559 } 4560 } 4561 4562 static class MdschemaLevelsRowset extends Rowset { 4563 private final RestrictionTest catalogRT; 4564 private final RestrictionTest schemaNameRT; 4565 private final RestrictionTest cubeNameRT; 4566 private final RestrictionTest dimensionUniqueNameRT; 4567 private final RestrictionTest hierarchyUniqueNameRT; 4568 private final RestrictionTest levelUniqueNameRT; 4569 private final RestrictionTest levelNameRT; 4570 4571 MdschemaLevelsRowset(XmlaRequest request, XmlaHandler handler) { 4572 super(MDSCHEMA_LEVELS, request, handler); 4573 catalogRT = getRestrictionTest(CatalogName); 4574 schemaNameRT = getRestrictionTest(SchemaName); 4575 cubeNameRT = getRestrictionTest(CubeName); 4576 dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName); 4577 hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName); 4578 levelUniqueNameRT = getRestrictionTest(LevelUniqueName); 4579 levelNameRT = getRestrictionTest(LevelName); 4580 } 4581 4582 public static final int MDLEVEL_TYPE_UNKNOWN = 0x0000; 4583 public static final int MDLEVEL_TYPE_REGULAR = 0x0000; 4584 public static final int MDLEVEL_TYPE_ALL = 0x0001; 4585 public static final int MDLEVEL_TYPE_CALCULATED = 0x0002; 4586 public static final int MDLEVEL_TYPE_TIME = 0x0004; 4587 public static final int MDLEVEL_TYPE_RESERVED1 = 0x0008; 4588 public static final int MDLEVEL_TYPE_TIME_YEARS = 0x0014; 4589 public static final int MDLEVEL_TYPE_TIME_HALF_YEAR = 0x0024; 4590 public static final int MDLEVEL_TYPE_TIME_QUARTERS = 0x0044; 4591 public static final int MDLEVEL_TYPE_TIME_MONTHS = 0x0084; 4592 public static final int MDLEVEL_TYPE_TIME_WEEKS = 0x0104; 4593 public static final int MDLEVEL_TYPE_TIME_DAYS = 0x0204; 4594 public static final int MDLEVEL_TYPE_TIME_HOURS = 0x0304; 4595 public static final int MDLEVEL_TYPE_TIME_MINUTES = 0x0404; 4596 public static final int MDLEVEL_TYPE_TIME_SECONDS = 0x0804; 4597 public static final int MDLEVEL_TYPE_TIME_UNDEFINED = 0x1004; 4598 4599 private static final Column CatalogName = 4600 new Column( 4601 "CATALOG_NAME", 4602 Type.String, 4603 null, 4604 Column.RESTRICTION, 4605 Column.OPTIONAL, 4606 "The name of the catalog to which this level belongs."); 4607 private static final Column SchemaName = 4608 new Column( 4609 "SCHEMA_NAME", 4610 Type.String, 4611 null, 4612 Column.RESTRICTION, 4613 Column.OPTIONAL, 4614 "The name of the schema to which this level belongs."); 4615 private static final Column CubeName = 4616 new Column( 4617 "CUBE_NAME", 4618 Type.String, 4619 null, 4620 Column.RESTRICTION, 4621 Column.REQUIRED, 4622 "The name of the cube to which this level belongs."); 4623 private static final Column DimensionUniqueName = 4624 new Column( 4625 "DIMENSION_UNIQUE_NAME", 4626 Type.String, 4627 null, 4628 Column.RESTRICTION, 4629 Column.REQUIRED, 4630 "The unique name of the dimension to which this level belongs."); 4631 private static final Column HierarchyUniqueName = 4632 new Column( 4633 "HIERARCHY_UNIQUE_NAME", 4634 Type.String, 4635 null, 4636 Column.RESTRICTION, 4637 Column.REQUIRED, 4638 "The unique name of the hierarchy."); 4639 private static final Column LevelName = 4640 new Column( 4641 "LEVEL_NAME", 4642 Type.String, 4643 null, 4644 Column.RESTRICTION, 4645 Column.REQUIRED, 4646 "The name of the level."); 4647 private static final Column LevelUniqueName = 4648 new Column( 4649 "LEVEL_UNIQUE_NAME", 4650 Type.String, 4651 null, 4652 Column.RESTRICTION, 4653 Column.REQUIRED, 4654 "The properly escaped unique name of the level."); 4655 private static final Column LevelGuid = 4656 new Column( 4657 "LEVEL_GUID", 4658 Type.UUID, 4659 null, 4660 Column.NOT_RESTRICTION, 4661 Column.OPTIONAL, 4662 "Level GUID."); 4663 private static final Column LevelCaption = 4664 new Column( 4665 "LEVEL_CAPTION", 4666 Type.String, 4667 null, 4668 Column.NOT_RESTRICTION, 4669 Column.REQUIRED, 4670 "A label or caption associated with the hierarchy."); 4671 private static final Column LevelNumber = 4672 new Column( 4673 "LEVEL_NUMBER", 4674 Type.UnsignedInteger, 4675 null, 4676 Column.NOT_RESTRICTION, 4677 Column.REQUIRED, 4678 "The distance of the level from the root of the hierarchy. Root level is zero (0)."); 4679 private static final Column LevelCardinality = 4680 new Column( 4681 "LEVEL_CARDINALITY", 4682 Type.UnsignedInteger, 4683 null, 4684 Column.NOT_RESTRICTION, 4685 Column.REQUIRED, 4686 "The number of members in the level. This value can be an approximation of the real cardinality."); 4687 private static final Column LevelType = 4688 new Column( 4689 "LEVEL_TYPE", 4690 Type.Integer, 4691 null, 4692 Column.NOT_RESTRICTION, 4693 Column.REQUIRED, 4694 "Type of the level"); 4695 private static final Column CustomRollupSettings = 4696 new Column( 4697 "CUSTOM_ROLLUP_SETTINGS", 4698 Type.Integer, 4699 null, 4700 Column.NOT_RESTRICTION, 4701 Column.REQUIRED, 4702 "A bitmap that specifies the custom rollup options."); 4703 private static final Column LevelUniqueSettings = 4704 new Column( 4705 "LEVEL_UNIQUE_SETTINGS", 4706 Type.Integer, 4707 null, 4708 Column.NOT_RESTRICTION, 4709 Column.REQUIRED, 4710 "A bitmap that specifies which columns contain unique values, if the level only has members with unique names or keys."); 4711 private static final Column LevelIsVisible = 4712 new Column( 4713 "LEVEL_IS_VISIBLE", 4714 Type.Boolean, 4715 null, 4716 Column.NOT_RESTRICTION, 4717 Column.REQUIRED, 4718 "A Boolean that indicates whether the level is visible."); 4719 private static final Column Description = 4720 new Column( 4721 "DESCRIPTION", 4722 Type.String, 4723 null, 4724 Column.NOT_RESTRICTION, 4725 Column.OPTIONAL, 4726 "A human-readable description of the level. NULL if no description exists."); 4727 4728 public void populate( 4729 XmlaResponse response, 4730 List<Row> rows) 4731 throws XmlaException 4732 { 4733 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 4734 DataSourcesConfig.Catalog[] catalogs = 4735 handler.getCatalogs(request, ds); 4736 String roleName = request.getRoleName(); 4737 Role role = request.getRole(); 4738 4739 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 4740 if (dsCatalog == null || dsCatalog.definition == null) { 4741 continue; 4742 } 4743 String catalogName = dsCatalog.name; 4744 if (!catalogRT.passes(catalogName)) { 4745 continue; 4746 } 4747 4748 Connection connection = 4749 handler.getConnection(dsCatalog, role, roleName); 4750 if (connection == null) { 4751 continue; 4752 } 4753 populateCatalog(connection, catalogName, rows); 4754 } 4755 } 4756 4757 protected void populateCatalog( 4758 Connection connection, 4759 String catalogName, 4760 List<Row> rows) 4761 throws XmlaException 4762 { 4763 Schema schema = connection.getSchema(); 4764 if (!schemaNameRT.passes(schema.getName())) { 4765 return; 4766 } 4767 for (Cube cube : sortedCubes(schema)) { 4768 if (!cubeNameRT.passes(cube.getName())) { 4769 continue; 4770 } 4771 SchemaReader schemaReader = 4772 cube.getSchemaReader( 4773 connection.getRole()); 4774 populateCube(schemaReader, catalogName, cube, rows); 4775 } 4776 } 4777 4778 protected void populateCube( 4779 SchemaReader schemaReader, 4780 String catalogName, 4781 Cube cube, 4782 List<Row> rows) 4783 throws XmlaException 4784 { 4785 for (Dimension dimension : cube.getDimensions()) { 4786 String uniqueName = dimension.getUniqueName(); 4787 if (dimensionUniqueNameRT.passes(uniqueName)) { 4788 populateDimension(schemaReader, catalogName, 4789 cube, dimension, rows); 4790 } 4791 } 4792 } 4793 4794 protected void populateDimension( 4795 SchemaReader schemaReader, 4796 String catalogName, 4797 Cube cube, 4798 Dimension dimension, 4799 List<Row> rows) 4800 throws XmlaException 4801 { 4802 Hierarchy[] hierarchies = dimension.getHierarchies(); 4803 for (Hierarchy hierarchy : hierarchies) { 4804 String uniqueName = hierarchy.getUniqueName(); 4805 if (hierarchyUniqueNameRT.passes(uniqueName)) { 4806 populateHierarchy(schemaReader, catalogName, 4807 cube, hierarchy, rows); 4808 } 4809 } 4810 } 4811 4812 protected void populateHierarchy( 4813 SchemaReader schemaReader, 4814 String catalogName, 4815 Cube cube, 4816 Hierarchy hierarchy, 4817 List<Row> rows) 4818 throws XmlaException 4819 { 4820 for (Level level : schemaReader.getHierarchyLevels(hierarchy)) { 4821 String uniqueName = level.getUniqueName(); 4822 String name = level.getName(); 4823 if (levelUniqueNameRT.passes(uniqueName) && 4824 levelNameRT.passes(name)) { 4825 outputLevel(schemaReader, 4826 catalogName, cube, hierarchy, level, rows); 4827 } 4828 } 4829 } 4830 4831 /** 4832 * Outputs a level. 4833 * 4834 * @param schemaReader Schema reader 4835 * @param catalogName Catalog name 4836 * @param cube Cube definition 4837 * @param hierarchy Hierarchy 4838 * @param level Level 4839 * @param rows List of rows to output to 4840 * @return whether the level is visible 4841 * @throws XmlaException If error occurs 4842 */ 4843 protected boolean outputLevel( 4844 SchemaReader schemaReader, 4845 String catalogName, 4846 Cube cube, 4847 Hierarchy hierarchy, 4848 Level level, 4849 List<Row> rows) 4850 throws XmlaException 4851 { 4852 // Access control 4853 if (!canAccess(schemaReader, level)) { 4854 return false; 4855 } 4856 String desc = level.getDescription(); 4857 if (desc == null) { 4858 desc = cube.getName() + 4859 " Cube - " + 4860 hierarchy.getName() + 4861 " Hierarchy" + 4862 level.getName() + 4863 " Level"; 4864 } 4865 4866 int adjustedLevelDepth = level.getDepth(); 4867 Role.HierarchyAccess hierarchyAccess = 4868 schemaReader.getRole().getAccessDetails(hierarchy); 4869 if (hierarchyAccess != null) { 4870 adjustedLevelDepth -= hierarchyAccess.getTopLevelDepth(); 4871 } 4872 4873 Row row = new Row(); 4874 row.set(CatalogName.name, catalogName); 4875 row.set(SchemaName.name, cube.getSchema().getName()); 4876 row.set(CubeName.name, cube.getName()); 4877 row.set(DimensionUniqueName.name, 4878 hierarchy.getDimension().getUniqueName()); 4879 row.set(HierarchyUniqueName.name, hierarchy.getUniqueName()); 4880 row.set(LevelName.name, level.getName()); 4881 row.set(LevelUniqueName.name, level.getUniqueName()); 4882 //row.set(LevelGuid.name, ""); 4883 row.set(LevelCaption.name, level.getCaption()); 4884 // see notes on this #getDepth() 4885 row.set(LevelNumber.name, adjustedLevelDepth); 4886 4887 // Get level cardinality 4888 // According to microsoft this is: 4889 // "The number of members in the level." 4890 int n = schemaReader.getLevelCardinality(level, true, true); 4891 row.set(LevelCardinality.name, n); 4892 4893 row.set(LevelType.name, getLevelType(level)); 4894 4895 // TODO: most of the time this is correct 4896 row.set(CustomRollupSettings.name, 0); 4897 4898 if (level instanceof RolapLevel) { 4899 RolapLevel rl = (RolapLevel) level; 4900 row.set( 4901 LevelUniqueSettings.name, 4902 (rl.isUnique() ? 1 : 0) + 4903 (rl.isAll() ? 2 : 0)); 4904 } else { 4905 // can not access unique member attribute 4906 // this is the best we can do. 4907 row.set( 4908 LevelUniqueSettings.name, 4909 (level.isAll() ? 2 : 0)); 4910 } 4911 row.set(LevelIsVisible.name, true); 4912 row.set(Description.name, desc); 4913 addRow(row, rows); 4914 return true; 4915 } 4916 4917 private int getLevelType(Level lev) { 4918 int ret = 0; 4919 4920 if (lev.isAll()) { 4921 ret |= MDLEVEL_TYPE_ALL; 4922 } 4923 4924 mondrian.olap.LevelType type = lev.getLevelType(); 4925 switch (type) { 4926 case Regular: 4927 ret |= MDLEVEL_TYPE_REGULAR; 4928 break; 4929 case TimeDays: 4930 ret |= MDLEVEL_TYPE_TIME_DAYS; 4931 break; 4932 case TimeMonths: 4933 ret |= MDLEVEL_TYPE_TIME_MONTHS; 4934 break; 4935 case TimeQuarters: 4936 ret |= MDLEVEL_TYPE_TIME_QUARTERS; 4937 break; 4938 case TimeWeeks: 4939 ret |= MDLEVEL_TYPE_TIME_WEEKS; 4940 break; 4941 case TimeYears: 4942 ret |= MDLEVEL_TYPE_TIME_YEARS; 4943 break; 4944 default: 4945 ret |= MDLEVEL_TYPE_UNKNOWN; 4946 } 4947 4948 return ret; 4949 } 4950 4951 protected void setProperty(PropertyDefinition propertyDef, String value) { 4952 switch (propertyDef) { 4953 case Content: 4954 break; 4955 default: 4956 super.setProperty(propertyDef, value); 4957 } 4958 } 4959 } 4960 4961 4962 // REF http://msdn.microsoft.com/library/en-us/oledb/htm/olapmeasures_rowset.asp 4963 static class MdschemaMeasuresRowset extends Rowset { 4964 public static final int MDMEASURE_AGGR_UNKNOWN = 0; 4965 public static final int MDMEASURE_AGGR_SUM = 1; 4966 public static final int MDMEASURE_AGGR_COUNT = 2; 4967 public static final int MDMEASURE_AGGR_MIN = 3; 4968 public static final int MDMEASURE_AGGR_MAX = 4; 4969 public static final int MDMEASURE_AGGR_AVG = 5; 4970 public static final int MDMEASURE_AGGR_VAR = 6; 4971 public static final int MDMEASURE_AGGR_STD = 7; 4972 public static final int MDMEASURE_AGGR_CALCULATED = 127; 4973 4974 private final RestrictionTest catalogRT; 4975 private final RestrictionTest schemaNameRT; 4976 private final RestrictionTest cubeNameRT; 4977 private final RestrictionTest measureUniqueNameRT; 4978 private final RestrictionTest measureNameRT; 4979 4980 MdschemaMeasuresRowset(XmlaRequest request, XmlaHandler handler) { 4981 super(MDSCHEMA_MEASURES, request, handler); 4982 catalogRT = getRestrictionTest(CatalogName); 4983 schemaNameRT = getRestrictionTest(SchemaName); 4984 cubeNameRT = getRestrictionTest(CubeName); 4985 measureNameRT = getRestrictionTest(MeasureName); 4986 measureUniqueNameRT = getRestrictionTest(MeasureUniqueName); 4987 } 4988 4989 private static final Column CatalogName = 4990 new Column( 4991 "CATALOG_NAME", 4992 Type.String, 4993 null, 4994 Column.RESTRICTION, 4995 Column.OPTIONAL, 4996 "The name of the catalog to which this measure belongs. "); 4997 private static final Column SchemaName = 4998 new Column( 4999 "SCHEMA_NAME", 5000 Type.String, 5001 null, 5002 Column.RESTRICTION, 5003 Column.OPTIONAL, 5004 "The name of the schema to which this measure belongs."); 5005 private static final Column CubeName = 5006 new Column( 5007 "CUBE_NAME", 5008 Type.String, 5009 null, 5010 Column.RESTRICTION, 5011 Column.REQUIRED, 5012 "The name of the cube to which this measure belongs."); 5013 private static final Column MeasureName = 5014 new Column( 5015 "MEASURE_NAME", 5016 Type.String, 5017 null, 5018 Column.RESTRICTION, 5019 Column.REQUIRED, 5020 "The name of the measure."); 5021 private static final Column MeasureUniqueName = 5022 new Column( 5023 "MEASURE_UNIQUE_NAME", 5024 Type.String, 5025 null, 5026 Column.RESTRICTION, 5027 Column.REQUIRED, 5028 "The Unique name of the measure."); 5029 private static final Column MeasureCaption = 5030 new Column( 5031 "MEASURE_CAPTION", 5032 Type.String, 5033 null, 5034 Column.NOT_RESTRICTION, 5035 Column.REQUIRED, 5036 "A label or caption associated with the measure. "); 5037 private static final Column MeasureGuid = 5038 new Column( 5039 "MEASURE_GUID", 5040 Type.UUID, 5041 null, 5042 Column.NOT_RESTRICTION, 5043 Column.OPTIONAL, 5044 "Measure GUID."); 5045 private static final Column MeasureAggregator = 5046 new Column( 5047 "MEASURE_AGGREGATOR", 5048 Type.Integer, 5049 null, 5050 Column.NOT_RESTRICTION, 5051 Column.REQUIRED, 5052 "How a measure was derived. "); 5053 private static final Column DataType = 5054 new Column( 5055 "DATA_TYPE", 5056 Type.UnsignedShort, 5057 null, 5058 Column.NOT_RESTRICTION, 5059 Column.REQUIRED, 5060 "Data type of the measure."); 5061 private static final Column MeasureIsVisible = 5062 new Column( 5063 "MEASURE_IS_VISIBLE", 5064 Type.Boolean, 5065 null, 5066 Column.NOT_RESTRICTION, 5067 Column.REQUIRED, 5068 "A Boolean that always returns True. If the measure is not visible, it will not be included in the schema rowset."); 5069 private static final Column LevelsList = 5070 new Column( 5071 "LEVELS_LIST", 5072 Type.String, 5073 null, 5074 Column.NOT_RESTRICTION, 5075 Column.OPTIONAL, 5076 "A string that always returns NULL. EXCEPT that SQL Server returns non-null values!!!"); 5077 private static final Column Description = 5078 new Column( 5079 "DESCRIPTION", 5080 Type.String, 5081 null, 5082 Column.NOT_RESTRICTION, 5083 Column.OPTIONAL, 5084 "A human-readable description of the measure. "); 5085 5086 public void populate( 5087 XmlaResponse response, 5088 List<Row> rows) 5089 throws XmlaException 5090 { 5091 DataSourcesConfig.DataSource ds = handler.getDataSource(request); 5092 DataSourcesConfig.Catalog[] catalogs = 5093 handler.getCatalogs(request, ds); 5094 String roleName = request.getRoleName(); 5095 Role role = request.getRole(); 5096 5097 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 5098 if (dsCatalog == null || dsCatalog.definition == null) { 5099 continue; 5100 } 5101 Connection connection = 5102 handler.getConnection(dsCatalog, role, roleName); 5103 if (connection == null) { 5104 continue; 5105 } 5106 5107 String catalogName = dsCatalog.name; 5108 if (catalogRT.passes(catalogName)) { 5109 populateCatalog(connection, catalogName, rows); 5110 } 5111 } 5112 } 5113 5114 protected void populateCatalog( 5115 Connection connection, 5116 String catalogName, 5117 List<Row> rows) 5118 throws XmlaException 5119 { 5120 // SQL Server actually includes the LEVELS_LIST row 5121 StringBuilder buf = new StringBuilder(100); 5122 5123 Schema schema = connection.getSchema(); 5124 if (!schemaNameRT.passes(schema.getName())) { 5125 return; 5126 } 5127 for (Cube cube : sortedCubes(schema)) { 5128 if (cubeNameRT.passes(cube.getName())) { 5129 SchemaReader schemaReader = 5130 cube.getSchemaReader( 5131 connection.getRole()); 5132 Dimension measuresDimension = cube.getDimensions()[0]; 5133 Hierarchy measuresHierarchy = 5134 measuresDimension.getHierarchies()[0]; 5135 Level measuresLevel = 5136 measuresHierarchy.getLevels()[0]; 5137 5138 buf.setLength(0); 5139 5140 int j = 0; 5141 for (Dimension dimension : cube.getDimensions()) { 5142 if (dimension.isMeasures()) { 5143 continue; 5144 } 5145 for (Hierarchy hierarchy : dimension.getHierarchies()) { 5146 Level[] levels = hierarchy.getLevels(); 5147 Level lastLevel = levels[levels.length - 1]; 5148 if (j++ > 0) { 5149 buf.append(','); 5150 } 5151 buf.append(lastLevel.getUniqueName()); 5152 } 5153 } 5154 String levelListStr = buf.toString(); 5155 5156 List<Member> storedMembers = 5157 schemaReader.getLevelMembers(measuresLevel, false); 5158 for (Member member : storedMembers) { 5159 String name = member.getName(); 5160 String unique = member.getUniqueName(); 5161 if (measureNameRT.passes(name) && 5162 measureUniqueNameRT.passes(unique)) { 5163 populateMember(schemaReader, catalogName, 5164 member, cube, levelListStr, rows); 5165 } 5166 } 5167 5168 for (Member member : 5169 schemaReader.getCalculatedMembers(measuresHierarchy)) { 5170 String name = member.getName(); 5171 String unique = member.getUniqueName(); 5172 if (measureNameRT.passes(name) && 5173 measureUniqueNameRT.passes(unique)) { 5174 populateMember(schemaReader, catalogName, 5175 member, cube, null, rows); 5176 } 5177 } 5178 } 5179 } 5180 } 5181 5182 private void populateMember( 5183 SchemaReader schemaReader, 5184 String catalogName, 5185 Member member, 5186 Cube cube, 5187 String levelListStr, 5188 List<Row> rows) 5189 { 5190 // Access control 5191 if (!canAccess(schemaReader, member)) { 5192 return; 5193 } 5194 5195 Boolean visible = 5196 (Boolean) member.getPropertyValue(Property.VISIBLE.name); 5197 if (visible == null) { 5198 visible = true; 5199 } 5200 if (!EMIT_INVISIBLE_MEMBERS && !visible) { 5201 return; 5202 } 5203 5204 //TODO: currently this is always null 5205 String desc = member.getDescription(); 5206 if (desc == null) { 5207 desc = cube.getName() + 5208 " Cube - " + 5209 member.getName() + 5210 " Member"; 5211 } 5212 5213 Row row = new Row(); 5214 row.set(CatalogName.name, catalogName); 5215 row.set(SchemaName.name, cube.getSchema().getName()); 5216 row.set(CubeName.name, cube.getName()); 5217 row.set(MeasureName.name, member.getName()); 5218 row.set(MeasureUniqueName.name, member.getUniqueName()); 5219 row.set(MeasureCaption.name, member.getCaption()); 5220 //row.set(MeasureGuid.name, ""); 5221 5222 Object aggProp = 5223 member.getPropertyValue(Property.AGGREGATION_TYPE.getName()); 5224 int aggNumber = MDMEASURE_AGGR_UNKNOWN; 5225 if (aggProp != null) { 5226 RolapAggregator agg = (RolapAggregator) aggProp; 5227 if (agg == RolapAggregator.Sum) { 5228 aggNumber = MDMEASURE_AGGR_SUM; 5229 } else if (agg == RolapAggregator.Count) { 5230 aggNumber = MDMEASURE_AGGR_COUNT; 5231 } else if (agg == RolapAggregator.Min) { 5232 aggNumber = MDMEASURE_AGGR_MIN; 5233 } else if (agg == RolapAggregator.Max) { 5234 aggNumber = MDMEASURE_AGGR_MAX; 5235 } else if (agg == RolapAggregator.Avg) { 5236 aggNumber = MDMEASURE_AGGR_AVG; 5237 } 5238 //TODO: what are VAR and STD 5239 } else { 5240 aggNumber = MDMEASURE_AGGR_CALCULATED; 5241 } 5242 row.set(MeasureAggregator.name, aggNumber); 5243 5244 // DATA_TYPE DBType best guess is string 5245 int dbType = DBType.WSTR.userOrdinal; 5246 String datatype = (String) 5247 member.getPropertyValue(Property.DATATYPE.getName()); 5248 if (datatype != null) { 5249 if (datatype.equals("Integer")) { 5250 dbType = DBType.I4.userOrdinal; 5251 } else if (datatype.equals("Numeric")) { 5252 dbType = DBType.R8.userOrdinal; 5253 } else { 5254 dbType = DBType.WSTR.userOrdinal; 5255 } 5256 } 5257 row.set(DataType.name, dbType); 5258 row.set(MeasureIsVisible.name, visible); 5259 5260 if (levelListStr != null) { 5261 row.set(LevelsList.name, levelListStr); 5262 } 5263 5264 row.set(Description.name, desc); 5265 addRow(row, rows); 5266 } 5267 5268 protected void setProperty(PropertyDefinition propertyDef, String value) { 5269 switch (propertyDef) { 5270 case Content: 5271 break; 5272 default: 5273 super.setProperty(propertyDef, value); 5274 } 5275 } 5276 } 5277 5278 static class MdschemaMembersRowset extends Rowset { 5279 private final RestrictionTest catalogRT; 5280 private final RestrictionTest schemaNameRT; 5281 private final RestrictionTest cubeNameRT; 5282 private final RestrictionTest dimensionUniqueNameRT; 5283 private final RestrictionTest hierarchyUniqueNameRT; 5284 private final RestrictionTest memberNameRT; 5285 private final RestrictionTest memberUniqueNameRT; 5286 private final RestrictionTest memberTypeRT; 5287 5288 MdschemaMembersRowset(XmlaRequest request, XmlaHandler handler) { 5289 super(MDSCHEMA_MEMBERS, request, handler); 5290 catalogRT = getRestrictionTest(CatalogName); 5291 schemaNameRT = getRestrictionTest(SchemaName); 5292 cubeNameRT = getRestrictionTest(CubeName); 5293 dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName); 5294 hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName); 5295 memberNameRT = getRestrictionTest(MemberName); 5296 memberUniqueNameRT = getRestrictionTest(MemberUniqueName); 5297 memberTypeRT = getRestrictionTest(MemberType); 5298 } 5299 5300 private static final Column CatalogName = 5301 new Column( 5302 "CATALOG_NAME", 5303 Type.String, 5304 null, 5305 Column.RESTRICTION, 5306 Column.OPTIONAL, 5307 "The name of the catalog to which this member belongs. "); 5308 private static final Column SchemaName = 5309 new Column( 5310 "SCHEMA_NAME", 5311 Type.String, 5312 null, 5313 Column.RESTRICTION, 5314 Column.OPTIONAL, 5315 "The name of the schema to which this member belongs. "); 5316 private static final Column CubeName = 5317 new Column( 5318 "CUBE_NAME", 5319 Type.String, 5320 null, 5321 Column.RESTRICTION, 5322 Column.REQUIRED, 5323 "Name of the cube to which this member belongs."); 5324 private static final Column DimensionUniqueName = 5325 new Column( 5326 "DIMENSION_UNIQUE_NAME", 5327 Type.String, 5328 null, 5329 Column.RESTRICTION, 5330 Column.REQUIRED, 5331 "Unique name of the dimension to which this member belongs. "); 5332 private static final Column HierarchyUniqueName = 5333 new Column( 5334 "HIERARCHY_UNIQUE_NAME", 5335 Type.String, 5336 null, 5337 Column.RESTRICTION, 5338 Column.REQUIRED, 5339 "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."); 5340 private static final Column LevelUniqueName = 5341 new Column( 5342 "LEVEL_UNIQUE_NAME", 5343 Type.String, 5344 null, 5345 Column.RESTRICTION, 5346 Column.REQUIRED, 5347 " Unique name of the level to which the member belongs."); 5348 private static final Column LevelNumber = 5349 new Column( 5350 "LEVEL_NUMBER", 5351 Type.UnsignedInteger, 5352 null, 5353 Column.RESTRICTION, 5354 Column.REQUIRED, 5355 "The distance of the member from the root of the hierarchy."); 5356 private static final Column MemberOrdinal = 5357 new Column( 5358 "MEMBER_ORDINAL", 5359 Type.UnsignedInteger, 5360 null, 5361 Column.NOT_RESTRICTION, 5362 Column.REQUIRED, 5363 "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."); 5364 private static final Column MemberName = 5365 new Column( 5366 "MEMBER_NAME", 5367 Type.String, 5368 null, 5369 Column.RESTRICTION, 5370 Column.REQUIRED, 5371 "Name of the member."); 5372 private static final Column MemberUniqueName = 5373 new Column( 5374 "MEMBER_UNIQUE_NAME", 5375 Type.StringSometimesArray, 5376 null, 5377 Column.RESTRICTION, 5378 Column.REQUIRED, 5379 " Unique name of the member."); 5380 private static final Column MemberType = 5381 new Column( 5382 "MEMBER_TYPE", 5383 Type.Integer, 5384 null, 5385 Column.RESTRICTION, 5386 Column.REQUIRED, 5387 "Type of the member."); 5388 private static final Column MemberGuid = 5389 new Column( 5390 "MEMBER_GUID", 5391 Type.UUID, 5392 null, 5393 Column.NOT_RESTRICTION, 5394 Column.OPTIONAL, 5395 "Memeber GUID."); 5396 private static final Column MemberCaption = 5397 new Column( 5398 "MEMBER_CAPTION", 5399 Type.String, 5400 null, 5401 Column.RESTRICTION, 5402 Column.REQUIRED, 5403 "A label or caption associated with the member."); 5404 private static final Column ChildrenCardinality = 5405 new Column( 5406 "CHILDREN_CARDINALITY", 5407 Type.UnsignedInteger, 5408 null, 5409 Column.NOT_RESTRICTION, 5410 Column.REQUIRED, 5411 "Number of children that the member has."); 5412 private static final Column ParentLevel = 5413 new Column( 5414 "PARENT_LEVEL", 5415 Type.UnsignedInteger, 5416 null, 5417 Column.NOT_RESTRICTION, 5418 Column.REQUIRED, 5419 "The distance of the member's parent from the root level of the hierarchy. "); 5420 private static final Column ParentUniqueName = 5421 new Column( 5422 "PARENT_UNIQUE_NAME", 5423 Type.String, 5424 null, 5425 Column.NOT_RESTRICTION, 5426 Column.OPTIONAL, 5427 "Unique name of the member's parent."); 5428 private static final Column ParentCount = 5429 new Column( 5430 "PARENT_COUNT", 5431 Type.UnsignedInteger, 5432 null, 5433 Column.NOT_RESTRICTION, 5434 Column.REQUIRED, 5435 "Number of parents that this member has."); 5436 private static final Column TreeOp = 5437 new Column( 5438 "TREE_OP", 5439 Type.Enumeration, 5440 Enumeration.TreeOp.enumeration, 5441 Column.RESTRICTION, 5442 Column.OPTIONAL, 5443 "Tree Operation"); 5444 /* Mondrian specified member properties. */ 5445 private static final Column Depth = 5446 new Column( 5447 "DEPTH", 5448 Type.Integer, 5449 null, 5450 Column.NOT_RESTRICTION, 5451 Column.OPTIONAL, 5452 "depth"); 5453 5454 public void populate( 5455 XmlaResponse response, 5456 List<Row> rows) 5457 throws XmlaException 5458 { 5459 DataSourcesConfig.DataSource ds = 5460 handler.getDataSource(request); 5461 DataSourcesConfig.Catalog[] catalogs = 5462 handler.getCatalogs(request, ds); 5463 String roleName = request.getRoleName(); 5464 Role role = request.getRole(); 5465 5466 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 5467 if (dsCatalog == null || dsCatalog.definition == null) { 5468 continue; 5469 } 5470 Connection connection = 5471 handler.getConnection(dsCatalog, role, roleName); 5472 if (connection == null) { 5473 continue; 5474 } 5475 5476 String catalogName = dsCatalog.name; 5477 if (catalogRT.passes(catalogName)) { 5478 populateCatalog(connection, catalogName, rows); 5479 } 5480 } 5481 } 5482 5483 protected void populateCatalog( 5484 Connection connection, 5485 String catalogName, 5486 List<Row> rows) 5487 throws XmlaException 5488 { 5489 Schema schema = connection.getSchema(); 5490 if (!schemaNameRT.passes(schema.getName())) { 5491 return; 5492 } 5493 for (Cube cube : sortedCubes(schema)) { 5494 if (cubeNameRT.passes(cube.getName())) { 5495 if (isRestricted(MemberUniqueName)) { 5496 // NOTE: it is believed that if MEMBER_UNIQUE_NAME is 5497 // a restriction, then none of the remaining possible 5498 // restrictions other than TREE_OP are relevant 5499 // (or allowed??). 5500 SchemaReader schemaReader = cube.getSchemaReader(null); 5501 outputUniqueMemberName( 5502 schemaReader, catalogName, cube, rows); 5503 } else { 5504 SchemaReader schemaReader = 5505 cube.getSchemaReader( 5506 connection.getRole()); 5507 populateCube(schemaReader, catalogName, cube, rows); 5508 } 5509 5510 } 5511 } 5512 } 5513 5514 protected void populateCube( 5515 SchemaReader schemaReader, 5516 String catalogName, 5517 Cube cube, 5518 List<Row> rows) 5519 throws XmlaException 5520 { 5521 if (isRestricted(LevelUniqueName)) { 5522 // Note: If the LEVEL_UNIQUE_NAME has been specified, then 5523 // the dimension and hierarchy are specified implicitly. 5524 String levelUniqueName = 5525 getRestrictionValueAsString(LevelUniqueName); 5526 if (levelUniqueName == null) { 5527 // The query specified two or more unique names 5528 // which means that nothing will match. 5529 return; 5530 } 5531 5532 final List<Id.Segment> nameParts = 5533 Util.parseIdentifier(levelUniqueName); 5534 Hierarchy hier = cube.lookupHierarchy(nameParts.get(0), false); 5535 if (hier == null) { 5536 return; 5537 } 5538 Level[] levels = hier.getLevels(); 5539 for (Level level : levels) { 5540 if (!level.getUniqueName().equals(levelUniqueName)) { 5541 continue; 5542 } 5543 // Get members of this level, without access control, but 5544 // including calculated members. 5545 List<Member> members = 5546 cube.getSchemaReader(null).getLevelMembers(level, true); 5547 outputMembers( 5548 schemaReader, members, catalogName, cube, rows); 5549 } 5550 } else { 5551 for (Dimension dimension : cube.getDimensions()) { 5552 String uniqueName = dimension.getUniqueName(); 5553 if (dimensionUniqueNameRT.passes(uniqueName)) { 5554 populateDimension( 5555 schemaReader, catalogName, 5556 cube, dimension, rows); 5557 } 5558 } 5559 } 5560 } 5561 5562 protected void populateDimension( 5563 SchemaReader schemaReader, 5564 String catalogName, 5565 Cube cube, 5566 Dimension dimension, 5567 List<Row> rows) 5568 throws XmlaException 5569 { 5570 Hierarchy[] hierarchies = dimension.getHierarchies(); 5571 for (Hierarchy hierarchy : hierarchies) { 5572 String uniqueName = hierarchy.getUniqueName(); 5573 if (hierarchyUniqueNameRT.passes(uniqueName)) { 5574 populateHierarchy( 5575 schemaReader, catalogName, 5576 cube, hierarchy, rows); 5577 } 5578 } 5579 } 5580 5581 protected void populateHierarchy( 5582 SchemaReader schemaReader, 5583 String catalogName, 5584 Cube cube, 5585 Hierarchy hierarchy, 5586 List<Row> rows) 5587 throws XmlaException 5588 { 5589 if (isRestricted(LevelNumber)) { 5590 int levelNumber = getRestrictionValueAsInt(LevelNumber); 5591 if (levelNumber == -1) { 5592 LOGGER.warn("RowsetDefinition.populateHierarchy: " + 5593 "LevelNumber invalid"); 5594 return; 5595 } 5596 Level[] levels = hierarchy.getLevels(); 5597 if (levelNumber >= levels.length) { 5598 LOGGER.warn("RowsetDefinition.populateHierarchy: " + 5599 "LevelNumber (" + 5600 levelNumber + 5601 ") is greater than number of levels (" + 5602 levels.length + 5603 ") for hierarchy \"" + 5604 hierarchy.getUniqueName() + 5605 "\""); 5606 return; 5607 } 5608 5609 Level level = levels[levelNumber]; 5610 List<Member> members = 5611 schemaReader.getLevelMembers(level, false); 5612 outputMembers(schemaReader, members, catalogName, cube, rows); 5613 } else { 5614 // At this point we get ALL of the members associated with 5615 // the Hierarchy (rather than getting them one at a time). 5616 // The value returned is not used at this point but they are 5617 // now cached in the SchemaReader. 5618 List<List<Member>> membersArray = 5619 RolapMember.getAllMembers(schemaReader, hierarchy); 5620 for (List<Member> members : membersArray) { 5621 outputMembers( 5622 schemaReader, members, 5623 catalogName, cube, rows); 5624 } 5625 } 5626 } 5627 5628 /** 5629 * Returns whether a value contains all of the bits in a mask. 5630 */ 5631 private static boolean mask(int value, int mask) { 5632 return (value & mask) == mask; 5633 } 5634 5635 /** 5636 * Adds a member to a result list and, depending upon the 5637 * <code>treeOp</code> parameter, other relatives of the member. This 5638 * method recursively invokes itself to walk up, down, or across the 5639 * hierarchy. 5640 */ 5641 private void populateMember( 5642 final SchemaReader schemaReader, 5643 String catalogName, 5644 Cube cube, 5645 Member member, 5646 int treeOp, 5647 List<Row> rows) 5648 { 5649 // Visit node itself. 5650 if (mask(treeOp, Enumeration.TreeOp.Self.userOrdinal())) { 5651 outputMember(schemaReader, member, catalogName, cube, rows); 5652 } 5653 // Visit node's siblings (not including itself). 5654 if (mask(treeOp, Enumeration.TreeOp.Siblings.userOrdinal())) { 5655 final Member parent = 5656 schemaReader.getMemberParent(member); 5657 final List<Member> siblings = (parent == null) 5658 ? schemaReader.getHierarchyRootMembers(member.getHierarchy()) 5659 : schemaReader.getMemberChildren(parent); 5660 5661 for (Member sibling : siblings) { 5662 if (sibling.equals(member)) { 5663 continue; 5664 } 5665 populateMember( 5666 schemaReader, catalogName, 5667 cube, sibling, 5668 Enumeration.TreeOp.Self.userOrdinal(), rows); 5669 } 5670 } 5671 // Visit node's descendants or its immediate children, but not both. 5672 if (mask(treeOp, Enumeration.TreeOp.Descendants.userOrdinal())) { 5673 final List<Member> children = schemaReader.getMemberChildren(member); 5674 for (Member child : children) { 5675 populateMember( 5676 schemaReader, catalogName, 5677 cube, child, 5678 Enumeration.TreeOp.Self.userOrdinal() | 5679 Enumeration.TreeOp.Descendants.userOrdinal(), 5680 rows); 5681 } 5682 } else if (mask(treeOp, Enumeration.TreeOp.Children.userOrdinal())) { 5683 final List<Member> children = 5684 schemaReader.getMemberChildren(member); 5685 for (Member child : children) { 5686 populateMember( 5687 schemaReader, catalogName, 5688 cube, child, 5689 Enumeration.TreeOp.Self.userOrdinal(), rows); 5690 } 5691 } 5692 // Visit node's ancestors or its immediate parent, but not both. 5693 if (mask(treeOp, Enumeration.TreeOp.Ancestors.userOrdinal())) { 5694 final Member parent = schemaReader.getMemberParent(member); 5695 if (parent != null) { 5696 populateMember( 5697 schemaReader, catalogName, 5698 cube, parent, 5699 Enumeration.TreeOp.Self.userOrdinal() | 5700 Enumeration.TreeOp.Ancestors.userOrdinal(), rows); 5701 } 5702 } else if (mask(treeOp, Enumeration.TreeOp.Parent.userOrdinal())) { 5703 final Member parent = schemaReader.getMemberParent(member); 5704 if (parent != null) { 5705 populateMember( 5706 schemaReader, catalogName, 5707 cube, parent, 5708 Enumeration.TreeOp.Self.userOrdinal(), rows); 5709 } 5710 } 5711 } 5712 5713 protected ArrayList<Column> pruneRestrictions(ArrayList<Column> list) { 5714 // If they've restricted TreeOp, we don't want to literally filter 5715 // the result on TreeOp (because it's not an output column) or 5716 // on MemberUniqueName (because TreeOp will have caused us to 5717 // generate other members than the one asked for). 5718 if (list.contains(TreeOp)) { 5719 list.remove(TreeOp); 5720 list.remove(MemberUniqueName); 5721 } 5722 return list; 5723 } 5724 5725 private void outputMembers( 5726 final SchemaReader schemaReader, 5727 List<Member> members, 5728 final String catalogName, 5729 Cube cube, List<Row> rows) { 5730 5731 for (Member member : members) { 5732 outputMember(schemaReader, member, catalogName, cube, rows); 5733 } 5734 } 5735 5736 private void outputUniqueMemberName( 5737 final SchemaReader schemaReader, 5738 final String catalogName, 5739 Cube cube, List<Row> rows) 5740 { 5741 final Object unameRestrictions = 5742 restrictions.get(MemberUniqueName.name); 5743 List<String> list; 5744 if (unameRestrictions instanceof String) { 5745 list = Collections.singletonList((String) unameRestrictions); 5746 } else { 5747 list = (List<String>) unameRestrictions; 5748 } 5749 for (String memberUniqueName : list) { 5750 final List<Id.Segment> nameParts = 5751 Util.parseIdentifier(memberUniqueName); 5752 5753 Member member = schemaReader.getMemberByUniqueName( 5754 nameParts, false); 5755 5756 if (member == null) { 5757 return; 5758 } 5759 if (isRestricted(TreeOp)) { 5760 int treeOp = getRestrictionValueAsInt(TreeOp); 5761 if (treeOp == -1) { 5762 return; 5763 } 5764 populateMember( 5765 schemaReader, catalogName, 5766 cube, member, treeOp, rows); 5767 } else { 5768 outputMember( 5769 schemaReader, member, catalogName, cube, rows); 5770 } 5771 } 5772 } 5773 5774 private void outputMember( 5775 final SchemaReader schemaReader, 5776 Member member, 5777 final String catalogName, 5778 Cube cube, 5779 List<Row> rows) 5780 { 5781 // Access control 5782 if (!canAccess(schemaReader, member)) { 5783 return; 5784 } 5785 if (! memberNameRT.passes(member.getName())) { 5786 return; 5787 } 5788 if (! memberTypeRT.passes(member.getMemberType())) { 5789 return; 5790 } 5791 5792 if (member.getOrdinal() == -1) { 5793 RolapMember.setOrdinals(schemaReader, member); 5794 } 5795 5796 // Check whether the member is visible, otherwise do not dump. 5797 Boolean visible = 5798 (Boolean) member.getPropertyValue(Property.VISIBLE.name); 5799 if (visible == null) { 5800 visible = true; 5801 } 5802 if (!EMIT_INVISIBLE_MEMBERS && !visible) { 5803 return; 5804 } 5805 5806 final Level level = member.getLevel(); 5807 final Hierarchy hierarchy = level.getHierarchy(); 5808 final Dimension dimension = hierarchy.getDimension(); 5809 5810 int adjustedLevelDepth = level.getDepth(); 5811 Role.HierarchyAccess hierarchyAccess = 5812 schemaReader.getRole().getAccessDetails(hierarchy); 5813 if (hierarchyAccess != null) { 5814 adjustedLevelDepth -= hierarchyAccess.getTopLevelDepth(); 5815 } 5816 5817 Row row = new Row(); 5818 row.set(CatalogName.name, catalogName); 5819 row.set(SchemaName.name, cube.getSchema().getName()); 5820 row.set(CubeName.name, cube.getName()); 5821 row.set(DimensionUniqueName.name, dimension.getUniqueName()); 5822 row.set(HierarchyUniqueName.name, hierarchy.getUniqueName()); 5823 row.set(LevelUniqueName.name, level.getUniqueName()); 5824 row.set(LevelNumber.name, adjustedLevelDepth); 5825 row.set(MemberOrdinal.name, false ? 0 : member.getOrdinal()); 5826 row.set(MemberName.name, member.getName()); 5827 row.set(MemberUniqueName.name, member.getUniqueName()); 5828 row.set(MemberType.name, member.getMemberType().ordinal()); 5829 //row.set(MemberGuid.name, ""); 5830 row.set(MemberCaption.name, member.getCaption()); 5831 row.set(ChildrenCardinality.name, 5832 member.getPropertyValue(Property.CHILDREN_CARDINALITY.name)); 5833 row.set(ChildrenCardinality.name, 100); 5834 5835 if (adjustedLevelDepth == 0) { 5836 row.set(ParentLevel.name, 0); 5837 } else { 5838 row.set(ParentLevel.name, adjustedLevelDepth - 1); 5839 String parentUniqueName = member.getParentUniqueName(); 5840 if (parentUniqueName != null) { 5841 row.set(ParentUniqueName.name, parentUniqueName); 5842 } 5843 } 5844 5845 row.set(ParentCount.name, member.getParentMember() == null ? 0 : 1); 5846 5847 row.set(Depth.name, member.getDepth()); 5848 addRow(row, rows); 5849 } 5850 5851 protected void setProperty( 5852 PropertyDefinition propertyDef, 5853 String value) 5854 { 5855 switch (propertyDef) { 5856 case Content: 5857 break; 5858 default: 5859 super.setProperty(propertyDef, value); 5860 } 5861 } 5862 5863 /* 5864 RME: this code was used to test various algorithms to set member ordinals. 5865 void setOrdinals(SchemaReader schemaReader, Member startMember) { 5866 //int v = 0; 5867 //int v = 1; 5868 //int v = 2; 5869 //int v = 3; 5870 int v = 4; 5871 LOGGER.debug("RowsetDefinition.setOrdinals: v==" +v); 5872 if (v == 0) { 5873 // foodmart time for Sales: time=63 5874 // For very big data set, it takes time= 651865ms 5875 RolapMember.setOrdinals(schemaReader, startMember); 5876 } else if (v == 1) { 5877 // foodmart time for Sales: time=32 5878 // result is same as v == 0 5879 // For very big data set, it takes time= 73880ms 5880 Hierarchy hierarchy = startMember.getHierarchy(); 5881 Member[][] membersArray = 5882 RolapMember.getAllMembers(schemaReader, hierarchy); 5883 RolapMember.setOrdinals(schemaReader, startMember); 5884 } else if (v == 2) { 5885 // foodmart time for Sales: time=18 5886 // result is NOT same as v == 0 5887 int ordinal = 0; 5888 Hierarchy hierarchy = startMember.getHierarchy(); 5889 Member[][] membersArray = 5890 RolapMember.getAllMembers(schemaReader, hierarchy); 5891 5892 // RME: this does a breath first setting of ordinals 5893 // for very big data set, it takes time= 4197ms 5894 for (int i = 0; i < membersArray.length; i++) { 5895 Member[] members = membersArray[i]; 5896 for (int j = 0; j < members.length; j++) { 5897 Member member = members[j]; 5898 ((RolapMember) member).setOrdinal(ordinal++); 5899 } 5900 } 5901 } else if (v == 3) { 5902 // foodmart time for Sales: time=19 5903 // result is same as v == 0 5904 int ordinal = 1; 5905 int depth = 1; 5906 Hierarchy hierarchy = startMember.getHierarchy(); 5907 Member[][] membersArray = 5908 RolapMember.getAllMembers(schemaReader, hierarchy); 5909 Member[] rootMembers = membersArray[0]; 5910 LOGGER.debug("RowsetDefinition.setOrdinals: rootMembers.length=" +rootMembers.length); 5911 // RME: this does a depth first setting of ordinals 5912 // for very big data set, it takes time= 97310ms 5913 for (int i = 0; i < rootMembers.length; i++) { 5914 Member member = rootMembers[i]; 5915 if (member.getOrdinal() == -1) { 5916 LOGGER.debug("RowsetDefinition.setOrdinals: member=" +member.getName()); 5917 ((RolapMember) member).setOrdinal(ordinal++); 5918 } else { 5919 LOGGER.debug("RowsetDefinition.setOrdinals: NO member=" +member.getName()); 5920 } 5921 ordinal = setOrdinals(ordinal, member, membersArray, depth); 5922 } 5923 } else { 5924 // foodmart time for Sales: time=17 5925 // result is same as v == 0 5926 // bottom up depth first 5927 // For very big data set, it takes time= 4241ms 5928 int ordinal = 1; 5929 Hierarchy hierarchy = startMember.getHierarchy(); 5930 Member[][] membersArray = 5931 RolapMember.getAllMembers(schemaReader, hierarchy); 5932 Member[] leafMembers = membersArray[membersArray.length-1]; 5933 5934 for (int i = 0; i < leafMembers.length; i++) { 5935 Member child = leafMembers[i]; 5936 ordinal = bottomUpSetOrdinals(ordinal, child); 5937 ((RolapMember) child).setOrdinal(ordinal++); 5938 } 5939 boolean needsFullTopDown = false; 5940 for (int i = 0; i < membersArray.length-1; i++) { 5941 Member[] members = membersArray[i]; 5942 for (int j = 0; j < members.length; j++) { 5943 Member member = members[j]; 5944 if (member.getOrdinal() == -1) { 5945 needsFullTopDown = true; 5946 break; 5947 } 5948 } 5949 } 5950 LOGGER.debug("RowsetDefinition.setOrdinals: needsFullTopDown=" +needsFullTopDown); 5951 } 5952 } 5953 int bottomUpSetOrdinals(int ordinal, Member child) { 5954 Member parent = child.getParentMember(); 5955 if (parent.getOrdinal() == -1) { 5956 ordinal = bottomUpSetOrdinals(ordinal, parent); 5957 ((RolapMember) parent).setOrdinal(ordinal++); 5958 } 5959 return ordinal; 5960 } 5961 5962 5963 // RME: this is used as part of the depth first setting of ordinals 5964 int setOrdinals(int ordinal, Member parent, Member[][] membersArray, int depth) { 5965 boolean nextLevelExists = (depth + 1 < membersArray.length); 5966 Member[] members = membersArray[depth]; 5967 for (int i = 0; i < members.length; i++) { 5968 Member member = members[i]; 5969 if (member.getParentMember() == parent) { 5970 ((RolapMember) member).setOrdinal(ordinal++); 5971 if (nextLevelExists) { 5972 ordinal = 5973 setOrdinals(ordinal, member, membersArray, depth + 1); 5974 } 5975 } 5976 } 5977 return ordinal; 5978 } 5979 */ 5980 5981 } 5982 5983 static class MdschemaSetsRowset extends Rowset { 5984 private final RestrictionTest catalogRT; 5985 private final RestrictionTest schemaNameRT; 5986 private final RestrictionTest cubeNameRT; 5987 private final RestrictionTest setNameRT; 5988 private static final String GLOBAL_SCOPE = "1"; 5989 5990 MdschemaSetsRowset(XmlaRequest request, XmlaHandler handler) { 5991 super(MDSCHEMA_SETS, request, handler); 5992 catalogRT = getRestrictionTest(CatalogName); 5993 schemaNameRT = getRestrictionTest(SchemaName); 5994 cubeNameRT = getRestrictionTest(CubeName); 5995 setNameRT = getRestrictionTest(SetName); 5996 } 5997 5998 private static final Column CatalogName = 5999 new Column( 6000 "CATALOG_NAME", 6001 Type.String, 6002 null, 6003 true, 6004 true, 6005 null); 6006 private static final Column SchemaName = 6007 new Column( 6008 "SCHEMA_NAME", 6009 Type.String, 6010 null, 6011 true, 6012 true, 6013 null); 6014 private static final Column CubeName = 6015 new Column( 6016 "CUBE_NAME", 6017 Type.String, 6018 null, 6019 true, 6020 false, 6021 null); 6022 private static final Column SetName = 6023 new Column( 6024 "SET_NAME", 6025 Type.String, 6026 null, 6027 true, 6028 false, 6029 null); 6030 private static final Column SetCaption = 6031 new Column( 6032 "SET_CAPTION", 6033 Type.String, 6034 null, 6035 true, 6036 true, 6037 null); 6038 private static final Column Scope = 6039 new Column( 6040 "SCOPE", 6041 Type.Integer, 6042 null, 6043 true, 6044 false, 6045 null); 6046 private static final Column Description = 6047 new Column("DESCRIPTION", 6048 Type.String, 6049 null, 6050 false, 6051 true, 6052 "A human-readable description of the measure."); 6053 6054 public void populate( 6055 XmlaResponse response, 6056 List<Row> rows) 6057 throws XmlaException 6058 { 6059 DataSourcesConfig.DataSource ds = 6060 handler.getDataSource(request); 6061 DataSourcesConfig.Catalog[] catalogs = 6062 handler.getCatalogs(request, ds); 6063 String roleName = request.getRoleName(); 6064 Role role = request.getRole(); 6065 6066 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 6067 if (dsCatalog == null || dsCatalog.definition == null) { 6068 continue; 6069 } 6070 Connection connection = 6071 handler.getConnection(dsCatalog, role, roleName); 6072 if (connection == null) { 6073 continue; 6074 } 6075 6076 String catalogName = dsCatalog.name; 6077 if (!catalogRT.passes(catalogName)) { 6078 continue; 6079 } 6080 processCatalog(connection, catalogName, rows); 6081 } 6082 } 6083 6084 private void processCatalog( 6085 Connection connection, 6086 String catalogName, 6087 List<Row> rows) 6088 { 6089 Schema schema = connection.getSchema(); 6090 if (!schemaNameRT.passes(schema.getName())) { 6091 return; 6092 } 6093 Cube[] cubes = connection.getSchemaReader().getCubes(); 6094 for (Cube cube : cubes) { 6095 if (!cubeNameRT.passes(cube.getName())) { 6096 continue; 6097 } 6098 populateNamedSets(cube, catalogName, rows); 6099 } 6100 } 6101 6102 private void populateNamedSets( 6103 Cube cube, 6104 String catalogName, 6105 List<Row> rows) 6106 { 6107 for (NamedSet namedSet : cube.getNamedSets()) { 6108 if (!setNameRT.passes(namedSet.getUniqueName())) { 6109 continue; 6110 } 6111 Row row = new Row(); 6112 row.set(CatalogName.name, catalogName); 6113 row.set(SchemaName.name, cube.getSchema().getName()); 6114 row.set(CubeName.name, cube.getName()); 6115 row.set(SetName.name, namedSet.getUniqueName()); 6116 row.set(Scope.name, GLOBAL_SCOPE); 6117 row.set(Description.name, namedSet.getDescription()); 6118 addRow(row, rows); 6119 } 6120 } 6121 } 6122 6123 static class MdschemaPropertiesRowset extends Rowset { 6124 private final RestrictionTest catalogRT; 6125 private final RestrictionTest schemaNameRT; 6126 private final RestrictionTest cubeNameRT; 6127 private final RestrictionTest dimensionUniqueNameRT; 6128 private final RestrictionTest hierarchyUniqueNameRT; 6129 private final RestrictionTest propertyNameRT; 6130 6131 MdschemaPropertiesRowset(XmlaRequest request, XmlaHandler handler) { 6132 super(MDSCHEMA_PROPERTIES, request, handler); 6133 catalogRT = getRestrictionTest(CatalogName); 6134 schemaNameRT = getRestrictionTest(SchemaName); 6135 cubeNameRT = getRestrictionTest(CubeName); 6136 dimensionUniqueNameRT = getRestrictionTest(DimensionUniqueName); 6137 hierarchyUniqueNameRT = getRestrictionTest(HierarchyUniqueName); 6138 propertyNameRT = getRestrictionTest(PropertyName); 6139 } 6140 6141 private static final int MDPROP_MEMBER = 0x01; 6142 private static final int MDPROP_CELL = 0x02; 6143 private static final int MDPROP_SYSTEM = 0x04; 6144 private static final int MDPROP_BLOB = 0x08; 6145 6146 private static final int MD_PROPTYPE_REGULAR = 0x00; 6147 6148 private static final Column CatalogName = 6149 new Column( 6150 "CATALOG_NAME", 6151 Type.String, 6152 null, 6153 Column.RESTRICTION, 6154 Column.OPTIONAL, 6155 "The name of the database."); 6156 private static final Column SchemaName = 6157 new Column( 6158 "SCHEMA_NAME", 6159 Type.String, 6160 null, 6161 Column.RESTRICTION, 6162 Column.OPTIONAL, 6163 "The name of the schema to which this property belongs."); 6164 private static final Column CubeName = 6165 new Column( 6166 "CUBE_NAME", 6167 Type.String, 6168 null, 6169 Column.RESTRICTION, 6170 Column.REQUIRED, 6171 "The name of the cube."); 6172 private static final Column DimensionUniqueName = 6173 new Column( 6174 "DIMENSION_UNIQUE_NAME", 6175 Type.String, 6176 null, 6177 Column.RESTRICTION, 6178 Column.REQUIRED, 6179 "The unique name of the dimension."); 6180 private static final Column HierarchyUniqueName = 6181 new Column( 6182 "HIERARCHY_UNIQUE_NAME", 6183 Type.String, 6184 null, 6185 Column.RESTRICTION, 6186 Column.REQUIRED, 6187 "The unique name of the hierarchy."); 6188 private static final Column LevelUniqueName = 6189 new Column( 6190 "LEVEL_UNIQUE_NAME", 6191 Type.String, 6192 null, 6193 Column.RESTRICTION, 6194 Column.REQUIRED, 6195 "The unique name of the level to which this property belongs."); 6196 // According to MS this should not be nullable 6197 private static final Column MemberUniqueName = 6198 new Column( 6199 "MEMBER_UNIQUE_NAME", 6200 Type.String, 6201 null, 6202 Column.RESTRICTION, 6203 Column.OPTIONAL, 6204 "The unique name of the member to which the property belongs."); 6205 private static final Column PropertyName = 6206 new Column( 6207 "PROPERTY_NAME", 6208 Type.String, 6209 null, 6210 Column.RESTRICTION, 6211 Column.REQUIRED, 6212 "Name of the property."); 6213 private static final Column PropertyType = 6214 new Column( 6215 "PROPERTY_TYPE", 6216 Type.Short, 6217 null, 6218 Column.RESTRICTION, 6219 Column.REQUIRED, 6220 "A bitmap that specifies the type of the property"); 6221 private static final Column PropertyCaption = 6222 new Column( 6223 "PROPERTY_CAPTION", 6224 Type.String, 6225 null, 6226 Column.NOT_RESTRICTION, 6227 Column.REQUIRED, 6228 "A label or caption associated with the property, used primarily for display purposes."); 6229 private static final Column DataType = 6230 new Column( 6231 "DATA_TYPE", 6232 Type.UnsignedShort, 6233 null, 6234 Column.NOT_RESTRICTION, 6235 Column.REQUIRED, 6236 "Data type of the property."); 6237 private static final Column PropertyContentType = 6238 new Column( 6239 "PROPERTY_CONTENT_TYPE", 6240 Type.Short, 6241 null, 6242 Column.RESTRICTION, 6243 Column.OPTIONAL, 6244 "The type of the property. "); 6245 private static final Column Description = 6246 new Column( 6247 "DESCRIPTION", 6248 Type.String, 6249 null, 6250 Column.NOT_RESTRICTION, 6251 Column.OPTIONAL, 6252 "A human-readable description of the measure. "); 6253 6254 public void populate( 6255 XmlaResponse response, 6256 List<Row> rows) 6257 throws XmlaException 6258 { 6259 DataSourcesConfig.DataSource ds = 6260 handler.getDataSource(request); 6261 DataSourcesConfig.Catalog[] catalogs = 6262 handler.getCatalogs(request, ds); 6263 String roleName = request.getRoleName(); 6264 Role role = request.getRole(); 6265 6266 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 6267 if (dsCatalog == null || dsCatalog.definition == null) { 6268 continue; 6269 } 6270 Connection connection = 6271 handler.getConnection(dsCatalog, role, roleName); 6272 if (connection == null) { 6273 continue; 6274 } 6275 6276 String catalogName = dsCatalog.name; 6277 if (catalogRT.passes(catalogName)) { 6278 populateCatalog(connection, catalogName, rows); 6279 } 6280 } 6281 } 6282 6283 protected void populateCatalog( 6284 Connection connection, 6285 String catalogName, 6286 List<Row> rows) 6287 throws XmlaException 6288 { 6289 Schema schema = connection.getSchema(); 6290 if (!schemaNameRT.passes(schema.getName())) { 6291 return; 6292 } 6293 for (Cube cube : sortedCubes(schema)) { 6294 if (cubeNameRT.passes(cube.getName())) { 6295 SchemaReader schemaReader = 6296 cube.getSchemaReader( 6297 connection.getRole()); 6298 populateCube(schemaReader, catalogName, cube, rows); 6299 } 6300 } 6301 } 6302 6303 protected void populateCube( 6304 SchemaReader schemaReader, 6305 String catalogName, 6306 Cube cube, 6307 List<Row> rows) 6308 throws XmlaException 6309 { 6310 if (isRestricted(LevelUniqueName)) { 6311 // Note: If the LEVEL_UNIQUE_NAME has been specified, then 6312 // the dimension and hierarchy are specified implicitly. 6313 String levelUniqueName = 6314 getRestrictionValueAsString(LevelUniqueName); 6315 if (levelUniqueName == null) { 6316 // The query specified two or more unique names 6317 // which means that nothing will match. 6318 return; 6319 } 6320 final List<Id.Segment> nameParts = 6321 Util.parseIdentifier(levelUniqueName); 6322 Hierarchy hier = cube.lookupHierarchy(nameParts.get(0), false); 6323 if (hier == null) { 6324 return; 6325 } 6326 for (Level level : schemaReader.getHierarchyLevels(hier)) { 6327 if (level.getUniqueName().equals(levelUniqueName)) { 6328 populateLevel(schemaReader, catalogName, 6329 cube, level, rows); 6330 break; 6331 } 6332 } 6333 6334 } else { 6335 for (Dimension dimension : cube.getDimensions()) { 6336 String uniqueName = dimension.getUniqueName(); 6337 if (dimensionUniqueNameRT.passes(uniqueName)) { 6338 populateDimension(schemaReader, catalogName, 6339 cube, dimension, rows); 6340 } 6341 } 6342 } 6343 } 6344 6345 private void populateDimension( 6346 final SchemaReader schemaReader, 6347 final String catalogName, 6348 Cube cube, 6349 Dimension dimension, 6350 List<Row> rows) 6351 { 6352 Hierarchy[] hierarchies = dimension.getHierarchies(); 6353 for (Hierarchy hierarchy : hierarchies) { 6354 String unique = hierarchy.getUniqueName(); 6355 if (hierarchyUniqueNameRT.passes(unique)) { 6356 populateHierarchy(schemaReader, catalogName, 6357 cube, hierarchy, rows); 6358 } 6359 } 6360 } 6361 6362 private void populateHierarchy( 6363 final SchemaReader schemaReader, 6364 final String catalogName, 6365 Cube cube, 6366 Hierarchy hierarchy, 6367 List<Row> rows) 6368 { 6369 for (Level level : schemaReader.getHierarchyLevels(hierarchy)) { 6370 populateLevel(schemaReader, catalogName, 6371 cube, level, rows); 6372 } 6373 } 6374 6375 private void populateLevel( 6376 final SchemaReader schemaReader, 6377 final String catalogName, 6378 Cube cube, 6379 Level level, 6380 List<Row> rows) 6381 { 6382 Property[] properties = level.getProperties(); 6383 for (Property property : properties) { 6384 if (propertyNameRT.passes(property.getName())) { 6385 outputProperty(schemaReader, property, 6386 catalogName, cube, level, rows); 6387 } 6388 } 6389 } 6390 6391 private void outputProperty( 6392 final SchemaReader schemaReader, 6393 Property property, 6394 final String catalogName, 6395 Cube cube, 6396 Level level, 6397 List<Row> rows) 6398 { 6399 Hierarchy hierarchy = level.getHierarchy(); 6400 Dimension dimension = hierarchy.getDimension(); 6401 6402 String propertyName = property.getName(); 6403 6404 Row row = new Row(); 6405 row.set(CatalogName.name, catalogName); 6406 row.set(SchemaName.name, cube.getSchema().getName()); 6407 row.set(CubeName.name, cube.getName()); 6408 row.set(DimensionUniqueName.name, dimension.getUniqueName()); 6409 row.set(HierarchyUniqueName.name, hierarchy.getUniqueName()); 6410 row.set(LevelUniqueName.name, level.getUniqueName()); 6411 //TODO: what is the correct value here 6412 //row.set(MemberUniqueName.name, ""); 6413 6414 row.set(PropertyName.name, propertyName); 6415 // Only member properties now 6416 row.set(PropertyType.name, MDPROP_MEMBER); 6417 row.set(PropertyContentType.name, MD_PROPTYPE_REGULAR); 6418 row.set(PropertyCaption.name, property.getCaption()); 6419 DBType dbType = getDBTypeFromProperty(property); 6420 row.set(DataType.name, dbType.userOrdinal); 6421 6422 String desc = cube.getName() + 6423 " Cube - " + 6424 hierarchy.getName() + 6425 " Hierarchy - " + 6426 level.getName() + 6427 " Level - " + 6428 property.getName() + 6429 " Property"; 6430 row.set(Description.name, desc); 6431 6432 addRow(row, rows); 6433 } 6434 6435 protected void setProperty( 6436 PropertyDefinition propertyDef, 6437 String value) 6438 { 6439 switch (propertyDef) { 6440 case Content: 6441 break; 6442 default: 6443 super.setProperty(propertyDef, value); 6444 } 6445 } 6446 } 6447 6448 private static boolean canAccess( 6449 SchemaReader schemaReader, 6450 OlapElement elem) 6451 { 6452 Role role = schemaReader.getRole(); 6453 return role.canAccess(elem); 6454 } 6455 6456 private static <T extends Comparable> List<T> sort( 6457 Collection<T> collection) 6458 { 6459 Object[] a = collection.toArray(new Object[collection.size()]); 6460 Arrays.sort(a); 6461 return Util.cast(Arrays.asList(a)); 6462 } 6463 6464 private static <T> List<T> sortArray( 6465 T[] a, 6466 Comparator<T> comparator) 6467 { 6468 T[] a2 = a.clone(); 6469 Arrays.sort(a2, comparator); 6470 return Arrays.asList(a2); 6471 } 6472 6473 static void serialize(StringBuilder buf, Collection<String> strings) { 6474 int k = 0; 6475 for (String name : sort(strings)) { 6476 if (k++ > 0) { 6477 buf.append(','); 6478 } 6479 buf.append(name); 6480 } 6481 } 6482 6483 static List<Cube> sortedCubes(Schema schema) { 6484 final Cube[] cubes = schema.getCubes(); 6485 return sortArray( 6486 cubes, 6487 new Comparator<Cube>() { 6488 public int compare(Cube o1, Cube o2) { 6489 return o1.getName().compareTo(o2.getName()); 6490 } 6491 } 6492 ); 6493 } 6494 } 6495 6496 // End RowsetDefinition.java