001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * Created Aug 31, 2005
014: * @author wseyler
015: */
016: package org.pentaho.data.connection.sql;
017:
018: import java.sql.ResultSet;
019: import java.sql.SQLException;
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022: import org.pentaho.commons.connection.IPentahoMetaData;
023: import org.pentaho.commons.connection.IPentahoResultSet;
024: import org.pentaho.commons.connection.memory.MemoryMetaData;
025: import org.pentaho.commons.connection.memory.MemoryResultSet;
026: import org.pentaho.messages.Messages;
027:
028: /**
029: * @author wseyler
030: *
031: * TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
032: */
033: public class SQLResultSet implements IPentahoResultSet {
034: ResultSet nativeResultSet = null;
035:
036: SQLConnection connection;
037:
038: private static final int COUNT_NEVER_OBTAINED = -2;
039:
040: private int rowCount = COUNT_NEVER_OBTAINED;
041:
042: private int columnCount = COUNT_NEVER_OBTAINED;
043:
044: private static final Log log = LogFactory
045: .getLog(SQLResultSet.class);
046:
047: private IPentahoMetaData metadata;
048:
049: /**
050: *
051: */
052: public SQLResultSet(ResultSet nativeResultSet,
053: SQLConnection nativeConnection) {
054: super ();
055: this .connection = nativeConnection;
056: this .nativeResultSet = nativeResultSet;
057: }
058:
059: public void setMetaData(IPentahoMetaData metadata) {
060: this .metadata = metadata;
061: }
062:
063: /*
064: * (non-Javadoc)
065: *
066: * @see org.pentaho.connection.IPentahoResultSet#getMetaData()
067: */
068: public IPentahoMetaData getMetaData() {
069: if (metadata == null) {
070: try {
071: metadata = new SQLMetaData(nativeResultSet
072: .getMetaData());
073: } catch (SQLException e) {
074: // TODO Auto-generated catch block
075: log
076: .error(
077: Messages
078: .getErrorString("SQLResultSet.ERROR_0004_GET_METADATA"), e); //$NON-NLS-1$
079: // e.printStackTrace();
080: throw new RuntimeException(e);
081: }
082: }
083: return metadata;
084: }
085:
086: /**
087: * (non-Javadoc)
088: *
089: * @see org.pentaho.connection.IPentahoResultSet#next() returns null if no more rows
090: *
091: * @throws SQLResultSetException
092: */
093: public Object[] next() {
094: try {
095: int columns = nativeResultSet.getMetaData()
096: .getColumnCount();
097: if (nativeResultSet.next()) {
098: Object[] row = new Object[columns];
099: for (int column = 0; column < columns; column++) {
100: row[column] = nativeResultSet.getObject(column + 1);
101: }
102: return row;
103: }
104: } catch (SQLException e) {
105: // TODO surface this error
106: log.error(Messages
107: .getErrorString("SQLResultSet.ERROR_0005_NEXT"), e); //$NON-NLS-1$
108: throw new SQLResultSetException(Messages
109: .getErrorString("SQLResultSet.ERROR_0005_NEXT"), e); //$NON-NLS-1$
110: }
111: return null;
112: }
113:
114: public void closeConnection() {
115: close();
116: if (connection != null) {
117: try {
118: connection.close();
119: } catch (Exception ignored) {
120: }
121: }
122: connection = null;
123: }
124:
125: public void close() {
126: if (nativeResultSet != null) {
127: try {
128: nativeResultSet.close();
129: } catch (SQLException e) {
130: // TODO sbarkdull, localize this!
131: log
132: .warn(Messages
133: .getString("SQLResultSet.WARN_CONNECTION_NOT_CLOSED")); //$NON-NLS-1$
134: }
135: rowCount = COUNT_NEVER_OBTAINED;
136: }
137: nativeResultSet = null;
138: }
139:
140: public void dispose() {
141: closeConnection();
142: }
143:
144: public boolean isScrollable() {
145: int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
146: try {
147: resultSetType = nativeResultSet.getType();
148: } catch (SQLException ex) {
149: log
150: .warn(Messages
151: .getString("SQLResultSet.WARN_RESULTSET_TYPE_UNDETERMINED")); //$NON-NLS-1$
152: }
153: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
154: return false;
155: } else {
156: return true;
157: }
158: }
159:
160: /**
161: * Returns the column count from the result set.
162: *
163: * @return the column count.
164: */
165: public int getColumnCount() {
166: if (columnCount != COUNT_NEVER_OBTAINED) {
167: // We have already calculated column count, return what we have.
168: return columnCount;
169: }
170: if (nativeResultSet == null) {
171: return 0;
172: }
173: try {
174: columnCount = nativeResultSet.getMetaData()
175: .getColumnCount();
176: return columnCount;
177: } catch (SQLException ex) {
178: // TODO: Surfase this exception.
179: log
180: .error(
181: Messages
182: .getErrorString("SQLResultSet.ERROR_0006_GET_COLUMNCOUNT"), ex); //$NON-NLS-1$
183: }
184: return 0;
185: }
186:
187: /**
188: * Get a rowCount from the resultset. If the resultset
189: *
190: * @return the row count.
191: */
192: public int getRowCount() {
193: if (rowCount != COUNT_NEVER_OBTAINED) {
194: // We have already calculated rowcount, return what we have
195: return rowCount;
196: }
197: // No resultset
198: if (nativeResultSet == null) {
199: return 0;
200: }
201: try {
202: // Get current row in the resultset
203: int curRow = nativeResultSet.getRow();
204: try {
205: // Seek to the end of the resultset. This could be very
206: // bad for performance if the cursor is client-side.
207: if (nativeResultSet.last()) {
208: // Get the rownumber of the last row
209: rowCount = nativeResultSet.getRow();
210: // Boundary case
211: if (rowCount <= 0) {
212: rowCount = 0;
213: }
214: } else {
215: // Couldn't seek to last row - Scrollable resultsets not
216: // supported?
217: // TODO: Possibly throw an exception in this case
218: rowCount = 0;
219: }
220: } finally {
221: // There is no row 0 - if the curRow was 0, go to before the
222: // first row in the resultset
223: if (curRow == 0) {
224: nativeResultSet.beforeFirst();
225: } else {
226: // Go back where we started
227: nativeResultSet.absolute(curRow);
228: }
229: }
230: } catch (SQLException sqle) {
231: log
232: .error(
233: Messages
234: .getErrorString("SQLResultSet.ERROR_0001_OBTAINING_ROWCOUNT"), sqle); //$NON-NLS-1$
235: rowCount = 0;
236: }
237: return rowCount;
238: }
239:
240: /**
241: * Returns the value of the specified row and the specified column from within the resultset.
242: *
243: * @param row
244: * the row index.
245: * @param column
246: * the column index.
247: * @return the value.
248: */
249: public Object getValueAt(int row, int column) {
250: if (nativeResultSet != null) {
251: try {
252: nativeResultSet.absolute(row + 1);
253: return nativeResultSet.getObject(column + 1);
254: } catch (SQLException ex) {
255: log
256: .error(
257: Messages
258: .getErrorString("SQLResultSet.ERROR_0002_GET_VALUE"), ex); //$NON-NLS-1$
259: ex.printStackTrace();
260: }
261: }
262: return null;
263: }
264:
265: public IPentahoResultSet memoryCopy() {
266: try {
267: IPentahoMetaData meta = getMetaData();
268: Object columnHeaders[][] = meta.getColumnHeaders();
269: MemoryMetaData cachedMetaData = new MemoryMetaData(
270: columnHeaders, null);
271: MemoryResultSet cachedResultSet = new MemoryResultSet(
272: cachedMetaData);
273: Object[] rowObjects = next();
274: while (rowObjects != null) {
275: cachedResultSet.addRow(rowObjects);
276: rowObjects = next();
277: }
278: return cachedResultSet;
279: } finally {
280: close();
281: }
282: }
283:
284: public void beforeFirst() {
285: try {
286: if (nativeResultSet == null) {
287: log
288: .error(Messages
289: .getErrorString("SQLResultSet.ERROR_0007_BEFORE_FIRST_CONNECTION_CLOSED")); //$NON-NLS-1$
290: } else {
291: nativeResultSet.beforeFirst();
292: }
293: } catch (SQLException e) {
294: log
295: .error(
296: Messages
297: .getErrorString("SQLResultSet.ERROR_0003_BEFORE_FIRST"), e); //$NON-NLS-1$
298: // TODO Auto-generated catch block
299: e.printStackTrace();
300: }
301: }
302:
303: public Object[] getDataColumn(int column) {
304: Object[] result = null;
305: result = new Object[getRowCount()];
306: for (int row = 0; row < result.length; row++) {
307: result[row] = getValueAt(row, column);
308: }
309: return result;
310: }
311:
312: public Object[] getDataRow(int row) {
313: Object[] rowData = new Object[this .getColumnCount()];
314: for (int column = 0; column < rowData.length; column++) {
315: rowData[column] = getValueAt(row, column);
316: }
317: return rowData;
318: }
319: }
|