blob: d88747907018bf1f19e381f5422bf32b9cd7931a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id$
*/
package org.apache.xalan.lib.sql;
import java.util.Vector;
import org.apache.xalan.extensions.ExpressionContext;
import org.apache.xpath.XPathContext;
import org.apache.xml.dtm.DTMManager;
import org.apache.xml.dtm.DTM;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.*;
import org.apache.xml.dtm.ref.*;
/**
* The SQL Document is the main controlling class the executesa SQL Query
*/
public class SQLDocument extends DTMDocument
{
/**
*/
private boolean DEBUG = false;
/**
*/
private static final String S_NAMESPACE = "http://xml.apache.org/xalan/SQLExtension";
/**
*/
private static final String S_SQL = "sql";
/**
*/
private static final String S_ROW_SET = "row-set";
/**
*/
private static final String S_METADATA = "metadata";
/**
*/
private static final String S_COLUMN_HEADER = "column-header";
/**
*/
private static final String S_ROW = "row";
/**
*/
private static final String S_COL = "col";
/**
*/
private static final String S_OUT_PARAMETERS = "out-parameters";
/**
*/
private static final String S_CATALOGUE_NAME = "catalogue-name";
/**
*/
private static final String S_DISPLAY_SIZE = "column-display-size";
/**
*/
private static final String S_COLUMN_LABEL = "column-label";
/**
*/
private static final String S_COLUMN_NAME = "column-name";
/**
*/
private static final String S_COLUMN_TYPE = "column-type";
/**
*/
private static final String S_COLUMN_TYPENAME = "column-typename";
/**
*/
private static final String S_PRECISION = "precision";
/**
*/
private static final String S_SCALE = "scale";
/**
*/
private static final String S_SCHEMA_NAME = "schema-name";
/**
*/
private static final String S_TABLE_NAME = "table-name";
/**
*/
private static final String S_CASESENSITIVE = "case-sensitive";
/**
*/
private static final String S_DEFINITELYWRITABLE = "definitely-writable";
/**
*/
private static final String S_ISNULLABLE = "nullable";
/**
*/
private static final String S_ISSIGNED = "signed";
/**
*/
private static final String S_ISWRITEABLE = "writable";
/**
*/
private static final String S_ISSEARCHABLE = "searchable";
/**
*/
private int m_SQL_TypeID = 0;
/**
*/
private int m_MetaData_TypeID = 0;
/**
*/
private int m_ColumnHeader_TypeID = 0;
/**
*/
private int m_RowSet_TypeID = 0;
/**
*/
private int m_Row_TypeID = 0;
/**
*/
private int m_Col_TypeID = 0;
/**
*/
private int m_OutParameter_TypeID = 0;
/**
*/
private int m_ColAttrib_CATALOGUE_NAME_TypeID = 0;
/**
*/
private int m_ColAttrib_DISPLAY_SIZE_TypeID = 0;
/**
*/
private int m_ColAttrib_COLUMN_LABEL_TypeID = 0;
/**
*/
private int m_ColAttrib_COLUMN_NAME_TypeID = 0;
/**
*/
private int m_ColAttrib_COLUMN_TYPE_TypeID = 0;
/**
*/
private int m_ColAttrib_COLUMN_TYPENAME_TypeID = 0;
/**
*/
private int m_ColAttrib_PRECISION_TypeID = 0;
/**
*/
private int m_ColAttrib_SCALE_TypeID = 0;
/**
*/
private int m_ColAttrib_SCHEMA_NAME_TypeID = 0;
/**
*/
private int m_ColAttrib_TABLE_NAME_TypeID = 0;
/**
*/
private int m_ColAttrib_CASESENSITIVE_TypeID = 0;
/**
*/
private int m_ColAttrib_DEFINITELYWRITEABLE_TypeID = 0;
/**
*/
private int m_ColAttrib_ISNULLABLE_TypeID = 0;
/**
*/
private int m_ColAttrib_ISSIGNED_TypeID = 0;
/**
*/
private int m_ColAttrib_ISWRITEABLE_TypeID = 0;
/**
*/
private int m_ColAttrib_ISSEARCHABLE_TypeID = 0;
/**
* The Statement used to extract the data from the database connection.
*/
private Statement m_Statement = null;
/**
* Expression COntext used to creat this document
* may be used to grab variables from the XSL processor
*/
private ExpressionContext m_ExpressionContext = null;
/**
* The Connection Pool where we has derived all of our connections
* for this document
*/
private ConnectionPool m_ConnectionPool = null;
/**
* The current ResultSet.
*/
private ResultSet m_ResultSet = null;
/**
* The parameter definitions if this is a callable
* statement with output parameters.
*/
private SQLQueryParser m_QueryParser = null;
/**
* As the column header array is built, keep the node index
* for each Column.
* The primary use of this is to locate the first attribute for
* each column in each row as we add records.
*/
private int[] m_ColHeadersIdx;
/**
* An indicator on how many columns are in this query
*/
private int m_ColCount;
/**
* The Index of the MetaData Node. Currently the MetaData Node contains the
*
*/
private int m_MetaDataIdx = DTM.NULL;
/**
* The index of the Row Set node. This is the sibling directly after
* the last Column Header.
*/
private int m_RowSetIdx = DTM.NULL;
/**
*/
private int m_SQLIdx = DTM.NULL;
/**
* Demark the first row element where we started adding rows into the
* Document.
*/
private int m_FirstRowIdx = DTM.NULL;
/**
* Keep track of the Last row inserted into the DTM from the ResultSet.
* This will be used as the index of the parent Row Element when adding
* a row.
*/
private int m_LastRowIdx = DTM.NULL;
/**
* Streaming Mode Control, In Streaming mode we reduce the memory
* footprint since we only use a single row instance.
*/
private boolean m_StreamingMode = true;
/**
* Multiple Result sets mode (metadata inside rowset).
*/
private boolean m_MultipleResults = false;
/**
* Flag to detect if an error occured during an operation
* Defines how errors are handled and how the SQL Connection
* is closed.
*/
private boolean m_HasErrors = false;
/**
* Is statement caching enabled.
*/
private boolean m_IsStatementCachingEnabled = false;
/**
* XConnection this document came from.
*/
private XConnection m_XConnection = null;
/**
* @param mgr
* @param ident
* @throws SQLException
*/
// public cSQLDocument(DTMManager mgr, int ident, Statement stmt,
// ResultSet singleResult, Vector paramdefs, boolean streamingMode,
// boolean multipleResults, boolean statementCachingEnabled) throws SQLException
public SQLDocument(DTMManager mgr, int ident)
{
super(mgr, ident);
}
/**
* This static method simplifies the creation of an SQL Document and allows
* us to embedd the complexity of creating / handling the dtmIdent inside
* the document. This type of method may better placed inside the DTMDocument
* code
*/
public static SQLDocument getNewDocument(ExpressionContext exprContext)
{
DTMManager mgr =
((XPathContext.XPathExpressionContext)exprContext).getDTMManager();
DTMManagerDefault mgrDefault = (DTMManagerDefault) mgr;
int dtmIdent = mgrDefault.getFirstFreeDTMID();
SQLDocument doc =
new SQLDocument(mgr, dtmIdent << DTMManager.IDENT_DTM_NODE_BITS);
// Register the document
mgrDefault.addDTM(doc, dtmIdent);
doc.setExpressionContext(exprContext);
return doc;
}
/**
* When building the SQL Document, we need to store the Expression
* Context that was used to create the document. This will be se to
* reference items int he XSLT process such as any variables that were
* present.
*/
protected void setExpressionContext(ExpressionContext expr)
{
m_ExpressionContext = expr;
}
/**
* Return the context used to build this document
*/
public ExpressionContext getExpressionContext()
{
return m_ExpressionContext;
}
public void execute(XConnection xconn, SQLQueryParser query)
throws SQLException
{
try
{
m_StreamingMode = "true".equals(xconn.getFeature("streaming"));
m_MultipleResults = "true".equals(xconn.getFeature("multiple-results"));
m_IsStatementCachingEnabled = "true".equals(xconn.getFeature("cache-statements"));
m_XConnection = xconn;
m_QueryParser = query;
executeSQLStatement();
createExpandedNameTable();
// Start the document here
m_DocumentIdx = addElement(0, m_Document_TypeID, DTM.NULL, DTM.NULL);
m_SQLIdx = addElement(1, m_SQL_TypeID, m_DocumentIdx, DTM.NULL);
if ( ! m_MultipleResults )
extractSQLMetaData(m_ResultSet.getMetaData());
// Only grab the first row, subsequent rows will be
// fetched on demand.
// We need to do this here so at least on row is set up
// to measure when we are actually reading rows.
// We won't grab the first record in case the skip function
// is applied prior to looking at the first record.
// JCG Changed 9/15/04
// addRowToDTMFromResultSet();
}
catch(SQLException e)
{
m_HasErrors = true;
throw e;
}
}
private void executeSQLStatement() throws SQLException
{
m_ConnectionPool = m_XConnection.getConnectionPool();
Connection conn = m_ConnectionPool.getConnection();
if (! m_QueryParser.hasParameters() )
{
m_Statement = conn.createStatement();
m_ResultSet = m_Statement.executeQuery(m_QueryParser.getSQLQuery());
}
else if (m_QueryParser.isCallable())
{
CallableStatement cstmt =
conn.prepareCall(m_QueryParser.getSQLQuery());
m_QueryParser.registerOutputParameters(cstmt);
m_QueryParser.populateStatement(cstmt, m_ExpressionContext);
m_Statement = cstmt;
if (! cstmt.execute()) throw new SQLException("Error in Callable Statement");
m_ResultSet = m_Statement.getResultSet();
}
else
{
PreparedStatement stmt =
conn.prepareStatement(m_QueryParser.getSQLQuery());
m_QueryParser.populateStatement(stmt, m_ExpressionContext);
m_Statement = stmt;
m_ResultSet = stmt.executeQuery();
}
}
/**
* Push the record set forward value rows. Used to help in
* SQL pagination.
*
* @param value
*/
public void skip( int value )
{
try
{
if (m_ResultSet != null) m_ResultSet.relative(value);
}
catch(Exception origEx)
{
// For now let's assume that the relative method is not supported.
// So let's do it manually.
try
{
for (int x=0; x<value; x++)
{
if (! m_ResultSet.next()) break;
}
}
catch(Exception e)
{
// If we still fail, add in both exceptions
m_XConnection.setError(origEx, this, checkWarnings());
m_XConnection.setError(e, this, checkWarnings());
}
}
}
/**
* Extract the Meta Data and build the Column Attribute List.
* @param meta
* @return
*/
private void extractSQLMetaData( ResultSetMetaData meta )
{
// Build the Node Tree, just add the Column Header
// branch now, the Row & col elements will be added
// on request.
// Add in the row-set Element
// Add in the MetaData Element
m_MetaDataIdx = addElement(1, m_MetaData_TypeID, m_MultipleResults ? m_RowSetIdx : m_SQLIdx, DTM.NULL);
try
{
m_ColCount = meta.getColumnCount();
m_ColHeadersIdx = new int[m_ColCount];
}
catch(Exception e)
{
m_XConnection.setError(e, this, checkWarnings());
//error("ERROR Extracting Metadata");
}
// The ColHeaderIdx will be used to keep track of the
// Element entries for the individual Column Header.
int lastColHeaderIdx = DTM.NULL;
// JDBC Columms Start at 1
int i = 1;
for (i=1; i<= m_ColCount; i++)
{
m_ColHeadersIdx[i-1] =
addElement(2,m_ColumnHeader_TypeID, m_MetaDataIdx, lastColHeaderIdx);
lastColHeaderIdx = m_ColHeadersIdx[i-1];
// A bit brute force, but not sure how to clean it up
try
{
addAttributeToNode(
meta.getColumnName(i),
m_ColAttrib_COLUMN_NAME_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_COLUMN_NAME_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.getColumnLabel(i),
m_ColAttrib_COLUMN_LABEL_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_COLUMN_LABEL_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.getCatalogName(i),
m_ColAttrib_CATALOGUE_NAME_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_CATALOGUE_NAME_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
new Integer(meta.getColumnDisplaySize(i)),
m_ColAttrib_DISPLAY_SIZE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_DISPLAY_SIZE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
new Integer(meta.getColumnType(i)),
m_ColAttrib_COLUMN_TYPE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_COLUMN_TYPE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.getColumnTypeName(i),
m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
new Integer(meta.getPrecision(i)),
m_ColAttrib_PRECISION_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_PRECISION_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
new Integer(meta.getScale(i)),
m_ColAttrib_SCALE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_SCALE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.getSchemaName(i),
m_ColAttrib_SCHEMA_NAME_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_SCHEMA_NAME_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.getTableName(i),
m_ColAttrib_TABLE_NAME_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_TABLE_NAME_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isCaseSensitive(i) ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_CASESENSITIVE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_CASESENSITIVE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isDefinitelyWritable(i) ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_DEFINITELYWRITEABLE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_DEFINITELYWRITEABLE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isNullable(i) != 0 ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_ISNULLABLE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_ISNULLABLE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isSigned(i) ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_ISSIGNED_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_ISSIGNED_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isWritable(i) == true ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_ISWRITEABLE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_ISWRITEABLE_TypeID, lastColHeaderIdx);
}
try
{
addAttributeToNode(
meta.isSearchable(i) == true ? S_ISTRUE : S_ISFALSE,
m_ColAttrib_ISSEARCHABLE_TypeID, lastColHeaderIdx);
}
catch(Exception e)
{
addAttributeToNode(
S_ATTRIB_NOT_SUPPORTED,
m_ColAttrib_ISSEARCHABLE_TypeID, lastColHeaderIdx);
}
}
}
/**
* Populate the Expanded Name Table with the Node that we will use.
* Keep a reference of each of the types for access speed.
* @return
*/
protected void createExpandedNameTable( )
{
super.createExpandedNameTable();
m_SQL_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SQL, DTM.ELEMENT_NODE);
m_MetaData_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_METADATA, DTM.ELEMENT_NODE);
m_ColumnHeader_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_HEADER, DTM.ELEMENT_NODE);
m_RowSet_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ROW_SET, DTM.ELEMENT_NODE);
m_Row_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ROW, DTM.ELEMENT_NODE);
m_Col_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COL, DTM.ELEMENT_NODE);
m_OutParameter_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_OUT_PARAMETERS, DTM.ELEMENT_NODE);
m_ColAttrib_CATALOGUE_NAME_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_CATALOGUE_NAME, DTM.ATTRIBUTE_NODE);
m_ColAttrib_DISPLAY_SIZE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_DISPLAY_SIZE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_COLUMN_LABEL_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_LABEL, DTM.ATTRIBUTE_NODE);
m_ColAttrib_COLUMN_NAME_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_NAME, DTM.ATTRIBUTE_NODE);
m_ColAttrib_COLUMN_TYPE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_TYPE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_COLUMN_TYPENAME_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_COLUMN_TYPENAME, DTM.ATTRIBUTE_NODE);
m_ColAttrib_PRECISION_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_PRECISION, DTM.ATTRIBUTE_NODE);
m_ColAttrib_SCALE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SCALE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_SCHEMA_NAME_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_SCHEMA_NAME, DTM.ATTRIBUTE_NODE);
m_ColAttrib_TABLE_NAME_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_TABLE_NAME, DTM.ATTRIBUTE_NODE);
m_ColAttrib_CASESENSITIVE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_CASESENSITIVE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_DEFINITELYWRITEABLE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_DEFINITELYWRITABLE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_ISNULLABLE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISNULLABLE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_ISSIGNED_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISSIGNED, DTM.ATTRIBUTE_NODE);
m_ColAttrib_ISWRITEABLE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISWRITEABLE, DTM.ATTRIBUTE_NODE);
m_ColAttrib_ISSEARCHABLE_TypeID =
m_expandedNameTable.getExpandedTypeID(S_NAMESPACE, S_ISSEARCHABLE, DTM.ATTRIBUTE_NODE);
}
/**
* Pull a record from the result set and map it to a DTM based ROW
* If we are in Streaming mode, then only create a single row and
* keep copying the data into the same row. This will keep the memory
* footprint constint independant of the RecordSet Size. If we are not
* in Streaming mode then create ROWS for the whole tree.
* @return
*/
private boolean addRowToDTMFromResultSet( )
{
try
{
// If we have not started the RowSet yet, then add it to the
// tree.
if (m_FirstRowIdx == DTM.NULL)
{
m_RowSetIdx =
addElement(1, m_RowSet_TypeID, m_SQLIdx, m_MultipleResults ? m_RowSetIdx : m_MetaDataIdx);
if ( m_MultipleResults ) extractSQLMetaData(m_ResultSet.getMetaData());
}
// Check to see if all the data has been read from the Query.
// If we are at the end the signal that event
if ( ! m_ResultSet.next())
{
// In Streaming mode, the current ROW will always point back
// to itself until all the data was read. Once the Query is
// empty then point the next row to DTM.NULL so that the stream
// ends. Only do this if we have statted the loop to begin with.
if (m_StreamingMode && (m_LastRowIdx != DTM.NULL))
{
// We are at the end, so let's untie the mark
m_nextsib.setElementAt(DTM.NULL, m_LastRowIdx);
}
m_ResultSet.close();
if ( m_MultipleResults )
{
while ( !m_Statement.getMoreResults() && m_Statement.getUpdateCount() >= 0 ) ;
m_ResultSet = m_Statement.getResultSet();
}
else
m_ResultSet = null;
if ( m_ResultSet != null )
{
m_FirstRowIdx = DTM.NULL;
addRowToDTMFromResultSet();
}
else
{
Vector parameters = m_QueryParser.getParameters();
// Get output parameters.
if ( parameters != null )
{
int outParamIdx = addElement(1, m_OutParameter_TypeID, m_SQLIdx, m_RowSetIdx);
int lastColID = DTM.NULL;
for ( int indx = 0 ; indx < parameters.size() ; indx++ )
{
QueryParameter parm = (QueryParameter)parameters.elementAt(indx);
if ( parm.isOutput() )
{
Object rawobj = ((CallableStatement)m_Statement).getObject(indx + 1);
lastColID = addElementWithData(rawobj, 2, m_Col_TypeID, outParamIdx, lastColID);
addAttributeToNode(parm.getName(), m_ColAttrib_COLUMN_NAME_TypeID, lastColID);
addAttributeToNode(parm.getName(), m_ColAttrib_COLUMN_LABEL_TypeID, lastColID);
addAttributeToNode(new Integer(parm.getType()), m_ColAttrib_COLUMN_TYPE_TypeID, lastColID);
addAttributeToNode(parm.getTypeName(), m_ColAttrib_COLUMN_TYPENAME_TypeID, lastColID);
}
}
}
SQLWarning warn = checkWarnings();
if ( warn != null ) m_XConnection.setError(null, null, warn);
}
return false;
}
// If this is the first time here, start the new level
if (m_FirstRowIdx == DTM.NULL)
{
m_FirstRowIdx =
addElement(2, m_Row_TypeID, m_RowSetIdx, m_MultipleResults ? m_MetaDataIdx : DTM.NULL);
m_LastRowIdx = m_FirstRowIdx;
if (m_StreamingMode)
{
// Let's tie the rows together until the end.
m_nextsib.setElementAt(m_LastRowIdx, m_LastRowIdx);
}
}
else
{
//
// If we are in Streaming mode, then only use a single row instance
if (! m_StreamingMode)
{
m_LastRowIdx = addElement(2, m_Row_TypeID, m_RowSetIdx, m_LastRowIdx);
}
}
// If we are not in streaming mode, this will always be DTM.NULL
// If we are in streaming mode, it will only be DTM.NULL the first time
int colID = _firstch(m_LastRowIdx);
// Keep Track of who our parent was when adding new col objects.
int pcolID = DTM.NULL;
// Columns in JDBC Start at 1 and go to the Extent
for (int i=1; i<= m_ColCount; i++)
{
// Just grab the Column Object Type, we will convert it to a string
// later.
Object o = m_ResultSet.getObject(i);
// Create a new column object if one does not exist.
// In Streaming mode, this mechinism will reuse the column
// data the second and subsequent row accesses.
if (colID == DTM.NULL)
{
pcolID = addElementWithData(o,3,m_Col_TypeID, m_LastRowIdx, pcolID);
cloneAttributeFromNode(pcolID, m_ColHeadersIdx[i-1]);
}
else
{
// We must be in streaming mode, so let's just replace the data
// If the firstch was not set then we have a major error
int dataIdent = _firstch(colID);
if (dataIdent == DTM.NULL)
{
error("Streaming Mode, Data Error");
}
else
{
m_ObjectArray.setAt(dataIdent, o);
}
} // If
// In streaming mode, this will be !DTM.NULL
// So if the elements were already established then we
// should be able to walk them in order.
if (colID != DTM.NULL)
{
colID = _nextsib(colID);
}
} // For Col Loop
}
catch(Exception e)
{
if (DEBUG)
{
System.out.println(
"SQL Error Fetching next row [" + e.getLocalizedMessage() + "]");
}
m_XConnection.setError(e, this, checkWarnings());
m_HasErrors = true;
}
// Only do a single row...
return true;
}
/**
* Used by the XConnection to determine if the Document should
* handle the document differently.
*/
public boolean hasErrors()
{
return m_HasErrors;
}
/**
* Close down any resources used by this document. If an SQL Error occure
* while the document was being accessed, the SQL Connection used to create
* this document will be released to the Connection Pool on error. This allows
* the COnnection Pool to give special attention to any connection that may
* be in a errored state.
*
*/
public void close(boolean flushConnPool )
{
try
{
SQLWarning warn = checkWarnings();
if ( warn != null ) m_XConnection.setError(null, null, warn);
}
catch(Exception e) {}
try
{
if (null != m_ResultSet)
{
m_ResultSet.close();
m_ResultSet = null;
}
}
catch(Exception e) {}
Connection conn = null;
try
{
if (null != m_Statement)
{
conn = m_Statement.getConnection();
m_Statement.close();
m_Statement = null;
}
}
catch(Exception e) {}
try
{
if (conn != null)
{
if (m_HasErrors) m_ConnectionPool.releaseConnectionOnError(conn);
else m_ConnectionPool.releaseConnection(conn);
// if (flushConnPool) m_ConnectionPool.freeUnused();
}
}
catch(Exception e) {}
getManager().release(this, true);
}
/**
* @return
*/
protected boolean nextNode( )
{
if (DEBUG) System.out.println("nextNode()");
try
{
return false;
// return m_ResultSet.isAfterLast();
}
catch(Exception e)
{
return false;
}
}
/**
* @param identity
* @return
*/
protected int _nextsib( int identity )
{
// If we are asking for the next row and we have not
// been there yet then let's see if we can get another
// row from the ResultSet.
//
if ( m_ResultSet != null )
{
int id = _exptype(identity);
// We need to prime the pump since we don't do it in execute any more.
if (m_FirstRowIdx == DTM.NULL)
{
addRowToDTMFromResultSet();
}
if (
( id == m_Row_TypeID) &&
(identity >= m_LastRowIdx) )
{
if (DEBUG) System.out.println("reading from the ResultSet");
addRowToDTMFromResultSet();
}
else if ( m_MultipleResults && identity == m_RowSetIdx )
{
if (DEBUG) System.out.println("reading for next ResultSet");
int startIdx = m_RowSetIdx;
while ( startIdx == m_RowSetIdx && m_ResultSet != null )
addRowToDTMFromResultSet();
}
}
return super._nextsib(identity);
}
public void documentRegistration()
{
if (DEBUG) System.out.println("Document Registration");
}
public void documentRelease()
{
if (DEBUG) System.out.println("Document Release");
}
public SQLWarning checkWarnings()
{
SQLWarning warn = null;
if ( m_Statement != null )
{
try
{
warn = m_Statement.getWarnings();
m_Statement.clearWarnings();
}
catch (SQLException se) {}
}
return(warn);
}
}