1 9 package mondrian.xmla; 10 11 import mondrian.calc.ExpCompiler.ResultStyle; 12 import mondrian.olap.*; 13 import mondrian.olap.Connection; 14 import mondrian.olap.DriverManager; 15 import mondrian.rolap.*; 16 import mondrian.rolap.agg.CellRequest; 17 import mondrian.spi.CatalogLocator; 18 import mondrian.xmla.impl.DefaultSaxWriter; 19 20 import org.apache.log4j.Logger; 21 import org.xml.sax.SAXException ; 22 23 import javax.sql.DataSource ; 24 import java.math.BigDecimal ; 25 import java.sql.*; 26 import java.util.*; 27 import java.io.StringWriter ; 28 import java.io.PrintWriter ; 29 30 31 38 public class XmlaHandler implements XmlaConstants { 39 private static final Logger LOGGER = Logger.getLogger(XmlaHandler.class); 40 41 private final Map<String , DataSourcesConfig.DataSource> dataSourcesMap; 42 private final List<String > drillThruColumnNames = new ArrayList<String >(); 43 private final CatalogLocator catalogLocator; 44 private final String prefix; 45 46 private static final int ROW_SET = 1; 47 private static final int MD_DATA_SET = 2; 48 49 private static final String ROW_SET_XML_SCHEMA = computeXsd(ROW_SET); 50 private static final String EMPTY_ROW_SET_XML_SCHEMA = 51 computeEmptyXsd(ROW_SET); 52 53 private static final String MD_DATA_SET_XML_SCHEMA = computeXsd(MD_DATA_SET); 54 private static final String EMPTY_MD_DATA_SET_XML_SCHEMA = 55 computeEmptyXsd(MD_DATA_SET); 56 57 private static final String NS_XML_SQL = "urn:schemas-microsoft-com:xml-sql"; 58 59 private static String computeXsd(int settype) { 60 final StringWriter sw = new StringWriter (); 61 SaxWriter writer = new DefaultSaxWriter(new PrintWriter (sw), 3); 62 writeDatasetXmlSchema(writer, settype); 63 writer.flush(); 64 return sw.toString(); 65 } 66 67 private static String computeEmptyXsd(int settype) { 68 final StringWriter sw = new StringWriter (); 69 SaxWriter writer = new DefaultSaxWriter(new PrintWriter (sw), 3); 70 writeEmptyDatasetXmlSchema(writer, settype); 71 writer.flush(); 72 return sw.toString(); 73 } 74 75 private static interface QueryResult { 76 public void unparse(SaxWriter res) throws SAXException ; 77 } 78 79 87 public XmlaHandler( 88 DataSourcesConfig.DataSources dataSources, 89 CatalogLocator catalogLocator, 90 String prefix) 91 { 92 this.catalogLocator = catalogLocator; 93 assert prefix != null; 94 this.prefix = prefix; 95 Map<String , DataSourcesConfig.DataSource> map = 96 new HashMap<String , DataSourcesConfig.DataSource>(); 97 if (dataSources != null) { 98 for (DataSourcesConfig.DataSource ds : dataSources.dataSources) { 99 if (map.containsKey(ds.getDataSourceName())) { 100 throw Util.newError( 102 "duplicated data source name '" + 103 ds.getDataSourceName() + "'"); 104 } 105 for (DataSourcesConfig.Catalog catalog : ds.catalogs.catalogs) { 107 catalog.setDataSource(ds); 108 } 109 map.put(ds.getDataSourceName(), ds); 110 } 111 } 112 dataSourcesMap = Collections.unmodifiableMap(map); 113 } 114 115 public Map<String , DataSourcesConfig.DataSource> getDataSourceEntries() { 116 return dataSourcesMap; 117 } 118 119 125 public void process(XmlaRequest request, XmlaResponse response) 126 throws XmlaException { 127 int method = request.getMethod(); 128 long start = System.currentTimeMillis(); 129 130 switch (method) { 131 case METHOD_DISCOVER: 132 discover(request, response); 133 break; 134 case METHOD_EXECUTE: 135 execute(request, response); 136 break; 137 default: 138 throw new XmlaException( 139 CLIENT_FAULT_FC, 140 HSB_BAD_METHOD_CODE, 141 HSB_BAD_METHOD_FAULT_FS, 142 new IllegalArgumentException ( 143 "Unsupported XML/A method: " +method)); 144 } 145 if (LOGGER.isDebugEnabled()) { 146 long end = System.currentTimeMillis(); 147 LOGGER.debug("XmlaHandler.process: time = " +(end-start)); 148 LOGGER.debug("XmlaHandler.process: " +Util.printMemory()); 149 } 150 } 151 152 private void checkFormat(XmlaRequest request) throws XmlaException { 153 final Map<String , String > properties = request.getProperties(); 155 if (request.isDrillThrough()) { 156 final String formatName = 157 properties.get(PropertyDefinition.Format.name()); 158 Enumeration.Format format = 159 valueOf( 160 Enumeration.Format.class, 161 formatName, 162 null); 163 if (format != Enumeration.Format.Tabular) { 164 throw new XmlaException( 165 CLIENT_FAULT_FC, 166 HSB_DRILL_THROUGH_FORMAT_CODE, 167 HSB_DRILL_THROUGH_FORMAT_FAULT_FS, 168 new UnsupportedOperationException ( 169 "<Format>: only 'Tabular' allowed when drilling through")); 170 } 171 } else { 172 final String formatName = 173 properties.get(PropertyDefinition.Format.name()); 174 if (formatName != null) { 175 Enumeration.Format format = valueOf( 176 Enumeration.Format.class, formatName, null); 177 if (format != Enumeration.Format.Multidimensional && 178 format != Enumeration.Format.Tabular) { 179 throw new UnsupportedOperationException ( 180 "<Format>: only 'Multidimensional', 'Tabular' currently supported"); 181 } 182 } 183 final String axisFormatName = 184 properties.get(PropertyDefinition.AxisFormat.name()); 185 if (axisFormatName != null) { 186 Enumeration.AxisFormat axisFormat = valueOf( 187 Enumeration.AxisFormat.class, axisFormatName, null); 188 189 if (axisFormat != Enumeration.AxisFormat.TupleFormat) { 190 throw new UnsupportedOperationException ( 191 "<AxisFormat>: only 'TupleFormat' currently supported"); 192 } 193 } 194 } 195 } 196 197 private void execute(XmlaRequest request, XmlaResponse response) 198 throws XmlaException { 199 200 final Map<String , String > properties = request.getProperties(); 201 final String contentName = 202 properties.get(PropertyDefinition.Content.name()); 203 Enumeration.Content content = 205 valueOf(Enumeration.Content.class, contentName, CONTENT_DEFAULT); 206 207 QueryResult result; 209 if (request.isDrillThrough()) { 210 String tabFields = 211 properties.get(PropertyDefinition.TableFields.name()); 212 if (tabFields != null && tabFields.length() > 0) { 213 result = executeColumnQuery(request); 216 } else { 217 result = executeDrillThroughQuery(request); 218 } 219 } else { 220 result = executeQuery(request); 221 } 222 223 SaxWriter writer = response.getWriter(); 224 writer.startDocument(); 225 226 writer.startElement(prefix + ":ExecuteResponse", new String [] { 227 "xmlns:" + prefix, NS_XMLA}); 228 writer.startElement(prefix + ":return"); 229 boolean rowset = 230 request.isDrillThrough() || 231 Enumeration.Format.Tabular.name().equals( 232 request.getProperties().get( 233 PropertyDefinition.Format.name())); 234 writer.startElement("root", new String [] { 235 "xmlns", 236 result == null ? NS_XMLA_EMPTY : 237 rowset ? NS_XMLA_ROWSET : 238 NS_XMLA_MDDATASET, 239 "xmlns:xsi", NS_XSI, 240 "xmlns:xsd", NS_XSD, 241 "xmlns:EX", NS_XMLA_EX, 242 }); 243 244 if ((content == Enumeration.Content.Schema) 245 || (content == Enumeration.Content.SchemaData)) { 246 if (result != null) { 247 if (result instanceof MDDataSet_Tabular) { 248 MDDataSet_Tabular tabResult = (MDDataSet_Tabular) result; 249 tabResult.metadata(writer); 250 } else if (rowset) { 251 writer.verbatim(ROW_SET_XML_SCHEMA); 252 } else { 253 writer.verbatim(MD_DATA_SET_XML_SCHEMA); 254 } 255 } else { 256 if (rowset) { 257 writer.verbatim(EMPTY_ROW_SET_XML_SCHEMA); 258 } else { 259 writer.verbatim(EMPTY_MD_DATA_SET_XML_SCHEMA); 260 } 261 } 262 } 263 264 try { 265 if ((content == Enumeration.Content.Data) 266 || (content == Enumeration.Content.SchemaData)) { 267 if (result != null) { 268 result.unparse(writer); 269 } 270 } 271 } catch (XmlaException xex) { 272 throw xex; 273 } catch (Throwable t) { 274 throw new XmlaException( 275 SERVER_FAULT_FC, 276 HSB_EXECUTE_UNPARSE_CODE, 277 HSB_EXECUTE_UNPARSE_FAULT_FS, 278 t); 279 } finally { 280 writer.endElement(); writer.endElement(); writer.endElement(); } 284 285 writer.endDocument(); 286 } 287 288 294 static void writeDatasetXmlSchema(SaxWriter writer, int settype) { 295 String setNsXmla = (settype == ROW_SET) 296 ? XmlaConstants.NS_XMLA_ROWSET 297 : XmlaConstants.NS_XMLA_MDDATASET; 298 299 writer.startElement("xsd:schema", new String [] { 300 "xmlns:xsd", XmlaConstants.NS_XSD, 301 "targetNamespace", setNsXmla, 302 "xmlns", setNsXmla, 303 "xmlns:xsi", XmlaConstants.NS_XSI, 304 "xmlns:sql", NS_XML_SQL, 305 "elementFormDefault", "qualified" 306 }); 307 308 310 writer.startElement("xsd:complexType", new String [] { 311 "name", "MemberType" 312 }); 313 writer.startElement("xsd:sequence"); 314 writer.element("xsd:element", new String [] { 315 "name", "UName", 316 "type", "xsd:string", 317 }); 318 writer.element("xsd:element", new String [] { 319 "name", "Caption", 320 "type", "xsd:string", 321 }); 322 writer.element("xsd:element", new String [] { 323 "name", "LName", 324 "type", "xsd:string", 325 }); 326 writer.element("xsd:element", new String [] { 327 "name", "LNum", 328 "type", "xsd:unsignedInt", 329 }); 330 writer.element("xsd:element", new String [] { 331 "name", "DisplayInfo", 332 "type", "xsd:unsignedInt", 333 }); 334 writer.startElement("xsd:sequence", new String [] { 335 "maxOccurs", "unbounded", 336 "minOccurs", "0", 337 }); 338 writer.element("xsd:any", new String [] { 339 "processContents", "lax", 340 "maxOccurs", "unbounded", 341 }); 342 writer.endElement(); writer.endElement(); writer.element("xsd:attribute", new String [] { 345 "name", "Hierarchy", 346 "type", "xsd:string", 347 }); 348 writer.endElement(); 350 352 writer.startElement("xsd:complexType", new String [] { 353 "name", "PropType", 354 }); 355 writer.element("xsd:attribute", new String [] { 356 "name", "name", 357 "type", "xsd:string", 358 }); 359 writer.endElement(); 361 363 writer.startElement("xsd:complexType", new String [] { 364 "name", "TupleType" 365 }); 366 writer.startElement("xsd:sequence", new String [] { 367 "maxOccurs", "unbounded" 368 }); 369 writer.element("xsd:element", new String [] { 370 "name", "Member", 371 "type", "MemberType", 372 }); 373 writer.endElement(); writer.endElement(); 376 378 writer.startElement("xsd:complexType", new String [] { 379 "name", "MembersType" 380 }); 381 writer.startElement("xsd:sequence", new String [] { 382 "maxOccurs", "unbounded", 383 }); 384 writer.element("xsd:element", new String [] { 385 "name", "Member", 386 "type", "MemberType", 387 }); 388 writer.endElement(); writer.element("xsd:attribute", new String [] { 390 "name", "Hierarchy", 391 "type", "xsd:string", 392 }); 393 writer.endElement(); 395 397 writer.startElement("xsd:complexType", new String [] { 398 "name", "TuplesType" 399 }); 400 writer.startElement("xsd:sequence", new String [] { 401 "maxOccurs", "unbounded", 402 }); 403 writer.element("xsd:element", new String [] { 404 "name", "Tuple", 405 "type", "TupleType", 406 }); 407 writer.endElement(); writer.endElement(); 410 412 writer.startElement("xsd:complexType", new String [] { 413 "name", "CrossProductType", 414 }); 415 writer.startElement("xsd:sequence"); 416 writer.startElement("xsd:choice", new String [] { 417 "minOccurs", "0", 418 "maxOccurs", "unbounded", 419 }); 420 writer.element("xsd:element", new String [] { 421 "name", "Members", 422 "type", "MembersType" 423 }); 424 writer.element("xsd:element", new String [] { 425 "name", "Tuples", 426 "type", "TuplesType" 427 }); 428 writer.endElement(); writer.endElement(); writer.element("xsd:attribute", new String [] { 431 "name", "Size", 432 "type", "xsd:unsignedInt" 433 }); 434 writer.endElement(); 436 438 writer.startElement("xsd:complexType", new String [] { 439 "name", "OlapInfo", 440 }); 441 writer.startElement("xsd:sequence"); 442 443 { writer.startElement("xsd:element", new String [] { 445 "name", "CubeInfo" 446 }); 447 writer.startElement("xsd:complexType"); 448 writer.startElement("xsd:sequence"); 449 450 { writer.startElement("xsd:element", new String [] { 452 "name", "Cube", 453 "maxOccurs", "unbounded" 454 }); 455 writer.startElement("xsd:complexType"); 456 writer.startElement("xsd:sequence"); 457 458 writer.element("xsd:element", new String [] { 459 "name", "CubeName", 460 "type", "xsd:string" 461 }); 462 463 writer.endElement(); writer.endElement(); writer.endElement(); } 467 468 writer.endElement(); writer.endElement(); writer.endElement(); } 472 { writer.startElement("xsd:element", new String [] { 474 "name", "AxesInfo" 475 }); 476 writer.startElement("xsd:complexType"); 477 writer.startElement("xsd:sequence"); 478 { writer.startElement("xsd:element", new String [] { 480 "name", "AxisInfo", 481 "maxOccurs", "unbounded" 482 }); 483 writer.startElement("xsd:complexType"); 484 writer.startElement("xsd:sequence"); 485 486 { writer.startElement("xsd:element", new String [] { 488 "name", "HierarchyInfo", 489 "minOccurs", "0", 490 "maxOccurs", "unbounded" 491 }); 492 writer.startElement("xsd:complexType"); 493 writer.startElement("xsd:sequence"); 494 writer.startElement("xsd:sequence", new String [] { 495 "maxOccurs", "unbounded" 496 }); 497 writer.element("xsd:element", new String [] { 498 "name", "UName", 499 "type", "PropType" 500 }); 501 writer.element("xsd:element", new String [] { 502 "name", "Caption", 503 "type", "PropType" 504 }); 505 writer.element("xsd:element", new String [] { 506 "name", "LName", 507 "type", "PropType" 508 }); 509 writer.element("xsd:element", new String [] { 510 "name", "LNum", 511 "type", "PropType" 512 }); 513 writer.element("xsd:element", new String [] { 514 "name", "DisplayInfo", 515 "type", "PropType", 516 "minOccurs", "0", 517 "maxOccurs", "unbounded" 518 }); 519 if (false) writer.element("xsd:element", new String [] { 520 "name", "PARENT_MEMBER_NAME", 521 "type", "PropType", 522 "minOccurs", "0", 523 "maxOccurs", "unbounded" 524 }); 525 writer.endElement(); 527 writer.startElement("xsd:sequence"); 529 writer.element("xsd:any", new String [] { 530 "processContents", "lax", 531 "minOccurs", "0", 532 "maxOccurs", "unbounded" 533 }); 534 writer.endElement(); 536 writer.endElement(); writer.endElement(); writer.element("xsd:attribute", new String [] { 539 "name", "name", 540 "type", "xsd:string", 541 "use", "required" 542 }); 543 writer.endElement(); } 545 writer.endElement(); writer.element("xsd:attribute", new String [] { 547 "name", "name", 548 "type", "xsd:string" 549 }); 550 writer.endElement(); writer.endElement(); } 553 writer.endElement(); writer.endElement(); writer.endElement(); } 557 558 560 { writer.startElement("xsd:element", new String [] { 562 "name", "CellInfo" 563 }); 564 writer.startElement("xsd:complexType"); 565 writer.startElement("xsd:sequence"); 566 writer.startElement("xsd:sequence", new String [] { 567 "minOccurs", "0", 568 "maxOccurs", "unbounded" 569 }); 570 writer.startElement("xsd:choice"); 571 writer.element("xsd:element", new String [] { 572 "name", "Value", 573 "type", "PropType" 574 }); 575 writer.element("xsd:element", new String [] { 576 "name", "FmtValue", 577 "type", "PropType" 578 }); 579 writer.element("xsd:element", new String [] { 580 "name", "BackColor", 581 "type", "PropType" 582 }); 583 writer.element("xsd:element", new String [] { 584 "name", "ForeColor", 585 "type", "PropType" 586 }); 587 writer.element("xsd:element", new String [] { 588 "name", "FontName", 589 "type", "PropType" 590 }); 591 writer.element("xsd:element", new String [] { 592 "name", "FontSize", 593 "type", "PropType" 594 }); 595 writer.element("xsd:element", new String [] { 596 "name", "FontFlags", 597 "type", "PropType" 598 }); 599 writer.element("xsd:element", new String [] { 600 "name", "FormatString", 601 "type", "PropType" 602 }); 603 writer.element("xsd:element", new String [] { 604 "name", "NonEmptyBehavior", 605 "type", "PropType" 606 }); 607 writer.element("xsd:element", new String [] { 608 "name", "SolveOrder", 609 "type", "PropType" 610 }); 611 writer.element("xsd:element", new String [] { 612 "name", "Updateable", 613 "type", "PropType" 614 }); 615 writer.element("xsd:element", new String [] { 616 "name", "Visible", 617 "type", "PropType" 618 }); 619 writer.element("xsd:element", new String [] { 620 "name", "Expression", 621 "type", "PropType" 622 }); 623 writer.endElement(); writer.endElement(); writer.startElement("xsd:sequence", new String [] { 626 "maxOccurs", "unbounded", 627 "minOccurs", "0" 628 }); 629 writer.element("xsd:any", new String [] { 630 "processContents", "lax", 631 "maxOccurs", "unbounded" 632 }); 633 writer.endElement(); writer.endElement(); writer.endElement(); writer.endElement(); } 638 639 writer.endElement(); writer.endElement(); 642 644 writer.startElement("xsd:complexType", new String [] { 645 "name", "Axes" 646 }); 647 writer.startElement("xsd:sequence", new String [] { 648 "maxOccurs", "unbounded" 649 }); 650 { writer.startElement("xsd:element", new String [] { 652 "name", "Axis" 653 }); 654 writer.startElement("xsd:complexType"); 655 writer.startElement("xsd:choice", new String [] { 656 "minOccurs", "0", 657 "maxOccurs", "unbounded" 658 }); 659 writer.element("xsd:element", new String [] { 660 "name", "CrossProduct", 661 "type", "CrossProductType" 662 }); 663 writer.element("xsd:element", new String [] { 664 "name", "Tuples", 665 "type", "TuplesType" 666 }); 667 writer.element("xsd:element", new String [] { 668 "name", "Members", 669 "type", "MembersType" 670 }); 671 writer.endElement(); writer.element("xsd:attribute", new String [] { 673 "name", "name", 674 "type", "xsd:string" 675 }); 676 writer.endElement(); } 678 writer.endElement(); writer.endElement(); writer.endElement(); 682 684 writer.startElement("xsd:complexType", new String [] { 685 "name", "CellData" 686 }); 687 writer.startElement("xsd:sequence"); 688 { writer.startElement("xsd:element", new String [] { 690 "name", "Cell", 691 "minOccurs", "0", 692 "maxOccurs", "unbounded" 693 }); 694 writer.startElement("xsd:complexType"); 695 writer.startElement("xsd:sequence", new String [] { 696 "maxOccurs", "unbounded" 697 }); 698 writer.startElement("xsd:choice"); 699 writer.element("xsd:element", new String [] { 700 "name", "Value" 701 }); 702 writer.element("xsd:element", new String [] { 703 "name", "FmtValue", 704 "type", "xsd:string" 705 }); 706 writer.element("xsd:element", new String [] { 707 "name", "BackColor", 708 "type", "xsd:unsignedInt" 709 }); 710 writer.element("xsd:element", new String [] { 711 "name", "ForeColor", 712 "type", "xsd:unsignedInt" 713 }); 714 writer.element("xsd:element", new String [] { 715 "name", "FontName", 716 "type", "xsd:string" 717 }); 718 writer.element("xsd:element", new String [] { 719 "name", "FontSize", 720 "type", "xsd:unsignedShort" 721 }); 722 writer.element("xsd:element", new String [] { 723 "name", "FontFlags", 724 "type", "xsd:unsignedInt" 725 }); 726 writer.element("xsd:element", new String [] { 727 "name", "FormatString", 728 "type", "xsd:string" 729 }); 730 writer.element("xsd:element", new String [] { 731 "name", "NonEmptyBehavior", 732 "type", "xsd:unsignedShort" 733 }); 734 writer.element("xsd:element", new String [] { 735 "name", "SolveOrder", 736 "type", "xsd:unsignedInt" 737 }); 738 writer.element("xsd:element", new String [] { 739 "name", "Updateable", 740 "type", "xsd:unsignedInt" 741 }); 742 writer.element("xsd:element", new String [] { 743 "name", "Visible", 744 "type", "xsd:unsignedInt" 745 }); 746 writer.element("xsd:element", new String [] { 747 "name", "Expression", 748 "type", "xsd:string" 749 }); 750 writer.endElement(); writer.endElement(); writer.element("xsd:attribute", new String [] { 753 "name", "CellOrdinal", 754 "type", "xsd:unsignedInt", 755 "use", "required" 756 }); 757 writer.endElement(); writer.endElement(); } 760 writer.endElement(); writer.endElement(); 763 { writer.startElement("xsd:element", new String [] { 765 "name", "root" 766 }); 767 writer.startElement("xsd:complexType"); 768 writer.startElement("xsd:sequence", new String [] { 769 "maxOccurs", "unbounded" 770 }); 771 writer.element("xsd:element", new String [] { 772 "name", "OlapInfo", 773 "type", "OlapInfo" 774 }); 775 writer.element("xsd:element", new String [] { 776 "name", "Axes", 777 "type", "Axes" 778 }); 779 writer.element("xsd:element", new String [] { 780 "name", "CellData", 781 "type", "CellData" 782 }); 783 writer.endElement(); writer.endElement(); writer.endElement(); } 787 788 writer.endElement(); } 790 791 static void writeEmptyDatasetXmlSchema(SaxWriter writer, int settype) { 792 String setNsXmla = XmlaConstants.NS_XMLA_ROWSET; 793 writer.startElement("xsd:schema", new String [] { 794 "xmlns:xsd", XmlaConstants.NS_XSD, 795 "targetNamespace", setNsXmla, 796 "xmlns", setNsXmla, 797 "xmlns:xsi", XmlaConstants.NS_XSI, 798 "xmlns:sql", NS_XML_SQL, 799 "elementFormDefault", "qualified" 800 }); 801 802 writer.element("xsd:element", new String [] { 803 "name", "root" 804 }); 805 806 writer.endElement(); } 808 809 private QueryResult executeDrillThroughQuery(XmlaRequest request) 810 throws XmlaException { 811 812 checkFormat(request); 813 814 DataSourcesConfig.DataSource ds = getDataSource(request); 815 DataSourcesConfig.Catalog dsCatalog = getCatalog(request, ds); 816 String role = request.getRole(); 817 final Map<String , String > properties = request.getProperties(); 818 819 final RolapConnection connection = 820 (RolapConnection) getConnection(dsCatalog, role); 821 822 final String statement = request.getStatement(); 823 final Query query = connection.parseQuery(statement); 824 query.setResultStyle(ResultStyle.LIST); 825 final Result result = connection.execute(query); 826 Cell dtCell = result.getCell(new int[] {0, 0}); 827 828 if (!dtCell.canDrillThrough()) { 829 throw new XmlaException( 830 SERVER_FAULT_FC, 831 HSB_DRILL_THROUGH_NOT_ALLOWED_CODE, 832 HSB_DRILL_THROUGH_NOT_ALLOWED_FAULT_FS, 833 Util.newError("Cannot do DrillThrough operation on the cell")); 834 } 835 836 String dtSql = dtCell.getDrillThroughSQL(true); 837 java.sql.Connection sqlConn = null; 838 ResultSet rs = null; 839 840 try { 841 final String advancedFlag = 842 properties.get(PropertyDefinition.AdvancedFlag.name()); 843 if ("true".equals(advancedFlag)) { 844 final Position position = result.getAxes()[0].getPositions().get(0); 845 Member[] members = position.toArray(new Member[position.size()]); 846 847 CellRequest cellRequest = 848 RolapAggregationManager.makeRequest(members, false, false); 849 List<MondrianDef.Relation> relationList = 850 new ArrayList<MondrianDef.Relation>(); 851 final RolapStar.Table factTable = 852 cellRequest.getMeasure().getStar().getFactTable(); 853 MondrianDef.Relation relation = factTable.getRelation(); 854 relationList.add(relation); 855 856 for (RolapStar.Table table : factTable.getChildren()) { 857 relationList.add(table.getRelation()); 858 } 859 List<String > truncatedTableList = new ArrayList<String >(); 860 sqlConn = connection.getDataSource().getConnection(); 861 Statement stmt = sqlConn.createStatement(); 862 List<List<String >> fields = new ArrayList<List<String >>(); 863 864 Map<String , List<String >> tableFieldMap = 865 new HashMap<String , List<String >>(); 866 for (MondrianDef.Relation relation1 : relationList) { 867 final String tableName = relation1.toString(); 868 List<String > fieldNameList = new ArrayList<String >(); 869 dtSql = "SELECT * FROM " + tableName + " WHERE 1=2"; 871 rs = stmt.executeQuery(dtSql); 872 ResultSetMetaData rsMeta = rs.getMetaData(); 873 for (int j = 1; j <= rsMeta.getColumnCount(); j++) { 874 String colName = rsMeta.getColumnName(j); 875 boolean colNameExists = false; 876 for (List<String > prvField : fields) { 877 if (prvField.contains(colName)) { 878 colNameExists = true; 879 break; 880 } 881 } 882 if (!colNameExists) { 883 fieldNameList.add(rsMeta.getColumnName(j)); 884 } 885 } 886 fields.add(fieldNameList); 887 String truncatedTableName = 888 tableName.substring(tableName.lastIndexOf(".") + 1); 889 truncatedTableList.add(truncatedTableName); 890 tableFieldMap.put(truncatedTableName, fieldNameList); 891 } 892 return new TabularRowSet(tableFieldMap, truncatedTableList); 893 } else { 894 int count = -1; 895 if (MondrianProperties.instance().EnableTotalCount.booleanValue()) { 896 count = dtCell.getDrillThroughCount(); 897 } 898 899 sqlConn = connection.getDataSource().getConnection(); 900 if (LOGGER.isDebugEnabled()) { 901 LOGGER.debug("drill through sql: " + dtSql); 902 } 903 int resultSetType = ResultSet.TYPE_SCROLL_INSENSITIVE; 904 int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY; 905 if (!sqlConn.getMetaData().supportsResultSetConcurrency( 906 ResultSet.TYPE_SCROLL_INSENSITIVE, 907 ResultSet.CONCUR_READ_ONLY)) { 908 resultSetType = ResultSet.TYPE_FORWARD_ONLY; 911 } 912 SqlStatement stmt = 913 RolapUtil.executeQuery( 914 connection.getDataSource(), dtSql, -1, 915 "XmlaHandler.executeDrillThroughQuery", 916 "Error in drill through", 917 resultSetType, resultSetConcurrency); 918 return new TabularRowSet( 919 stmt, request.drillThroughMaxRows(), 920 request.drillThroughFirstRowset(), count, 921 resultSetType); 922 } 923 } catch (XmlaException xex) { 924 throw xex; 925 } catch (SQLException sqle) { 926 throw new XmlaException( 927 SERVER_FAULT_FC, 928 HSB_DRILL_THROUGH_SQL_CODE, 929 HSB_DRILL_THROUGH_SQL_FAULT_FS, 930 Util.newError(sqle, "Error in drill through")); 931 } catch (RuntimeException e) { 932 throw new XmlaException( 933 SERVER_FAULT_FC, 934 HSB_DRILL_THROUGH_SQL_CODE, 935 HSB_DRILL_THROUGH_SQL_FAULT_FS, 936 e); 937 } finally { 938 try { 939 if (rs != null) rs.close(); 940 } catch (SQLException ignored) { 941 } 942 try { 943 if (sqlConn != null && !sqlConn.isClosed()) sqlConn.close(); 944 } catch (SQLException ignored) { 945 } 946 } 947 } 948 949 static class TabularRowSet implements QueryResult { 950 private final String [] headers; 951 private final List<Object []> rows; 952 private int totalCount; 953 954 968 public TabularRowSet( 969 SqlStatement stmt, 970 int maxRows, 971 int firstRowset, 972 int totalCount, 973 int resultSetType) 974 { 975 this.totalCount = totalCount; 976 ResultSet rs = stmt.getResultSet(); 977 try { 978 ResultSetMetaData md = rs.getMetaData(); 979 int columnCount = md.getColumnCount(); 980 981 headers = new String [columnCount]; 983 for (int i = 0; i < columnCount; i++) { 984 headers[i] = md.getColumnName(i + 1); 985 } 986 987 int firstRow = (firstRowset <= 0 ? 1 : firstRowset); 989 if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) { 990 for (int i = 0; i < firstRow; ++i) { 991 if (!rs.next()) { 992 break; 993 } 994 } 995 } else { 996 rs.absolute(firstRow); 997 } 998 999 rows = new ArrayList<Object []>(); 1001 maxRows = (maxRows <= 0 ? Integer.MAX_VALUE : maxRows); 1002 do { 1003 Object [] row = new Object [columnCount]; 1004 for (int i = 0; i < columnCount; i++) { 1005 row[i] = rs.getObject(i + 1); 1006 } 1007 rows.add(row); 1008 } while (rs.next() && --maxRows > 0); 1009 } catch (SQLException e) { 1010 throw stmt.handle(e); 1011 } finally { 1012 stmt.close(); 1013 } 1014 } 1015 1016 1023 public TabularRowSet( 1024 Map<String , List<String >> tableFieldMap, List<String > tableList) 1025 { 1026 List<String > headerList = new ArrayList<String >(); 1027 for (String tableName : tableList) { 1028 List<String > fieldNames = tableFieldMap.get(tableName); 1029 for (String fieldName : fieldNames) { 1030 headerList.add(tableName + "." + fieldName); 1031 } 1032 } 1033 headers = headerList.toArray(new String [headerList.size()]); 1034 rows = new ArrayList<Object []>(); 1035 Object [] row = new Object [headers.length]; 1036 for (int k = 0; k < row.length; k++) { 1037 row[k] = k; 1038 } 1039 rows.add(row); 1040 } 1041 1042 public void unparse(SaxWriter writer) throws SAXException { 1043 String [] encodedHeader = new String [headers.length]; 1044 for (int i = 0; i < headers.length; i++) { 1045 encodedHeader[i] = XmlaUtil.encodeElementName(headers[i]); 1049 } 1050 1051 if (totalCount >= 0) { 1053 String countStr = Integer.toString(totalCount); 1054 writer.startElement("row"); 1055 for (String anEncodedHeader : encodedHeader) { 1056 writer.startElement(anEncodedHeader); 1057 writer.characters(countStr); 1058 writer.endElement(); 1059 } 1060 writer.endElement(); } 1062 1063 for (Object [] row : rows) { 1064 writer.startElement("row"); 1065 for (int i = 0; i < row.length; i++) { 1066 writer.startElement(encodedHeader[i]); 1067 Object value = row[i]; 1068 if (value == null) { 1069 writer.characters("null"); 1070 } else { 1071 String valueString = value.toString(); 1072 if (value instanceof Number ) { 1073 valueString = 1074 XmlaUtil.normalizeNumericString(valueString); 1075 } 1076 writer.characters(valueString); 1077 } 1078 writer.endElement(); 1079 } 1080 writer.endElement(); } 1082 } 1083 1084 public TabularRowSet(ResultSet rs) throws SQLException { 1085 ResultSetMetaData md = rs.getMetaData(); 1086 int columnCount = md.getColumnCount(); 1087 1088 headers = new String [columnCount]; 1090 for (int i = 0; i < columnCount; i++) { 1091 headers[i] = md.getColumnName(i + 1); 1092 } 1093 1094 rows = new ArrayList<Object []>(); 1096 while (rs.next()) { 1097 Object [] row = new Object [columnCount]; 1098 for (int i = 0; i < columnCount; i++) { 1099 row[i] = rs.getObject(i + 1); 1100 } 1101 rows.add(row); 1102 } 1103 } 1104 } 1105 1106 private QueryResult executeQuery(XmlaRequest request) 1107 throws XmlaException { 1108 final String statement = request.getStatement(); 1109 1110 if (LOGGER.isDebugEnabled()) { 1111 LOGGER.debug("mdx: \"" + statement + "\""); 1112 } 1113 1114 if ((statement == null) || (statement.length() == 0)) { 1115 return null; 1116 } else { 1117 checkFormat(request); 1118 1119 DataSourcesConfig.DataSource ds = getDataSource(request); 1120 DataSourcesConfig.Catalog dsCatalog = getCatalog(request, ds); 1121 String role = request.getRole(); 1122 1123 final Connection connection = getConnection(dsCatalog, role); 1124 1125 final Query query; 1126 try { 1127 query = connection.parseQuery(statement); 1128 query.setResultStyle(ResultStyle.LIST); 1129 } catch (XmlaException ex) { 1130 throw ex; 1131 } catch (Exception ex) { 1132 throw new XmlaException( 1133 CLIENT_FAULT_FC, 1134 HSB_PARSE_QUERY_CODE, 1135 HSB_PARSE_QUERY_FAULT_FS, 1136 ex); 1137 } 1138 final Result result; 1139 try { 1140 result = connection.execute(query); 1141 } catch (XmlaException ex) { 1142 throw ex; 1143 } catch (Exception ex) { 1144 throw new XmlaException( 1145 SERVER_FAULT_FC, 1146 HSB_EXECUTE_QUERY_CODE, 1147 HSB_EXECUTE_QUERY_FAULT_FS, 1148 ex); 1149 } 1150 1151 final String formatName = request.getProperties().get( 1152 PropertyDefinition.Format.name()); 1153 Enumeration.Format format = valueOf(Enumeration.Format.class, formatName, 1154 null); 1155 1156 if (format == Enumeration.Format.Multidimensional) { 1157 return new MDDataSet_Multidimensional(result); 1158 } else { 1159 return new MDDataSet_Tabular(result); 1160 } 1161 } 1162 } 1163 1164 1178 protected static String deduceValueType(Cell cell, final Object value) { 1179 String datatype = (String ) 1180 cell.getPropertyValue(Property.DATATYPE.getName()); 1181 if (datatype != null) { 1182 if (datatype.equals("Integer")) { 1183 return "xsd:int"; 1184 } else if (datatype.equals("Numeric")) { 1185 return "xsd:double"; 1186 } else { 1187 return "xsd:string"; 1188 } 1189 } else if (value instanceof Integer || value instanceof Long ) { 1190 return "xsd:int"; 1191 } else if (value instanceof Double || value instanceof BigDecimal ) { 1192 return "xsd:double"; 1193 } else { 1194 return "xsd:string"; 1195 } 1196 } 1197 protected static String deduceValueType(Evaluator evaluator, 1198 final Object value) { 1199 String datatype = (String ) 1200 evaluator.getProperty(Property.DATATYPE.getName(), null); 1201 if (datatype != null) { 1202 if (datatype.equals("Integer")) { 1203 return "xsd:int"; 1204 } else if (datatype.equals("Numeric")) { 1205 return "xsd:double"; 1206 } else { 1207 return "xsd:string"; 1208 } 1209 } else if (value instanceof Integer || value instanceof Long ) { 1210 return "xsd:int"; 1211 } else if (value instanceof Double || value instanceof BigDecimal ) { 1212 return "xsd:double"; 1213 } else { 1214 return "xsd:string"; 1215 } 1216 } 1217 1218 static abstract class MDDataSet implements QueryResult { 1219 protected final Result result; 1220 1221 protected static final String [] cellProps = new String [] { 1222 "Value", 1223 "FmtValue", 1224 "FormatString"}; 1225 1226 protected static final String [] cellPropLongs = new String [] { 1227 Property.VALUE.name, 1228 Property.FORMATTED_VALUE.name, 1229 Property.FORMAT_STRING.name}; 1230 1231 protected static final String [] defaultProps = new String [] { 1232 "UName", 1233 "Caption", 1234 "LName", 1235 "LNum", 1236 "DisplayInfo", 1237 }; 1240 protected static final Map<String , String > longPropNames = new HashMap<String , String >(); 1241 1242 static { 1243 longPropNames.put("UName", Property.MEMBER_UNIQUE_NAME.name); 1244 longPropNames.put("Caption", Property.MEMBER_CAPTION.name); 1245 longPropNames.put("LName", Property.LEVEL_UNIQUE_NAME.name); 1246 longPropNames.put("LNum", Property.LEVEL_NUMBER.name); 1247 longPropNames.put("DisplayInfo", Property.DISPLAY_INFO.name); 1248 } 1249 1250 protected MDDataSet(Result result) { 1251 this.result = result; 1252 } 1253 } 1254 1255 static class MDDataSet_Multidimensional extends MDDataSet { 1256 private Hierarchy[] slicerAxisHierarchies; 1257 1258 protected MDDataSet_Multidimensional(Result result) { 1259 super(result); 1260 } 1261 1262 public void unparse(SaxWriter writer) throws SAXException { 1263 olapInfo(writer); 1264 axes(writer); 1265 cellData(writer); 1266 } 1267 1268 private void olapInfo(SaxWriter writer) { 1269 Cube cube = result.getQuery().getCube(); 1271 List<Hierarchy> hierarchyList = new ArrayList<Hierarchy>(); 1272 Dimension[] dimensions = cube.getDimensions(); 1273 for (Dimension dimension : dimensions) { 1274 Hierarchy[] hierarchies = dimension.getHierarchies(); 1275 for (Hierarchy hierarchy : hierarchies) { 1276 hierarchyList.add(hierarchy); 1277 } 1278 } 1279 1280 writer.startElement("OlapInfo"); 1281 writer.startElement("CubeInfo"); 1282 writer.startElement("Cube"); 1283 writer.startElement("CubeName"); 1284 writer.characters(result.getQuery().getCube().getName()); 1285 writer.endElement(); 1286 writer.endElement(); 1287 writer.endElement(); 1289 writer.startElement("AxesInfo"); 1292 final Axis[] axes = result.getAxes(); 1293 final QueryAxis[] queryAxes = result.getQuery().getAxes(); 1294 List<Hierarchy> axisHierarchyList = new ArrayList<Hierarchy>(); 1296 for (int i = 0; i < axes.length; i++) { 1297 Hierarchy[] hiers = 1298 axisInfo(writer, axes[i], queryAxes[i], "Axis" + i); 1299 for (Hierarchy hier : hiers) { 1300 axisHierarchyList.add(hier); 1301 } 1302 1303 } 1304 for (Hierarchy hier1 : axisHierarchyList) { 1312 Dimension dim = hier1.getDimension(); 1313 Hierarchy[] hiers = dim.getHierarchies(); 1314 for (Hierarchy h : hiers) { 1315 String uniqueName = h.getUniqueName(); 1316 for (Iterator<Hierarchy> it2 = hierarchyList.iterator(); it2 1317 .hasNext();) { 1318 Hierarchy hier2 = it2.next(); 1319 if (uniqueName.equals(hier2.getUniqueName())) { 1320 it2.remove(); 1321 break; 1322 } 1323 } 1324 } 1325 } 1326 1327 Hierarchy[] hierarchies = 1331 hierarchyList.toArray(new Hierarchy[hierarchyList.size()]); 1332 writer.startElement("AxisInfo", 1333 new String [] { "name", "SlicerAxis"}); 1334 final QueryAxis slicerAxis = result.getQuery().getSlicerAxis(); 1335 writeHierarchyInfo(writer, hierarchies, getProps(slicerAxis)); 1336 writer.endElement(); slicerAxisHierarchies = hierarchies; 1338 1341 1342 writer.endElement(); writer.startElement("CellInfo"); 1345 writer.element("Value", new String [] { 1346 "name", "VALUE"}); 1347 writer.element("FmtValue", new String [] { 1348 "name", "FORMATTED_VALUE"}); 1349 writer.element("FormatString", new String [] { 1350 "name", "FORMAT_STRING"}); 1351 writer.endElement(); writer.endElement(); } 1355 1356 private Hierarchy[] axisInfo( 1357 SaxWriter writer, 1358 Axis axis, 1359 QueryAxis queryAxis, 1360 String axisName) { 1361 1362 writer.startElement("AxisInfo", new String [] { "name", axisName}); 1363 1364 Hierarchy[] hierarchies; 1365 Iterator<Position> it = axis.getPositions().iterator(); 1366 if (it.hasNext()) { 1367 final Position position = it.next(); 1368 List<Hierarchy> l = new ArrayList<Hierarchy>(); 1369 for (Member member: position) { 1370 l.add(member.getHierarchy()); 1371 } 1372 hierarchies = l.toArray(new Hierarchy[l.size()]); 1373 } else { 1374 hierarchies = new Hierarchy[0]; 1375 } 1378 String [] props = getProps(queryAxis); 1379 writeHierarchyInfo(writer, hierarchies, props); 1380 1381 writer.endElement(); 1383 return hierarchies; 1384 } 1385 1386 1387 private void writeHierarchyInfo( 1388 SaxWriter writer, 1389 Hierarchy[] hierarchies, 1390 String [] props) { 1391 1392 for (Hierarchy hierarchy : hierarchies) { 1393 writer.startElement( 1394 "HierarchyInfo", new String []{ 1395 "name", hierarchy.getName() 1396 }); 1397 for (final String prop : props) { 1398 String longPropName = longPropNames.get(prop); 1399 if (longPropName == null) { 1400 longPropName = prop; 1401 } 1402 writer.element( 1403 prop, new String []{ 1404 "name", 1405 hierarchy.getUniqueName() + "." + 1406 Util.quoteMdxIdentifier(longPropName), 1407 }); 1408 } 1409 writer.endElement(); } 1411 } 1412 1413 private void axes(SaxWriter writer) { 1414 writer.startElement("Axes"); 1415 final Axis[] axes = result.getAxes(); 1417 final QueryAxis[] queryAxes = result.getQuery().getAxes(); 1418 for (int i = 0; i < axes.length; i++) { 1419 final String [] props = getProps(queryAxes[i]); 1420 axis(writer, axes[i], props, "Axis" + i); 1421 } 1422 1423 Hierarchy[] hierarchies = slicerAxisHierarchies; 1427 writer.startElement("Axis", new String [] { "name", "SlicerAxis"}); 1428 writer.startElement("Tuples"); 1429 writer.startElement("Tuple"); 1430 1431 Map<String , Integer > memberMap = new HashMap<String , Integer >(); 1432 Member positionMember; 1433 Axis slicerAxis = result.getSlicerAxis(); 1434 if (slicerAxis.getPositions() != null && 1435 slicerAxis.getPositions().size() > 0) { 1436 final Position pos0 = slicerAxis.getPositions().get(0); 1437 int i = 0; 1438 for (Member member : pos0) { 1439 memberMap.put(member.getHierarchy().getName(), i++); 1440 } 1441 } 1442 1443 final QueryAxis slicerQueryAxis = result.getQuery().getSlicerAxis(); 1444 final List<Member> slicerMembers = 1445 result.getSlicerAxis().getPositions().get(0); 1446 for (Hierarchy hierarchy : hierarchies) { 1447 Member member = hierarchy.getDefaultMember(); 1450 final Integer indexPosition = 1451 memberMap.get(hierarchy.getName()); 1452 if (indexPosition != null) { 1453 positionMember = 1454 slicerAxis.getPositions().get(0).get(indexPosition); 1455 } else { 1456 positionMember = null; 1457 } 1458 for (Member slicerMember : slicerMembers) { 1459 if (slicerMember.getHierarchy().equals(hierarchy)) { 1460 member = slicerMember; 1461 break; 1462 } 1463 } 1464 1465 if (member != null) { 1466 if (positionMember != null) { 1467 writeMember( 1468 writer, positionMember, null, 1469 slicerAxis.getPositions().get(0), indexPosition, 1470 getProps(slicerQueryAxis)); 1471 } else { 1472 slicerAxis(writer, member, getProps(slicerQueryAxis)); 1473 } 1474 } else { 1475 LOGGER.warn( 1476 "Can not create SlicerAxis: " + 1477 "null default member for Hierarchy " + 1478 hierarchy.getUniqueName()); 1479 } 1480 } 1481 1482 1485 writer.endElement(); writer.endElement(); writer.endElement(); 1489 1490 1491 writer.endElement(); } 1493 1494 private String [] getProps(QueryAxis queryAxis) { 1495 if (queryAxis == null) { 1496 return defaultProps; 1497 } 1498 Id[] dimensionProperties = queryAxis.getDimensionProperties(); 1499 if (dimensionProperties.length == 0) { 1500 return defaultProps; 1501 } 1502 String [] props = new String [defaultProps.length + dimensionProperties.length]; 1503 System.arraycopy(defaultProps, 0, props, 0, defaultProps.length); 1504 for (int i = 0; i < dimensionProperties.length; i++) { 1505 props[defaultProps.length + i] = 1506 dimensionProperties[i].toStringArray()[0]; 1507 } 1508 return props; 1509 } 1510 1511 private void axis(SaxWriter writer, Axis axis, String [] props, String axisName) { 1512 writer.startElement("Axis", new String [] { "name", axisName}); 1513 writer.startElement("Tuples"); 1514 1515 List<Position> positions = axis.getPositions(); 1516 Iterator<Position> pit = positions.iterator(); 1517 Position prevPosition = null; 1518 Position position = pit.hasNext() ? pit.next() : null; 1519 Position nextPosition = pit.hasNext() ? pit.next() : null; 1520 while (position != null) { 1521 writer.startElement("Tuple"); 1522 int k = 0; 1523 for (Member member: position) { 1524 writeMember( 1525 writer, member, prevPosition, nextPosition, k++, props); 1526 } 1527 writer.endElement(); prevPosition = position; 1529 position = nextPosition; 1530 nextPosition = pit.hasNext() ? pit.next() : null; 1531 } 1532 writer.endElement(); writer.endElement(); } 1535 1536 private void writeMember( 1537 SaxWriter writer, 1538 Member member, 1539 Position prevPosition, 1540 Position nextPosition, 1541 int k, 1542 String [] props) 1543 { 1544 writer.startElement("Member", new String [] { 1545 "Hierarchy", member.getHierarchy().getName()}); 1546 for (String prop : props) { 1547 Object value; 1548 String propLong = longPropNames.get(prop); 1549 if (propLong == null) { 1550 propLong = prop; 1551 } 1552 if (propLong.equals(Property.DISPLAY_INFO.name)) { 1553 Integer childrenCard = (Integer ) member 1554 .getPropertyValue(Property.CHILDREN_CARDINALITY.name); 1555 value = calculateDisplayInfo(prevPosition, 1556 nextPosition, 1557 member, k, childrenCard); 1558 } else if (propLong.equals(Property.DEPTH.name)) { 1559 value = member.getDepth(); 1560 } else { 1561 value = member.getPropertyValue(propLong); 1562 } 1563 if (value != null) { 1564 writer.startElement(prop); writer.characters(value.toString()); 1566 writer.endElement(); } 1568 } 1569 writer.endElement(); } 1571 1572 private void slicerAxis( 1573 SaxWriter writer, Member member, String [] props) { 1574 writer.startElement("Member", new String [] { 1575 "Hierarchy", member.getHierarchy().getName()}); 1576 for (String prop : props) { 1577 Object value; 1578 String propLong = longPropNames.get(prop); 1579 if (propLong == null) { 1580 propLong = prop; 1581 } 1582 if (propLong.equals(Property.DISPLAY_INFO.name)) { 1583 Integer childrenCard = 1584 (Integer ) member 1585 .getPropertyValue(Property.CHILDREN_CARDINALITY.name); 1586 int displayInfo = 0xffff & childrenCard; 1589 1595 value = displayInfo; 1596 } else if (propLong.equals(Property.DEPTH.name)) { 1597 value = member.getDepth(); 1598 } else { 1599 value = member.getPropertyValue(propLong); 1600 } 1601 if (value != null) { 1602 writer.startElement(prop); writer.characters(value.toString()); 1604 writer.endElement(); } 1606 } 1607 writer.endElement(); } 1609 1610 private int calculateDisplayInfo( 1611 Position prevPosition, Position nextPosition, 1612 Member currentMember, int memberOrdinal, int childrenCount) 1613 { 1614 int displayInfo = 0xffff & childrenCount; 1615 1616 if (nextPosition != null) { 1617 String currentUName = currentMember.getUniqueName(); 1618 Member nextMember = nextPosition.get(memberOrdinal); 1619 String nextParentUName = nextMember.getParentUniqueName(); 1620 if (currentUName.equals(nextParentUName)) { 1621 displayInfo |= 0x10000; 1622 } 1623 } 1624 if (prevPosition != null) { 1625 String currentParentUName = currentMember.getParentUniqueName(); 1626 Member prevMember = prevPosition.get(memberOrdinal); 1627 String prevParentUName = prevMember.getParentUniqueName(); 1628 if (currentParentUName != null && 1629 currentParentUName.equals(prevParentUName)) { 1630 displayInfo |= 0x20000; 1631 } 1632 } 1633 return displayInfo; 1634 } 1635 1636 private void cellData(SaxWriter writer) { 1637 writer.startElement("CellData"); 1638 final int axisCount = result.getAxes().length; 1639 int[] pos = new int[axisCount]; 1640 int[] cellOrdinal = new int[] {0}; 1641 1642 Evaluator evaluator = RolapUtil.createEvaluator(result.getQuery()); 1643 int axisOrdinal = axisCount-1; 1644 recurse(writer, pos, axisOrdinal, evaluator, cellOrdinal); 1645 1646 writer.endElement(); } 1648 private void recurse(SaxWriter writer, int[] pos, 1649 int axisOrdinal, Evaluator evaluator, int[] cellOrdinal) { 1650 if (axisOrdinal < 0) { 1651 emitCell(writer, pos, evaluator, cellOrdinal[0]++); 1652 1653 } else { 1654 Axis axis = result.getAxes()[axisOrdinal]; 1655 List<Position> positions = axis.getPositions(); 1656 int i = 0; 1657 for (Position position: positions) { 1658 pos[axisOrdinal] = i; 1659 evaluator.setContext(position); 1660 recurse(writer, pos, axisOrdinal - 1, evaluator, cellOrdinal); 1661 i++; 1662 } 1663 } 1664 } 1665 private void emitCell(SaxWriter writer, int[] pos, 1666 Evaluator evaluator, int ordinal) { 1667 Cell cell = result.getCell(pos); 1668 if (cell.isNull()) { 1669 return; 1671 } 1672 1673 writer.startElement("Cell", new String [] { 1674 "CellOrdinal", Integer.toString(ordinal)}); 1675 for (int i = 0; i < cellProps.length; i++) { 1676 String cellPropLong = cellPropLongs[i]; 1677 final Object value = cell.getPropertyValue(cellPropLong); 1678 1679 if (value != null) { 1680 if (cellPropLong.equals(Property.VALUE.name)) { 1681 String valueType = deduceValueType(evaluator, value); 1682 writer.startElement(cellProps[i], new String [] {"xsi:type", valueType}); 1683 } else { 1684 writer.startElement(cellProps[i]); 1685 } 1686 1687 String valueString = value.toString(); 1688 1689 if (cellPropLong.equals(Property.VALUE.name) && 1690 value instanceof Number ) { 1691 valueString = XmlaUtil.normalizeNumericString(valueString); 1692 } 1693 1694 writer.characters(valueString); 1695 writer.endElement(); 1696 } 1697 } 1698 writer.endElement(); } 1700 } 1701 1702 static abstract class ColumnHandler { 1703 protected final String name; 1704 protected final String encodedName; 1705 1706 protected ColumnHandler(String name) { 1707 this.name = name; 1708 this.encodedName = XmlaUtil.encodeElementName(this.name); 1709 } 1710 1711 abstract void write(SaxWriter writer, Cell cell, Member[] members); 1712 abstract void metadata(SaxWriter writer); 1713 } 1714 1715 1716 1721 static class CellColumnHandler extends ColumnHandler { 1722 1723 CellColumnHandler(String name) { 1724 super(name); 1725 } 1726 1727 public void metadata(SaxWriter writer) { 1728 writer.element("xsd:element", new String [] { 1729 "minOccurs", "0", 1730 "name", encodedName, 1731 "sql:field", name, 1732 }); 1733 } 1734 1735 public void write( 1736 SaxWriter writer, Cell cell, Member[] members) { 1737 if (cell.isNull()) { 1738 return; 1739 } 1740 Object value = cell.getValue(); 1741 String valueString = value.toString(); 1742 String valueType = deduceValueType(cell, value); 1743 1744 writer.startElement(encodedName, new String [] { 1745 "xsi:type", valueType}); 1746 if (value instanceof Number ) { 1747 valueString = XmlaUtil.normalizeNumericString(valueString); 1748 } 1749 writer.characters(valueString); 1750 writer.endElement(); 1751 } 1752 } 1753 1754 1759 static class MemberColumnHandler extends ColumnHandler { 1760 private final String property; 1761 private final Level level; 1762 private final int memberOrdinal; 1763 1764 public MemberColumnHandler( 1765 String property, Level level, int memberOrdinal) { 1766 super(level.getUniqueName() + "." + 1767 Util.quoteMdxIdentifier(property)); 1768 this.property = property; 1769 this.level = level; 1770 this.memberOrdinal = memberOrdinal; 1771 } 1772 1773 public void metadata(SaxWriter writer) { 1774 writer.element("xsd:element", new String [] { 1775 "minOccurs", "0", 1776 "name", encodedName, 1777 "sql:field", name, 1778 "type", "xsd:string", 1779 }); 1780 } 1781 1782 public void write( 1783 SaxWriter writer, Cell cell, Member[] members) { 1784 Member member = members[memberOrdinal]; 1785 final int depth = level.getDepth(); 1786 if (member.getDepth() < depth) { 1787 return; 1790 } 1791 while (member.getDepth() > depth) { 1792 member = member.getParentMember(); 1793 } 1794 final Object propertyValue = member.getPropertyValue(property); 1795 if (propertyValue == null) { 1796 return; 1797 } 1798 1799 writer.startElement(encodedName); 1800 writer.characters(propertyValue.toString()); 1801 writer.endElement(); 1802 } 1803 } 1804 1805 static class MDDataSet_Tabular extends MDDataSet { 1806 private final boolean empty; 1807 private final int[] pos; 1808 private final int axisCount; 1809 private int cellOrdinal; 1810 1811 private static final Id[] MemberCaptionIdArray = { 1812 new Id(new Id.Segment(Property.MEMBER_CAPTION.name, Id.Quoting.QUOTED)) 1813 }; 1814 private final Member[] members; 1815 private final ColumnHandler[] columnHandlers; 1816 1817 public MDDataSet_Tabular(Result result) { 1818 super(result); 1819 final Axis[] axes = result.getAxes(); 1820 axisCount = axes.length; 1821 pos = new int[axisCount]; 1822 1823 boolean empty = false; 1826 int dimensionCount = 0; 1827 for (int i = axes.length - 1; i > 0; i--) { 1828 Axis axis = axes[i]; 1829 if (axis.getPositions().size() == 0) { 1830 empty = true; 1832 continue; 1833 } 1834 dimensionCount += axis.getPositions().get(0).size(); 1835 } 1836 this.empty = empty; 1837 1838 Level[] levels = new Level[dimensionCount]; 1840 List<ColumnHandler> columnHandlerList = new ArrayList<ColumnHandler>(); 1841 int memberOrdinal = 0; 1842 if (!empty) { 1843 for (int i = axes.length - 1; i > 0; i--) { 1844 final Axis axis = axes[i]; 1845 final QueryAxis queryAxis = result.getQuery().getAxes()[i]; 1846 final int z0 = memberOrdinal; final List<Position> positions = axis.getPositions(); 1848 int jj = 0; 1849 for (Position position: positions) { 1850 memberOrdinal = z0; for (Member member : position) { 1853 if (jj == 0 || 1854 member.getLevel().getDepth() > 1855 levels[memberOrdinal].getDepth()) { 1856 levels[memberOrdinal] = member.getLevel(); 1857 } 1858 } 1859 ++memberOrdinal; 1860 jj++; 1861 } 1862 1863 Id[] dimProps = queryAxis.getDimensionProperties(); 1866 if (dimProps.length == 0) { 1867 dimProps = MemberCaptionIdArray; 1868 } 1869 for (int j = z0; j < memberOrdinal; j++) { 1870 Level level = levels[j]; 1871 for (int k = 0; k <= level.getDepth(); k++) { 1872 final Level level2 = 1873 level.getHierarchy().getLevels()[k]; 1874 if (level2.isAll()) { 1875 continue; 1876 } 1877 for (Id dimProp : dimProps) { 1878 columnHandlerList.add( 1879 new MemberColumnHandler( 1880 dimProp.toStringArray()[0], 1881 level2, 1882 j)); 1883 } 1884 } 1885 } 1886 } 1887 } 1888 this.members = new Member[memberOrdinal]; 1889 1890 Axis columnsAxis = axes[0]; 1892 for (Position position : columnsAxis.getPositions()) { 1893 String name = null; 1894 int j = 0; 1895 for (Member member : position) { 1896 if (j == 0) { 1897 name = member.getUniqueName(); 1898 } else { 1899 name = name + "." + member.getUniqueName(); 1900 } 1901 j++; 1902 } 1903 columnHandlerList.add( 1904 new CellColumnHandler(name)); 1905 } 1906 1907 this.columnHandlers = 1908 columnHandlerList.toArray( 1909 new ColumnHandler[columnHandlerList.size()]); 1910 } 1911 1912 public void metadata(SaxWriter writer) { 1913 if (empty) { 1914 return; 1915 } 1916 writer.startElement("xsd:schema", new String [] { 1917 "xmlns:xsd", XmlaConstants.NS_XSD, 1918 "targetNamespace", NS_XMLA_ROWSET, 1919 "xmlns", NS_XMLA_ROWSET, 1920 "xmlns:xsi", XmlaConstants.NS_XSI, 1921 "xmlns:sql", NS_XML_SQL, 1922 "elementFormDefault", "qualified" 1923 }); 1924 1925 { writer.startElement("xsd:element", new String [] { 1927 "name", "root" 1928 }); 1929 writer.startElement("xsd:complexType"); 1930 writer.startElement("xsd:sequence"); 1931 writer.element("xsd:element", new String [] { 1932 "maxOccurs", "unbounded", 1933 "minOccurs", "0", 1934 "name", "row", 1935 "type", "row", 1936 }); 1937 writer.endElement(); writer.endElement(); writer.endElement(); } 1941 1942 { writer.startElement("xsd:simpleType", new String [] { 1944 "name", "uuid", 1945 }); 1946 writer.startElement("xsd:restriction", new String [] { 1947 "base", "xsd:string", 1948 }); 1949 writer.element("xsd:pattern", new String [] { 1950 "value", "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" 1951 }); 1952 writer.endElement(); writer.endElement(); } 1955 1956 { writer.startElement("xsd:complexType", new String [] { 1958 "name", "row", 1959 }); 1960 writer.startElement("xsd:sequence"); 1961 for (ColumnHandler columnHandler : columnHandlers) { 1962 columnHandler.metadata(writer); 1963 } 1964 writer.endElement(); writer.endElement(); } 1967 writer.endElement(); } 1969 1970 public void unparse(SaxWriter writer) throws SAXException { 1971 if (empty) { 1972 return; 1973 } 1974 cellData(writer); 1975 } 1976 1977 private void cellData(SaxWriter writer) throws SAXException { 1978 cellOrdinal = 0; 1979 if (axisCount == 0) { emitCell(writer, result.getCell(pos)); 1981 } else { 1982 recurse(writer, axisCount - 1, 0); 1983 } 1984 } 1985 1986 private void recurse( 1987 SaxWriter writer, 1988 int axis, 1989 final int headerOrdinal) throws SAXException { 1990 final List<Position> positions = result.getAxes()[axis].getPositions(); 1991 int i = 0; 1992 for (Position position: positions) { 1993 pos[axis] = i; 1994 if (axis == 0) { 1995 final Cell cell = result.getCell(pos); 1996 emitCell(writer, cell); 1997 } else { 1998 int ho = headerOrdinal; 2000 for (Member member : position) { 2001 members[ho++] = member; 2002 } 2003 2004 recurse(writer, axis - 1, ho); 2005 } 2006 i++; 2007 } 2008 } 2009 2010 private void emitCell(SaxWriter writer, Cell cell) { 2011 ++cellOrdinal; 2012 Util.discard(cellOrdinal); 2013 2014 final Object cellValue = cell.getValue(); 2016 if (cellValue == null) { 2017 return; 2018 } 2019 2020 writer.startElement("row"); 2021 for (ColumnHandler columnHandler : columnHandlers) { 2022 columnHandler.write(writer, cell, members); 2023 } 2024 writer.endElement(); 2025 } 2026 } 2027 2028 private void discover(XmlaRequest request, XmlaResponse response) 2029 throws XmlaException { 2030 2031 final RowsetDefinition rowsetDefinition = 2032 RowsetDefinition.valueOf(request.getRequestType()); 2033 Rowset rowset = rowsetDefinition.getRowset(request, this); 2034 2035 final String formatName = 2036 request.getProperties().get(PropertyDefinition.Format.name()); 2037 Enumeration.Format format = 2038 valueOf( 2039 Enumeration.Format.class, 2040 formatName, 2041 Enumeration.Format.Tabular); 2042 if (format != Enumeration.Format.Tabular) { 2043 throw new XmlaException( 2044 CLIENT_FAULT_FC, 2045 HSB_DISCOVER_FORMAT_CODE, 2046 HSB_DISCOVER_FORMAT_FAULT_FS, 2047 new UnsupportedOperationException ("<Format>: only 'Tabular' allowed in Discover method type")); 2048 } 2049 final String contentName = 2050 request.getProperties().get(PropertyDefinition.Content.name()); 2051 Enumeration.Content content = 2053 valueOf(Enumeration.Content.class, contentName, CONTENT_DEFAULT); 2054 2055 SaxWriter writer = response.getWriter(); 2056 writer.startDocument(); 2057 2058 writer.startElement(prefix + ":DiscoverResponse", new String [] { 2059 "xmlns:" + prefix, NS_XMLA}); 2060 writer.startElement(prefix + ":return"); 2061 writer.startElement("root", new String [] { 2062 "xmlns", NS_XMLA_ROWSET, 2063 "xmlns:xsi", NS_XSI, 2064 "xmlns:xsd", NS_XSD, 2065 "xmlns:EX", NS_XMLA_EX 2066 }); 2067 2068 if ((content == Enumeration.Content.Schema) 2069 || (content == Enumeration.Content.SchemaData)) { 2070 rowset.rowsetDefinition.writeRowsetXmlSchema(writer); 2071 } 2072 2073 try { 2074 if ((content == Enumeration.Content.Data) 2075 || (content == Enumeration.Content.SchemaData)) { 2076 rowset.unparse(response); 2077 } 2078 } catch (XmlaException xex) { 2079 throw xex; 2080 } catch (Throwable t) { 2081 throw new XmlaException( 2082 SERVER_FAULT_FC, 2083 HSB_DISCOVER_UNPARSE_CODE, 2084 HSB_DISCOVER_UNPARSE_FAULT_FS, 2085 t); 2086 2087 } finally { 2088 writer.endElement(); 2090 writer.endElement(); 2091 writer.endElement(); 2092 } 2093 2094 writer.endDocument(); 2095 } 2096 2097 2105 private <E extends Enum <E>> E valueOf( 2106 Class <E> enumType, 2107 String name, E defaultValue) 2108 { 2109 if (name == null) { 2110 return defaultValue; 2111 } else { 2112 try { 2113 return Enum.valueOf(enumType, name); 2114 } catch (IllegalArgumentException e) { 2115 return defaultValue; 2116 } 2117 } 2118 } 2119 2120 2129 protected Connection getConnection( 2130 DataSourcesConfig.Catalog catalog, 2131 String role) 2132 throws XmlaException { 2133 DataSourcesConfig.DataSource ds = catalog.getDataSource(); 2134 2135 Util.PropertyList connectProperties = 2136 Util.parseConnectString(catalog.getDataSourceInfo()); 2137 2138 String catalogUrl = catalogLocator.locate(catalog.definition); 2139 2140 if (LOGGER.isDebugEnabled()) { 2141 if (catalogUrl == null) { 2142 LOGGER.debug("XmlaHandler.getConnection: catalogUrl is null"); 2143 } else { 2144 LOGGER.debug("XmlaHandler.getConnection: catalogUrl=" + catalogUrl); 2145 } 2146 } 2147 2148 connectProperties.put("catalog", catalogUrl); 2149 2150 if (!DataSourcesConfig.DataSource.AUTH_MODE_UNAUTHENTICATED 2152 .equalsIgnoreCase( 2153 ds.getAuthenticationMode()) && 2154 null == role) 2155 { 2156 throw new XmlaException( 2157 CLIENT_FAULT_FC, 2158 HSB_ACCESS_DENIED_CODE, 2159 HSB_ACCESS_DENIED_FAULT_FS, 2160 new SecurityException ( 2161 "Access denied for data source needing authentication")); 2162 } 2163 2164 connectProperties.put("role", role); 2165 RolapConnection conn = 2166 (RolapConnection) DriverManager.getConnection( 2167 connectProperties, null, false); 2168 2169if (LOGGER.isDebugEnabled()) { 2170if (conn == null) { 2171LOGGER.debug("XmlaHandler.getConnection: returning connection null"); 2172} else { 2173LOGGER.debug("XmlaHandler.getConnection: returning connection not null"); 2174} 2175} 2176 return conn; 2177 } 2178 2179 2187 public DataSourcesConfig.DataSource getDataSource(XmlaRequest request) 2188 throws XmlaException 2189 { 2190 Map<String , String > properties = request.getProperties(); 2191 final String dataSourceInfo = 2192 properties.get(PropertyDefinition.DataSourceInfo.name()); 2193 if (!dataSourcesMap.containsKey(dataSourceInfo)) { 2194 throw new XmlaException( 2195 CLIENT_FAULT_FC, 2196 HSB_CONNECTION_DATA_SOURCE_CODE, 2197 HSB_CONNECTION_DATA_SOURCE_FAULT_FS, 2198 Util.newError("no data source is configured with name '" + 2199 dataSourceInfo + "'")); 2200 } 2201 if (LOGGER.isDebugEnabled()) { 2202 LOGGER.debug("XmlaHandler.getDataSource: dataSourceInfo=" + 2203 dataSourceInfo); 2204 } 2205 2206 final DataSourcesConfig.DataSource ds = 2207 dataSourcesMap.get(dataSourceInfo); 2208 if (LOGGER.isDebugEnabled()) { 2209 if (ds == null) { 2210 LOGGER.debug("XmlaHandler.getDataSource: ds is null"); 2212 } else { 2213 LOGGER.debug("XmlaHandler.getDataSource: ds.dataSourceInfo=" + 2214 ds.getDataSourceInfo()); 2215 } 2216 } 2217 return ds; 2218 } 2219 2220 2228 public DataSourcesConfig.Catalog getCatalog( 2229 DataSourcesConfig.DataSource ds, 2230 String catalogName) 2231 { 2232 DataSourcesConfig.Catalog[] catalogs = ds.catalogs.catalogs; 2233 if (catalogName == null) { 2234 if (catalogs.length == 1) { 2237 return catalogs[0]; 2238 } 2239 } else { 2240 for (DataSourcesConfig.Catalog dsCatalog : catalogs) { 2241 if (catalogName.equals(dsCatalog.name)) { 2242 return dsCatalog; 2243 } 2244 } 2245 } 2246 return null; 2247 } 2248 2249 2258 public DataSourcesConfig.Catalog[] getCatalogs( 2259 XmlaRequest request, 2260 DataSourcesConfig.DataSource ds) { 2261 2262 Map<String , String > properties = request.getProperties(); 2263 final String catalogName = 2264 properties.get(PropertyDefinition.Catalog.name()); 2265 if (catalogName != null) { 2266 DataSourcesConfig.Catalog dsCatalog = getCatalog(ds, catalogName); 2267 return new DataSourcesConfig.Catalog[] { dsCatalog }; 2268 } else { 2269 return ds.catalogs.catalogs; 2271 } 2272 } 2273 2274 2284 public DataSourcesConfig.Catalog getCatalog( 2285 XmlaRequest request, 2286 DataSourcesConfig.DataSource ds) 2287 throws XmlaException 2288 { 2289 Map<String , String > properties = request.getProperties(); 2290 final String catalogName = 2291 properties.get(PropertyDefinition.Catalog.name()); 2292 DataSourcesConfig.Catalog dsCatalog = getCatalog(ds, catalogName); 2293 if ((dsCatalog == null) && (catalogName == null)) { 2294 throw new XmlaException( 2295 CLIENT_FAULT_FC, 2296 HSB_CONNECTION_DATA_SOURCE_CODE, 2297 HSB_CONNECTION_DATA_SOURCE_FAULT_FS, 2298 Util.newError("no catalog named '" + catalogName + "'")); 2299 } 2300 return dsCatalog; 2301 } 2302 2303 private TabularRowSet executeColumnQuery(XmlaRequest request) 2304 throws XmlaException 2305 { 2306 checkFormat(request); 2307 2308 DataSourcesConfig.DataSource ds = getDataSource(request); 2309 DataSourcesConfig.Catalog dsCatalog = getCatalog(request, ds); 2310 String role = request.getRole(); 2311 2312 final Connection connection = getConnection(dsCatalog, role); 2313 final String statement = request.getStatement(); 2314 final Query query = connection.parseQuery(statement); 2315 query.setResultStyle(ResultStyle.LIST); 2316 final Result result = connection.execute(query); 2317 Cell dtCell = result.getCell(new int[] {0, 0}); 2318 2319 if (!dtCell.canDrillThrough()) { 2320 throw new XmlaException( 2321 SERVER_FAULT_FC, 2322 HSB_DRILL_THROUGH_NOT_ALLOWED_CODE, 2323 HSB_DRILL_THROUGH_NOT_ALLOWED_FAULT_FS, 2324 Util.newError("Cannot do DillThrough operation on the cell")); 2325 } 2326 2327 final Map<String , String > properties = request.getProperties(); 2328 String dtSql = dtCell.getDrillThroughSQL(true); 2329 2330 int index = dtSql.indexOf("from"); 2331 String whereClause = " " + dtSql.substring(index); 2332 final String fieldNames = properties.get(PropertyDefinition.TableFields.name()); 2333 StringTokenizer st = new StringTokenizer(fieldNames, ","); 2334 drillThruColumnNames.clear(); 2335 while (st.hasMoreTokens()) { 2336 drillThruColumnNames.add(st.nextToken()); 2337 } 2338 2339 StringBuilder buf = new StringBuilder ("select "); 2341 int k = -1; 2342 for (String drillThruColumnName : drillThruColumnNames) { 2343 if (++k > 0) { 2344 buf.append(","); 2345 } 2346 buf.append(drillThruColumnName); 2347 } 2348 buf.append(' '); 2349 buf.append(whereClause); 2350 dtSql = buf.toString(); 2351 2352 DataSource dataSource = ((RolapConnection) connection).getDataSource(); 2353 try { 2354 int count = -1; 2355 if (MondrianProperties.instance().EnableTotalCount.booleanValue()) { 2356 String temp = dtSql.toUpperCase(); 2357 int fromOff = temp.indexOf("FROM"); 2358 buf.setLength(0); 2359 buf.append("select count(*) "); 2360 buf.append(dtSql.substring(fromOff)); 2361 2362 String countSql = buf.toString(); 2363 2364 if (LOGGER.isDebugEnabled()) { 2365 LOGGER.debug("Advanced drill through counting sql: " + countSql); 2366 } 2367 SqlStatement smt = 2368 RolapUtil.executeQuery( 2369 dataSource, countSql, -1, 2370 "XmlaHandler.executeColumnQuery", 2371 "Advanced drill-through", 2372 ResultSet.TYPE_SCROLL_INSENSITIVE, 2373 ResultSet.CONCUR_READ_ONLY); 2374 2375 try { 2376 ResultSet rs = smt.getResultSet(); 2377 if (rs.next()) { 2378 count = rs.getInt(1); 2379 ++smt.rowCount; 2380 } 2381 } catch (SQLException e) { 2382 smt.handle(e); 2383 } finally { 2384 smt.close(); 2385 } 2386 } 2387 2388 if (LOGGER.isDebugEnabled()) { 2389 LOGGER.debug("Advanced drill through sql: " + dtSql); 2390 } 2391 SqlStatement stmt = 2392 RolapUtil.executeQuery( 2393 dataSource, dtSql, -1, "XmlaHandler.executeColumnQuery", 2394 "Advanced drill-through", 2395 ResultSet.TYPE_SCROLL_INSENSITIVE, 2396 ResultSet.CONCUR_READ_ONLY); 2397 2398 return new TabularRowSet( 2399 stmt, request.drillThroughMaxRows(), 2400 request.drillThroughFirstRowset(), count, 2401 ResultSet.TYPE_FORWARD_ONLY); 2402 2403 } catch (XmlaException xex) { 2404 throw xex; 2405 } catch (RuntimeException rte) { 2406 throw new XmlaException( 2407 SERVER_FAULT_FC, 2408 HSB_DRILL_THROUGH_SQL_CODE, 2409 HSB_DRILL_THROUGH_SQL_FAULT_FS, 2410 rte); 2411 } 2412 } 2413} 2414 2415 | Popular Tags |