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