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 }