1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package javax.servlet.jsp.jstl.sql;
18
19 import java.sql.*;
20 import java.util.*;
21
22 /***
23 * <p>This class creates a cached version of a <tt>ResultSet</tt>.
24 * It's represented as a <tt>Result</tt> implementation, capable of
25 * returing an array of <tt>Row</tt> objects containing a <tt>Column</tt>
26 * instance for each column in the row. It is not part of the JSTL
27 * API; it serves merely as a back-end to ResultSupport's static methods.
28 * Thus, we scope its access to the package.
29 *
30 * @author Hans Bergsten
31 * @author Justyna Horwat
32 */
33
34 class ResultImpl implements Result {
35 private List rowMap;
36 private List rowByIndex;
37 private String[] columnNames;
38 private boolean isLimited;
39
40 /***
41 * This constructor reads the ResultSet and saves a cached
42 * copy.
43 *
44 * @param rs an open <tt>ResultSet</tt>, positioned before the first
45 * row
46 * @param startRow, beginning row to be cached
47 * @param maxRows, query maximum rows limit
48 * @exception if a database error occurs
49 */
50 public ResultImpl(ResultSet rs, int startRow, int maxRows)
51 throws SQLException
52 {
53 rowMap = new ArrayList();
54 rowByIndex = new ArrayList();
55
56 ResultSetMetaData rsmd = rs.getMetaData();
57 int noOfColumns = rsmd.getColumnCount();
58
59
60 columnNames = new String[noOfColumns];
61 for (int i = 1; i <= noOfColumns; i++) {
62 columnNames[i-1] = rsmd.getColumnName(i);
63 }
64
65
66 for (int i = 0; i < startRow; i++) {
67 rs.next();
68 }
69
70
71 int processedRows = 0;
72 while (rs.next()) {
73 if ((maxRows != -1) && (processedRows == maxRows)) {
74 isLimited = true;
75 break;
76 }
77 Object[] columns = new Object[noOfColumns];
78 SortedMap columnMap =
79 new TreeMap(String.CASE_INSENSITIVE_ORDER);
80
81
82 for (int i = 1; i <= noOfColumns; i++) {
83 Object value = rs.getObject(i);
84 if (rs.wasNull()) {
85 value = null;
86 }
87 columns[i-1] = value;
88 columnMap.put(columnNames[i-1], value);
89 }
90 rowMap.add(columnMap);
91 rowByIndex.add(columns);
92 processedRows++;
93 }
94 }
95
96 /***
97 * Returns an array of SortedMap objects. The SortedMap
98 * object key is the ColumnName and the value is the ColumnValue.
99 * SortedMap was created using the CASE_INSENSITIVE_ORDER
100 * Comparator so the key is the case insensitive representation
101 * of the ColumnName.
102 *
103 * @return an array of Map, or null if there are no rows
104 */
105 public SortedMap[] getRows() {
106 if (rowMap == null) {
107 return null;
108 }
109
110
111 return (SortedMap []) rowMap.toArray(new SortedMap[0]);
112 }
113
114
115 /***
116 * Returns an array of Object[] objects. The first index
117 * designates the Row, the second the Column. The array
118 * stores the value at the specified row and column.
119 *
120 * @return an array of Object[], or null if there are no rows
121 */
122 public Object[][] getRowsByIndex() {
123 if (rowByIndex == null) {
124 return null;
125 }
126
127
128 return (Object [][])rowByIndex.toArray(new Object[0][0]);
129 }
130
131 /***
132 * Returns an array of String objects. The array represents
133 * the names of the columns arranged in the same order as in
134 * the getRowsByIndex() method.
135 *
136 * @return an array of String[]
137 */
138 public String[] getColumnNames() {
139 return columnNames;
140 }
141
142 /***
143 * Returns the number of rows in the cached ResultSet
144 *
145 * @return the number of cached rows, or -1 if the Result could
146 * not be initialized due to SQLExceptions
147 */
148 public int getRowCount() {
149 if (rowMap == null) {
150 return -1;
151 }
152 return rowMap.size();
153 }
154
155 /***
156 * Returns true of the query was limited by a maximum row setting
157 *
158 * @return true if the query was limited by a MaxRows attribute
159 */
160 public boolean isLimitedByMaxRows() {
161 return isLimited;
162 }
163
164 }