001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: SQLDocument.java 468638 2006-10-28 06:52:06Z minchau $ 020 */ 021 022 package org.apache.xalan.lib.sql; 023 024 import java.util.Vector; 025 026 import org.apache.xalan.extensions.ExpressionContext; 027 import org.apache.xpath.XPathContext; 028 029 import org.apache.xml.dtm.DTMManager; 030 import org.apache.xml.dtm.DTM; 031 import java.sql.Connection; 032 import java.sql.Statement; 033 import java.sql.ResultSet; 034 import java.sql.ResultSetMetaData; 035 import java.sql.SQLException; 036 import java.sql.*; 037 import org.apache.xml.dtm.ref.*; 038 039 /** 040 * The SQL Document is the main controlling class the executesa SQL Query 041 */ 042 public class SQLDocument extends DTMDocument 043 { 044 045 /** 046 */ 047 private boolean DEBUG = false; 048 049 /** 050 */ 051 private static final String S_NAMESPACE = "http://xml.apache.org/xalan/SQLExtension"; 052 053 054 /** 055 */ 056 private static final String S_SQL = "sql"; 057 058 /** 059 */ 060 private static final String S_ROW_SET = "row-set"; 061 062 /** 063 */ 064 private static final String S_METADATA = "metadata"; 065 066 /** 067 */ 068 private static final String S_COLUMN_HEADER = "column-header"; 069 070 /** 071 */ 072 private static final String S_ROW = "row"; 073 074 /** 075 */ 076 private static final String S_COL = "col"; 077 078 /** 079 */ 080 private static final String S_OUT_PARAMETERS = "out-parameters"; 081 082 /** 083 */ 084 private static final String S_CATALOGUE_NAME = "catalogue-name"; 085 /** 086 */ 087 private static final String S_DISPLAY_SIZE = "column-display-size"; 088 /** 089 */ 090 private static final String S_COLUMN_LABEL = "column-label"; 091 /** 092 */ 093 private static final String S_COLUMN_NAME = "column-name"; 094 /** 095 */ 096 private static final String S_COLUMN_TYPE = "column-type"; 097 /** 098 */ 099 private static final String S_COLUMN_TYPENAME = "column-typename"; 100 /** 101 */ 102 private static final String S_PRECISION = "precision"; 103 /** 104 */ 105 private static final String S_SCALE = "scale"; 106 /** 107 */ 108 private static final String S_SCHEMA_NAME = "schema-name"; 109 /** 110 */ 111 private static final String S_TABLE_NAME = "table-name"; 112 /** 113 */ 114 private static final String S_CASESENSITIVE = "case-sensitive"; 115 /** 116 */ 117 private static final String S_DEFINITELYWRITABLE = "definitely-writable"; 118 /** 119 */ 120 private static final String S_ISNULLABLE = "nullable"; 121 /** 122 */ 123 private static final String S_ISSIGNED = "signed"; 124 /** 125 */ 126 private static final String S_ISWRITEABLE = "writable"; 127 /** 128 */ 129 private static final String S_ISSEARCHABLE = "searchable"; 130 131 /** 132 */ 133 private int m_SQL_TypeID = 0; 134 /** 135 */ 136 private int m_MetaData_TypeID = 0; 137 /** 138 */ 139 private int m_ColumnHeader_TypeID = 0; 140 /** 141 */ 142 private int m_RowSet_TypeID = 0; 143 /** 144 */ 145 private int m_Row_TypeID = 0; 146 /** 147 */ 148 private int m_Col_TypeID = 0; 149 /** 150 */ 151 private int m_OutParameter_TypeID = 0; 152 153 /** 154 */ 155 private int m_ColAttrib_CATALOGUE_NAME_TypeID = 0; 156 /** 157 */ 158 private int m_ColAttrib_DISPLAY_SIZE_TypeID = 0; 159 /** 160 */ 161 private int m_ColAttrib_COLUMN_LABEL_TypeID = 0; 162 /** 163 */ 164 private int m_ColAttrib_COLUMN_NAME_TypeID = 0; 165 /** 166 */ 167 private int m_ColAttrib_COLUMN_TYPE_TypeID = 0; 168 /** 169 */ 170 private int m_ColAttrib_COLUMN_TYPENAME_TypeID = 0; 171 /** 172 */ 173 private int m_ColAttrib_PRECISION_TypeID = 0; 174 /** 175 */ 176 private int m_ColAttrib_SCALE_TypeID = 0; 177 /** 178 */ 179 private int m_ColAttrib_SCHEMA_NAME_TypeID = 0; 180 /** 181 */ 182 private int m_ColAttrib_TABLE_NAME_TypeID = 0; 183 /** 184 */ 185 private int m_ColAttrib_CASESENSITIVE_TypeID = 0; 186 /** 187 */ 188 private int m_ColAttrib_DEFINITELYWRITEABLE_TypeID = 0; 189 /** 190 */ 191 private int m_ColAttrib_ISNULLABLE_TypeID = 0; 192 /** 193 */ 194 private int m_ColAttrib_ISSIGNED_TypeID = 0; 195 /** 196 */ 197 private int m_ColAttrib_ISWRITEABLE_TypeID = 0; 198 /** 199 */ 200 private int m_ColAttrib_ISSEARCHABLE_TypeID = 0; 201 202 /** 203 * The Statement used to extract the data from the database connection. 204 */ 205 private Statement m_Statement = null; 206 207 /** 208 * Expression COntext used to creat this document 209 * may be used to grab variables from the XSL processor 210 */ 211 private ExpressionContext m_ExpressionContext = null; 212 213 /** 214 * The Connection Pool where we has derived all of our connections 215 * for this document 216 */ 217 private ConnectionPool m_ConnectionPool = null; 218 219 /** 220 * The current ResultSet. 221 */ 222 private ResultSet m_ResultSet = null; 223 224 /** 225 * The parameter definitions if this is a callable 226 * statement with output parameters. 227 */ 228 private SQLQueryParser m_QueryParser = null; 229 230 /** 231 * As the column header array is built, keep the node index 232 * for each Column. 233 * The primary use of this is to locate the first attribute for 234 * each column in each row as we add records. 235 */ 236 private int[] m_ColHeadersIdx; 237 238 /** 239 * An indicator on how many columns are in this query 240 */ 241 private int m_ColCount; 242 243 /** 244 * The Index of the MetaData Node. Currently the MetaData Node contains the 245 * 246 */ 247 private int m_MetaDataIdx = DTM.NULL; 248 249 /** 250 * The index of the Row Set node. This is the sibling directly after 251 * the last Column Header. 252 */ 253 private int m_RowSetIdx = DTM.NULL; 254 255 /** 256 */ 257 private int m_SQLIdx = DTM.NULL; 258 259 /** 260 * Demark the first row element where we started adding rows into the 261 * Document. 262 */ 263 private int m_FirstRowIdx = DTM.NULL; 264 265 /** 266 * Keep track of the Last row inserted into the DTM from the ResultSet. 267 * This will be used as the index of the parent Row Element when adding 268 * a row. 269 */ 270 private int m_LastRowIdx = DTM.NULL; 271 272 /** 273 * Streaming Mode Control, In Streaming mode we reduce the memory 274 * footprint since we only use a single row instance. 275 */ 276 private boolean m_StreamingMode = true; 277 278 /** 279 * Multiple Result sets mode (metadata inside rowset). 280 */ 281 private boolean m_MultipleResults = false; 282 283 /** 284 * Flag to detect if an error occured during an operation 285 * Defines how errors are handled and how the SQL Connection 286 * is closed. 287 */ 288 private boolean m_HasErrors = false; 289 290 /** 291 * Is statement caching enabled. 292 */ 293 private boolean m_IsStatementCachingEnabled = false; 294 295 /** 296 * XConnection this document came from. 297 */ 298 private XConnection m_XConnection = null; 299 300 /** 301 * @param mgr 302 * @param ident 303 * @throws SQLException 304 */ 305 // public cSQLDocument(DTMManager mgr, int ident, Statement stmt, 306 // ResultSet singleResult, Vector paramdefs, boolean streamingMode, 307 // boolean multipleResults, boolean statementCachingEnabled) throws SQLException 308 309 public SQLDocument(DTMManager mgr, int ident) 310 { 311 super(mgr, ident); 312 } 313 314 /** 315 * This static method simplifies the creation of an SQL Document and allows 316 * us to embedd the complexity of creating / handling the dtmIdent inside 317 * the document. This type of method may better placed inside the DTMDocument 318 * code 319 */ 320 public static SQLDocument getNewDocument(ExpressionContext exprContext) 321 { 322 DTMManager mgr = 323 ((XPathContext.XPathExpressionContext)exprContext).getDTMManager(); 324 DTMManagerDefault mgrDefault = (DTMManagerDefault) mgr; 325 326 327 int dtmIdent = mgrDefault.getFirstFreeDTMID(); 328 329 SQLDocument doc = 330 new SQLDocument(mgr, dtmIdent << DTMManager.IDENT_DTM_NODE_BITS); 331 332 // Register the document 333 mgrDefault.addDTM(doc, dtmIdent); 334 doc.setExpressionContext(exprContext); 335 336 return doc; 337 } 338 339 /** 340 * When building the SQL Document, we need to store the Expression 341 * Context that was used to create the document. This will be se to 342 * reference items int he XSLT process such as any variables that were 343 * present. 344 */ 345 protected void setExpressionContext(ExpressionContext expr) 346 { 347 m_ExpressionContext = expr; 348 } 349 350 /** 351 * Return the context used to build this document 352 */ 353 public ExpressionContext getExpressionContext() 354 { 355 return m_ExpressionContext; 356 } 357 358 359 public void execute(XConnection xconn, SQLQueryParser query) 360 throws SQLException 361 { 362 try 363 { 364 m_StreamingMode = "true".equals(xconn.getFeature("streaming")); 365 m_MultipleResults = "true".equals(xconn.getFeature("multiple-results")); 366 m_IsStatementCachingEnabled = "true".equals(xconn.getFeature("cache-statements")); 367 m_XConnection = xconn; 368 m_QueryParser = query; 369 370 executeSQLStatement(); 371 372 createExpandedNameTable(); 373 374 // Start the document here 375 m_DocumentIdx = addElement(0, m_Document_TypeID, DTM.NULL, DTM.NULL); 376 m_SQLIdx = addElement(1, m_SQL_TypeID, m_DocumentIdx, DTM.NULL); 377 378 379 if ( ! m_MultipleResults ) 380 extractSQLMetaData(m_ResultSet.getMetaData()); 381 382 // Only grab the first row, subsequent rows will be 383 // fetched on demand. 384 // We need to do this here so at least on row is set up 385 // to measure when we are actually reading rows. 386 387 // We won't grab the first record in case the skip function 388 // is applied prior to looking at the first record. 389 // JCG Changed 9/15/04 390 // addRowToDTMFromResultSet(); 391 } 392 catch(SQLException e) 393 { 394 m_HasErrors = true; 395 throw e; 396 } 397 } 398 399 private void executeSQLStatement() throws SQLException 400 { 401 m_ConnectionPool = m_XConnection.getConnectionPool(); 402 403 Connection conn = m_ConnectionPool.getConnection(); 404 405 if (! m_QueryParser.hasParameters() ) 406 { 407 m_Statement = conn.createStatement(); 408 m_ResultSet = m_Statement.executeQuery(m_QueryParser.getSQLQuery()); 409 410 411 } 412 413 else if (m_QueryParser.isCallable()) 414 { 415 CallableStatement cstmt = 416 conn.prepareCall(m_QueryParser.getSQLQuery()); 417 m_QueryParser.registerOutputParameters(cstmt); 418 m_QueryParser.populateStatement(cstmt, m_ExpressionContext); 419 m_Statement = cstmt; 420 if (! cstmt.execute()) throw new SQLException("Error in Callable Statement"); 421 422 m_ResultSet = m_Statement.getResultSet(); 423 } 424 else 425 { 426 PreparedStatement stmt = 427 conn.prepareStatement(m_QueryParser.getSQLQuery()); 428 m_QueryParser.populateStatement(stmt, m_ExpressionContext); 429 m_Statement = stmt; 430 m_ResultSet = stmt.executeQuery(); 431 } 432 433 } 434 435 /** 436 * Push the record set forward value rows. Used to help in 437 * SQL pagination. 438 * 439 * @param value 440 */ 441 public void skip( int value ) 442 { 443 try 444 { 445 if (m_ResultSet != null) m_ResultSet.relative(value); 446 } 447 catch(Exception origEx) 448 { 449 // For now let's assume that the relative method is not supported. 450 // So let's do it manually. 451 try 452 { 453 for (int x=0; x<value; x++) 454 { 455 if (! m_ResultSet.next()) break; 456 } 457 } 458 catch(Exception e) 459 { 460 // If we still fail, add in both exceptions 461 m_XConnection.setError(origEx, this, checkWarnings()); 462 m_XConnection.setError(e, this, checkWarnings()); 463 } 464 } 465 } 466 467 468 /** 469 * Extract the Meta Data and build the Column Attribute List. 470 * @param meta 471 * @return 472 */ 473 private void extractSQLMetaData( ResultSetMetaData meta ) 474 { 475 // Build the Node Tree, just add the Column Header 476 // branch now, the Row & col elements will be added 477 // on request. 478 479 // Add in the row-set Element 480 481 // Add in the MetaData Element 482 m_MetaDataIdx = addElement(1, m_MetaData_TypeID, m_MultipleResults ? m_RowSetIdx : m_SQLIdx, DTM.NULL); 483 484 try 485 { 486 m_ColCount = meta.getColumnCount(); 487 m_ColHeadersIdx = new int[m_ColCount]; 488 } 489 catch(Exception e) 490 { 491 m_XConnection.setError(e, this, checkWarnings()); 492 //error("ERROR Extracting Metadata"); 493 } 494 495 // The ColHeaderIdx will be used to keep track of the 496 // Element entries for the individual Column Header. 497 int lastColHeaderIdx = DTM.NULL; 498 499 // JDBC Columms Start at 1 500 int i = 1; 501 for (i=1; i<= m_ColCount; i++) 502 { 503 m_ColHeadersIdx[i-1] = 504 addElement(2,m_ColumnHeader_TypeID, m_MetaDataIdx, lastColHeaderIdx); 505 506 lastColHeaderIdx = m_ColHeadersIdx[i-1]; 507 // A bit brute force, but not sure how to clean it up 508 509 try 510 { 511 addAttributeToNode( 512 meta.getColumnName(i), 513 m_ColAttrib_COLUMN_NAME_TypeID, lastColHeaderIdx); 514 } 515 catch(Exception e) 516 { 517 addAttributeToNode( 518 S_ATTRIB_NOT_SUPPORTED, 519 m_ColAttrib_COLUMN_NAME_TypeID, lastColHeaderIdx); 520 } 521 522 try 523 { 524 addAttributeToNode( 525 meta.getColumnLabel(i), 526 m_ColAttrib_COLUMN_LABEL_TypeID, lastColHeaderIdx); 527 } 528 catch(Exception e) 529 { 530 addAttributeToNode( 531 S_ATTRIB_NOT_SUPPORTED, 532 m_ColAttrib_COLUMN_LABEL_TypeID, lastColHeaderIdx); 533 } 534 535 try 536 { 537 addAttributeToNode( 538 meta.getCatalogName(i), 539 m_ColAttrib_CATALOGUE_NAME_TypeID, lastColHeaderIdx); 540 } 541 catch(Exception e) 542 { 543 addAttributeToNode( 544 S_ATTRIB_NOT_SUPPORTED, 545 m_ColAttrib_CATALOGUE_NAME_TypeID, lastColHeaderIdx); 546 } 547 548 try 549 { 550 addAttributeToNode( 551 new Integer(meta.getColumnDisplaySize(i)), 552 m_ColAttrib_DISPLAY_SIZE_TypeID, lastColHeaderIdx); 553 } 554 catch(Exception e) 555 { 556 addAttributeToNode( 557 S_ATTRIB_NOT_SUPPORTED, 558 m_ColAttrib_DISPLAY_SIZE_TypeID, lastColHeaderIdx); 559 } 560 561 try 562 { 563 addAttributeToNode( 564 new Integer(meta.getColumnType(i)), 565 m_ColAttrib_COLUMN_TYPE_TypeID, lastColHeaderIdx); 566 } 567 catch(Exception e) 568 { 569 addAttributeToNode( 570 S_ATTRIB_NOT_SUPPORTED, 571 m_ColAttrib_COLUMN_TYPE_TypeID, lastColHeaderIdx); 572 } 573 574 try 575 { 576 addAttributeToNode( 577 meta.getColumnTypeName(i), 578 m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColHeaderIdx); 579 } 580 catch(Exception e) 581 { 582 addAttributeToNode( 583 S_ATTRIB_NOT_SUPPORTED, 584 m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColHeaderIdx); 585 } 586 587 try 588 { 589 addAttributeToNode( 590 new Integer(meta.getPrecision(i)), 591 m_ColAttrib_PRECISION_TypeID, lastColHeaderIdx); 592 } 593 catch(Exception e) 594 { 595 addAttributeToNode( 596 S_ATTRIB_NOT_SUPPORTED, 597 m_ColAttrib_PRECISION_TypeID, lastColHeaderIdx); 598 } 599 try 600 { 601 addAttributeToNode( 602 new Integer(meta.getScale(i)), 603 m_ColAttrib_SCALE_TypeID, lastColHeaderIdx); 604 } 605 catch(Exception e) 606 { 607 addAttributeToNode( 608 S_ATTRIB_NOT_SUPPORTED, 609 m_ColAttrib_SCALE_TypeID, lastColHeaderIdx); 610 } 611 612 try 613 { 614 addAttributeToNode( 615 meta.getSchemaName(i), 616 m_ColAttrib_SCHEMA_NAME_TypeID, lastColHeaderIdx); 617 } 618 catch(Exception e) 619 { 620 addAttributeToNode( 621 S_ATTRIB_NOT_SUPPORTED, 622 m_ColAttrib_SCHEMA_NAME_TypeID, lastColHeaderIdx); 623 } 624 try 625 { 626 addAttributeToNode( 627 meta.getTableName(i), 628 m_ColAttrib_TABLE_NAME_TypeID, lastColHeaderIdx); 629 } 630 catch(Exception e) 631 { 632 addAttributeToNode( 633 S_ATTRIB_NOT_SUPPORTED, 634 m_ColAttrib_TABLE_NAME_TypeID, lastColHeaderIdx); 635 } 636 637 try 638 { 639 addAttributeToNode( 640 meta.isCaseSensitive(i) ? S_ISTRUE : S_ISFALSE, 641 m_ColAttrib_CASESENSITIVE_TypeID, lastColHeaderIdx); 642 } 643 catch(Exception e) 644 { 645 addAttributeToNode( 646 S_ATTRIB_NOT_SUPPORTED, 647 m_ColAttrib_CASESENSITIVE_TypeID, lastColHeaderIdx); 648 } 649 650 try 651 { 652 addAttributeToNode( 653 meta.isDefinitelyWritable(i) ? S_ISTRUE : S_ISFALSE, 654 m_ColAttrib_DEFINITELYWRITEABLE_TypeID, lastColHeaderIdx); 655 } 656 catch(Exception e) 657 { 658 addAttributeToNode( 659 S_ATTRIB_NOT_SUPPORTED, 660 m_ColAttrib_DEFINITELYWRITEABLE_TypeID, lastColHeaderIdx); 661 } 662 663 try 664 { 665 addAttributeToNode( 666 meta.isNullable(i) != 0 ? S_ISTRUE : S_ISFALSE, 667 m_ColAttrib_ISNULLABLE_TypeID, lastColHeaderIdx); 668 } 669 catch(Exception e) 670 { 671 addAttributeToNode( 672 S_ATTRIB_NOT_SUPPORTED, 673 m_ColAttrib_ISNULLABLE_TypeID, lastColHeaderIdx); 674 } 675 676 try 677 { 678 addAttributeToNode( 679 meta.isSigned(i) ? S_ISTRUE : S_ISFALSE, 680 m_ColAttrib_ISSIGNED_TypeID, lastColHeaderIdx); 681 } 682 catch(Exception e) 683 { 684 addAttributeToNode( 685 S_ATTRIB_NOT_SUPPORTED, 686 m_ColAttrib_ISSIGNED_TypeID, lastColHeaderIdx); 687 } 688 689 try 690 { 691 addAttributeToNode( 692 meta.isWritable(i) == true ? S_ISTRUE : S_ISFALSE, 693 m_ColAttrib_ISWRITEABLE_TypeID, lastColHeaderIdx); 694 } 695 catch(Exception e) 696 { 697 addAttributeToNode( 698 S_ATTRIB_NOT_SUPPORTED, 699 m_ColAttrib_ISWRITEABLE_TypeID, lastColHeaderIdx); 700 } 701 702 try 703 { 704 addAttributeToNode( 705 meta.isSearchable(i) == true ? S_ISTRUE : S_ISFALSE, 706 m_ColAttrib_ISSEARCHABLE_TypeID, lastColHeaderIdx); 707 } 708 catch(Exception e) 709 { 710 addAttributeToNode( 711 S_ATTRIB_NOT_SUPPORTED, 712 m_ColAttrib_ISSEARCHABLE_TypeID, lastColHeaderIdx); 713 } 714 } 715 } 716 717 /** 718 * Populate the Expanded Name Table with the Node that we will use. 719 * Keep a reference of each of the types for access speed. 720 * @return 721 */ 722 protected void createExpandedNameTable( ) 723 { 724 super.createExpandedNameTable(); 725 726 m_SQL_TypeID = 727 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SQL, DTM.ELEMENT_NODE); 728 729 m_MetaData_TypeID = 730 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_METADATA, DTM.ELEMENT_NODE); 731 732 m_ColumnHeader_TypeID = 733 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_HEADER, DTM.ELEMENT_NODE); 734 m_RowSet_TypeID = 735 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ROW_SET, DTM.ELEMENT_NODE); 736 m_Row_TypeID = 737 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ROW, DTM.ELEMENT_NODE); 738 m_Col_TypeID = 739 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COL, DTM.ELEMENT_NODE); 740 m_OutParameter_TypeID = 741 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_OUT_PARAMETERS, DTM.ELEMENT_NODE); 742 743 m_ColAttrib_CATALOGUE_NAME_TypeID = 744 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_CATALOGUE_NAME, DTM.ATTRIBUTE_NODE); 745 m_ColAttrib_DISPLAY_SIZE_TypeID = 746 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_DISPLAY_SIZE, DTM.ATTRIBUTE_NODE); 747 m_ColAttrib_COLUMN_LABEL_TypeID = 748 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_LABEL, DTM.ATTRIBUTE_NODE); 749 m_ColAttrib_COLUMN_NAME_TypeID = 750 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_NAME, DTM.ATTRIBUTE_NODE); 751 m_ColAttrib_COLUMN_TYPE_TypeID = 752 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_TYPE, DTM.ATTRIBUTE_NODE); 753 m_ColAttrib_COLUMN_TYPENAME_TypeID = 754 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_TYPENAME, DTM.ATTRIBUTE_NODE); 755 m_ColAttrib_PRECISION_TypeID = 756 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_PRECISION, DTM.ATTRIBUTE_NODE); 757 m_ColAttrib_SCALE_TypeID = 758 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SCALE, DTM.ATTRIBUTE_NODE); 759 m_ColAttrib_SCHEMA_NAME_TypeID = 760 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SCHEMA_NAME, DTM.ATTRIBUTE_NODE); 761 m_ColAttrib_TABLE_NAME_TypeID = 762 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_TABLE_NAME, DTM.ATTRIBUTE_NODE); 763 m_ColAttrib_CASESENSITIVE_TypeID = 764 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_CASESENSITIVE, DTM.ATTRIBUTE_NODE); 765 m_ColAttrib_DEFINITELYWRITEABLE_TypeID = 766 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_DEFINITELYWRITABLE, DTM.ATTRIBUTE_NODE); 767 m_ColAttrib_ISNULLABLE_TypeID = 768 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISNULLABLE, DTM.ATTRIBUTE_NODE); 769 m_ColAttrib_ISSIGNED_TypeID = 770 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISSIGNED, DTM.ATTRIBUTE_NODE); 771 m_ColAttrib_ISWRITEABLE_TypeID = 772 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISWRITEABLE, DTM.ATTRIBUTE_NODE); 773 m_ColAttrib_ISSEARCHABLE_TypeID = 774 m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISSEARCHABLE, DTM.ATTRIBUTE_NODE); 775 } 776 777 778 /** 779 * Pull a record from the result set and map it to a DTM based ROW 780 * If we are in Streaming mode, then only create a single row and 781 * keep copying the data into the same row. This will keep the memory 782 * footprint constint independant of the RecordSet Size. If we are not 783 * in Streaming mode then create ROWS for the whole tree. 784 * @return 785 */ 786 private boolean addRowToDTMFromResultSet( ) 787 { 788 try 789 { 790 // If we have not started the RowSet yet, then add it to the 791 // tree. 792 if (m_FirstRowIdx == DTM.NULL) 793 { 794 m_RowSetIdx = 795 addElement(1, m_RowSet_TypeID, m_SQLIdx, m_MultipleResults ? m_RowSetIdx : m_MetaDataIdx); 796 if ( m_MultipleResults ) extractSQLMetaData(m_ResultSet.getMetaData()); 797 } 798 799 800 // Check to see if all the data has been read from the Query. 801 // If we are at the end the signal that event 802 if ( ! m_ResultSet.next()) 803 { 804 // In Streaming mode, the current ROW will always point back 805 // to itself until all the data was read. Once the Query is 806 // empty then point the next row to DTM.NULL so that the stream 807 // ends. Only do this if we have statted the loop to begin with. 808 809 if (m_StreamingMode && (m_LastRowIdx != DTM.NULL)) 810 { 811 // We are at the end, so let's untie the mark 812 m_nextsib.setElementAt(DTM.NULL, m_LastRowIdx); 813 } 814 815 m_ResultSet.close(); 816 if ( m_MultipleResults ) 817 { 818 while ( !m_Statement.getMoreResults() && m_Statement.getUpdateCount() >= 0 ) ; 819 m_ResultSet = m_Statement.getResultSet(); 820 } 821 else 822 m_ResultSet = null; 823 824 if ( m_ResultSet != null ) 825 { 826 m_FirstRowIdx = DTM.NULL; 827 addRowToDTMFromResultSet(); 828 } 829 else 830 { 831 Vector parameters = m_QueryParser.getParameters(); 832 // Get output parameters. 833 if ( parameters != null ) 834 { 835 int outParamIdx = addElement(1, m_OutParameter_TypeID, m_SQLIdx, m_RowSetIdx); 836 int lastColID = DTM.NULL; 837 for ( int indx = 0 ; indx < parameters.size() ; indx++ ) 838 { 839 QueryParameter parm = (QueryParameter)parameters.elementAt(indx); 840 if ( parm.isOutput() ) 841 { 842 Object rawobj = ((CallableStatement)m_Statement).getObject(indx + 1); 843 lastColID = addElementWithData(rawobj, 2, m_Col_TypeID, outParamIdx, lastColID); 844 addAttributeToNode(parm.getName(), m_ColAttrib_COLUMN_NAME_TypeID, lastColID); 845 addAttributeToNode(parm.getName(), m_ColAttrib_COLUMN_LABEL_TypeID, lastColID); 846 addAttributeToNode(new Integer(parm.getType()), m_ColAttrib_COLUMN_TYPE_TypeID, lastColID); 847 addAttributeToNode(parm.getTypeName(), m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColID); 848 } 849 } 850 } 851 852 SQLWarning warn = checkWarnings(); 853 if ( warn != null ) m_XConnection.setError(null, null, warn); 854 } 855 856 return false; 857 } 858 859 // If this is the first time here, start the new level 860 if (m_FirstRowIdx == DTM.NULL) 861 { 862 m_FirstRowIdx = 863 addElement(2, m_Row_TypeID, m_RowSetIdx, m_MultipleResults ? m_MetaDataIdx : DTM.NULL); 864 865 m_LastRowIdx = m_FirstRowIdx; 866 867 if (m_StreamingMode) 868 { 869 // Let's tie the rows together until the end. 870 m_nextsib.setElementAt(m_LastRowIdx, m_LastRowIdx); 871 } 872 873 } 874 else 875 { 876 // 877 // If we are in Streaming mode, then only use a single row instance 878 if (! m_StreamingMode) 879 { 880 m_LastRowIdx = addElement(2, m_Row_TypeID, m_RowSetIdx, m_LastRowIdx); 881 } 882 } 883 884 // If we are not in streaming mode, this will always be DTM.NULL 885 // If we are in streaming mode, it will only be DTM.NULL the first time 886 int colID = _firstch(m_LastRowIdx); 887 888 // Keep Track of who our parent was when adding new col objects. 889 int pcolID = DTM.NULL; 890 891 // Columns in JDBC Start at 1 and go to the Extent 892 for (int i=1; i<= m_ColCount; i++) 893 { 894 // Just grab the Column Object Type, we will convert it to a string 895 // later. 896 Object o = m_ResultSet.getObject(i); 897 898 // Create a new column object if one does not exist. 899 // In Streaming mode, this mechinism will reuse the column 900 // data the second and subsequent row accesses. 901 if (colID == DTM.NULL) 902 { 903 pcolID = addElementWithData(o,3,m_Col_TypeID, m_LastRowIdx, pcolID); 904 cloneAttributeFromNode(pcolID, m_ColHeadersIdx[i-1]); 905 } 906 else 907 { 908 // We must be in streaming mode, so let's just replace the data 909 // If the firstch was not set then we have a major error 910 int dataIdent = _firstch(colID); 911 if (dataIdent == DTM.NULL) 912 { 913 error("Streaming Mode, Data Error"); 914 } 915 else 916 { 917 m_ObjectArray.setAt(dataIdent, o); 918 } 919 } // If 920 921 // In streaming mode, this will be !DTM.NULL 922 // So if the elements were already established then we 923 // should be able to walk them in order. 924 if (colID != DTM.NULL) 925 { 926 colID = _nextsib(colID); 927 } 928 929 } // For Col Loop 930 } 931 catch(Exception e) 932 { 933 if (DEBUG) 934 { 935 System.out.println( 936 "SQL Error Fetching next row [" + e.getLocalizedMessage() + "]"); 937 } 938 939 m_XConnection.setError(e, this, checkWarnings()); 940 m_HasErrors = true; 941 } 942 943 // Only do a single row... 944 return true; 945 } 946 947 948 /** 949 * Used by the XConnection to determine if the Document should 950 * handle the document differently. 951 */ 952 public boolean hasErrors() 953 { 954 return m_HasErrors; 955 } 956 957 /** 958 * Close down any resources used by this document. If an SQL Error occure 959 * while the document was being accessed, the SQL Connection used to create 960 * this document will be released to the Connection Pool on error. This allows 961 * the COnnection Pool to give special attention to any connection that may 962 * be in a errored state. 963 * 964 */ 965 public void close(boolean flushConnPool ) 966 { 967 try 968 { 969 SQLWarning warn = checkWarnings(); 970 if ( warn != null ) m_XConnection.setError(null, null, warn); 971 } 972 catch(Exception e) {} 973 974 try 975 { 976 if (null != m_ResultSet) 977 { 978 m_ResultSet.close(); 979 m_ResultSet = null; 980 } 981 } 982 catch(Exception e) {} 983 984 985 Connection conn = null; 986 987 try 988 { 989 if (null != m_Statement) 990 { 991 conn = m_Statement.getConnection(); 992 m_Statement.close(); 993 m_Statement = null; 994 } 995 } 996 catch(Exception e) {} 997 998 try 999 { 1000 if (conn != null) 1001 { 1002 if (m_HasErrors) m_ConnectionPool.releaseConnectionOnError(conn); 1003 else m_ConnectionPool.releaseConnection(conn); 1004 // if (flushConnPool) m_ConnectionPool.freeUnused(); 1005 } 1006 } 1007 catch(Exception e) {} 1008 1009 getManager().release(this, true); 1010 } 1011 1012 /** 1013 * @return 1014 */ 1015 protected boolean nextNode( ) 1016 { 1017 if (DEBUG) System.out.println("nextNode()"); 1018 try 1019 { 1020 return false; 1021 // return m_ResultSet.isAfterLast(); 1022 } 1023 catch(Exception e) 1024 { 1025 return false; 1026 } 1027 } 1028 1029 /** 1030 * @param identity 1031 * @return 1032 */ 1033 protected int _nextsib( int identity ) 1034 { 1035 // If we are asking for the next row and we have not 1036 // been there yet then let's see if we can get another 1037 // row from the ResultSet. 1038 // 1039 1040 if ( m_ResultSet != null ) 1041 { 1042 int id = _exptype(identity); 1043 1044 // We need to prime the pump since we don't do it in execute any more. 1045 if (m_FirstRowIdx == DTM.NULL) 1046 { 1047 addRowToDTMFromResultSet(); 1048 } 1049 1050 if ( 1051 ( id == m_Row_TypeID) && 1052 (identity >= m_LastRowIdx) ) 1053 { 1054 if (DEBUG) System.out.println("reading from the ResultSet"); 1055 addRowToDTMFromResultSet(); 1056 } 1057 else if ( m_MultipleResults && identity == m_RowSetIdx ) 1058 { 1059 if (DEBUG) System.out.println("reading for next ResultSet"); 1060 int startIdx = m_RowSetIdx; 1061 while ( startIdx == m_RowSetIdx && m_ResultSet != null ) 1062 addRowToDTMFromResultSet(); 1063 } 1064 } 1065 1066 return super._nextsib(identity); 1067 } 1068 1069 public void documentRegistration() 1070 { 1071 if (DEBUG) System.out.println("Document Registration"); 1072 } 1073 1074 public void documentRelease() 1075 { 1076 if (DEBUG) System.out.println("Document Release"); 1077 } 1078 1079 public SQLWarning checkWarnings() 1080 { 1081 SQLWarning warn = null; 1082 if ( m_Statement != null ) 1083 { 1084 try 1085 { 1086 warn = m_Statement.getWarnings(); 1087 m_Statement.clearWarnings(); 1088 } 1089 catch (SQLException se) {} 1090 } 1091 return(warn); 1092 } 1093 }