Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 1badf50b1041c43aa14549747da7690080213a41 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*******************************************************************************
 * Copyright (c) 2011, 2013 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.common.utility.internal.jdbc;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * {@link ResultSet} utility methods.
 */
public class ResultSetTools {
	/**
	 * Return an iterator the returns the first object in each row of the
	 * specified result set. The first object in each must be of type
	 * {@code <E>}. The iterator will close the result set once it has returned
	 * all its elements.
	 * @see ResultSetIterator
	 */
	@SuppressWarnings("unchecked")
	public static <E> ResultSetIterator<E> iterator(ResultSet resultSet) throws SQLException {
		return (ResultSetIterator<E>) iterator(resultSet, defaultRowTransformer());
	}

	/**
	 * Return a row transformer the returns the first object in a result set's
	 * current row.
	 */
	@SuppressWarnings("unchecked")
	public static <E> ResultSetRowTransformer<E> defaultRowTransformer() {
		return DEFAULT_ROW_TRANSFORMER;
	}

	/**
	 * A row transformer the returns the first object in a result set's
	 * current row.
	 */
	@SuppressWarnings("rawtypes")
	public static final ResultSetRowTransformer DEFAULT_ROW_TRANSFORMER = new DefaultRowTransformer();

	/**
	 * A row transformer the returns the first object in a result set's
	 * current row.
	 */
	public static class DefaultRowTransformer<E>
		extends ResultSetRowTransformerAdapter<E>
	{
		@Override
		@SuppressWarnings("unchecked")
		public E transform(ResultSet rs) throws SQLException {
			// result set columns are indexed starting with 1
			return (E) rs.getObject(1);
		}
	}

	/**
	 * Return an iterator the returns the objects produced by the specified row
	 * transformer. The transformer will be used to convert each row in the
	 * result set into an object. The iterator will close the result set once
	 * it has returned all its elements.
	 * @see ResultSetIterator
	 */
	public static <E> ResultSetIterator<E> iterator(ResultSet resultSet, ResultSetRowTransformer<? extends E> rowTransformer) throws SQLException {
		return new ResultSetIterator<E>(resultSet, rowTransformer);
	}

	/**
	 * Convert the specified result set into a list of maps, each map
	 * corresponding a result set row and mapping column names to their
	 * corresponding row values. The result set will be closed upon return
	 * from this method.
	 */
	public static List<Map<String, Object>> convertToMaps(ResultSet resultSet) throws SQLException {
		return convertToList(resultSet, mapRowTransformer(resultSet));
	}

	/**
	 * Convert the specified result set into a list of maps, each map
	 * corresponding a result set row and mapping column names to their
	 * corresponding row values. The result set will be closed upon return
	 * from this method.
	 */
	public static <E> List<E> convertToList(ResultSet resultSet, ResultSetRowTransformer<? extends E> rowTransformer) throws SQLException {
		List<E> rows = new ArrayList<E>();
		for (ResultSetIterator<E> stream = iterator(resultSet, rowTransformer); stream.hasNext(); ) {
			rows.add(stream.next());
		}
		return rows;
	}

	/**
	 * Convert the specified result set into an iterator of maps, each map
	 * corresponding a result set row and mapping column names to their
	 * corresponding row values. The iterator will close the result set once
	 * it has returned all its elements.
	 */
	public static ResultSetIterator<Map<String, Object>> mapIterator(ResultSet resultSet) throws SQLException {
		return iterator(resultSet, mapRowTransformer(resultSet));
	}

	/**
	 * Return a result set row transformer that will transform the specified
	 * result set's current row into a map of the column names to their
	 * corresponding row values.
	 */
	public static MapRowTransformer mapRowTransformer(ResultSet resultSet) throws SQLException {
		return new MapRowTransformer(resultSet);
	}

	/**
	 * A row transformer the converts a result set's current row into a map of
	 * the row's column names to their corresponding values in the row.
	 */
	public static class MapRowTransformer
		extends ResultSetRowTransformerAdapter<Map<String, Object>>
	{
		private final int columnCount;
		private final String[] columnNames;

		/**
		 * The specified array of column names must be 1-based
		 * (i.e. the value at index 0 is ignored).
		 * @see ResultSet#getObject(int)
		 */
		public MapRowTransformer(ResultSet resultSet) throws SQLException {
			super();
			ResultSetMetaData rsMetaData = resultSet.getMetaData();
			this.columnCount = rsMetaData.getColumnCount() + 1;
			this.columnNames = this.buildColumnNames(rsMetaData);
		}

		/**
		 * Return the names of the specified result set's columns in an array where
		 * the index of each name matches its column index in the result set.
		 * <p>
		 * <strong>NB:</strong> A result set's index is 1-based
		 * (i.e. it is a "subscript). As a result the returned array will contain a
		 * <code>null</code> at index 0.
		 * 
		 * @see ResultSet#getObject(int)
		 */
		private String[] buildColumnNames(ResultSetMetaData rsMetaData) throws SQLException {
			String[] names = new String[this.columnCount];
			for (int i = 1; i < names.length; i++) {  // NB: start with 1
				names[i] = rsMetaData.getColumnName(i);
			}
			return names;
		}

		@Override
		public Map<String, Object> transform(ResultSet resultSet) throws SQLException {
			// use a linked hash map so the column order is preserved
			LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>(this.columnCount);
			for (int i = 1; i < this.columnCount; i++) {  // NB: start with 1 (ResultSet is 1-based)
				map.put(this.columnNames[i], resultSet.getObject(i));
			}
			return map;
		}
	}

	/**
	 * Dump contents of the specified result set to the
	 * {@link System#out system console}. The result set will be closed upon return
	 * from this method.
	 */
	public static void dump(ResultSet resultSet) throws SQLException {
		PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
		// synchronize the console so everything is contiguous
		synchronized (System.out) {
			dumpOn(resultSet, pw);
		}
		pw.flush();
	}

	/**
	 * Dump contents of the specified result set to the specified writer.
	 * The result set will be closed upon return from this method.
	 */
	public static void dumpOn(ResultSet resultSet, PrintWriter pw) throws SQLException {
		List<Map<String, Object>> maps = convertToMaps(resultSet);
		for (Iterator<Map<String, Object>> mapStream = maps.iterator(); mapStream.hasNext(); ) {
			for (Map.Entry<String, Object> entry : mapStream.next().entrySet()) {
				pw.print(entry.getKey());
				pw.print(" = "); //$NON-NLS-1$
				pw.print(entry.getValue());
				pw.println();
			}
			if (mapStream.hasNext()) {
				pw.println();
			}
		}
		pw.println("total rows: " + maps.size()); //$NON-NLS-1$
	}
}

Back to the top