1 /*
2 * Tentackle - https://tentackle.org.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 package org.tentackle.dbms;
20
21 import org.tentackle.session.PersistenceException;
22
23 import java.sql.ResultSetMetaData;
24 import java.sql.SQLException;
25 import java.util.HashMap;
26 import java.util.Locale;
27 import java.util.Map;
28
29 /**
30 * A subset of the columns returned by a {@link ResultSetWrapper}.
31 *
32 * @author harald
33 */
34 public class ResultSetSkipBlock {
35
36 private final ResultSetWrapper rs; // the rs wrapper
37 private final int skippedColumns; // number of columns skipped
38 private final Map<String,Integer> columnMap; // the current map of columns
39 private int maxColumnIndex; // the highest used column index so far
40
41 /**
42 * Creates a skip block.
43 *
44 * @param rs the result set
45 * @param skippedColumns the number of columns skipped
46 */
47 public ResultSetSkipBlock(ResultSetWrapper rs, int skippedColumns) {
48 this.rs = rs;
49 this.skippedColumns = skippedColumns;
50 this.maxColumnIndex = skippedColumns;
51 // build the column map
52 columnMap = new HashMap<>();
53 int max = rs.getColumnCount();
54 ResultSetMetaData meta = rs.getMetaData();
55 for (int i = skippedColumns + 1; i <= max; i++) {
56 try {
57 // append only the first occurrence (from the left).
58 // lowercase because column names are converted to lowercase in the model (see AttributeImpl)
59 columnMap.putIfAbsent(meta.getColumnName(i).toLowerCase(Locale.ROOT), i);
60 }
61 catch (SQLException e) {
62 throw new PersistenceException(rs.getSession(), e);
63 }
64 }
65 }
66
67 /**
68 * Gets the number of columns skipped in the result set.
69 *
70 * @return the number of skipped columns, 0 if no column skipped
71 */
72 public int getSkippedColumns() {
73 return skippedColumns;
74 }
75
76 /**
77 * Gets the highest used column index.<br>
78 * This will be the skippedColumns of the next skip block.
79 *
80 * @return the highest-used index
81 */
82 public int getMaxColumnIndex() {
83 return maxColumnIndex;
84 }
85
86 /**
87 * Maps the given column name to its column index.
88 * <p>
89 * Finds the first column with that name after the skipped columns of this block.
90 * The column names of the result set are mapped in lowercase.
91 *
92 * @param name the column name
93 * @return the index in the result set
94 * @throws PersistenceException if no such column beyond the skipped columns
95 */
96 public int findColumn(String name) {
97 Integer ndx = columnMap.get(name);
98 if (ndx == null) {
99 throw new PersistenceException(rs.getSession(),
100 "no such column '" + name + "' beyond " + skippedColumns + " skipped columns in " + rs);
101 }
102 applyColumnIndex(ndx);
103 return ndx;
104 }
105
106 /**
107 * Applies the used column index to this skip block.
108 *
109 * @param ndx the used column index
110 */
111 public void applyColumnIndex(int ndx) {
112 if (ndx > maxColumnIndex) { // remember the highest configured column
113 maxColumnIndex = ndx;
114 }
115 }
116
117 }