[#1860] Bad Results returned from plain SQL "select *" queries, if

several selected columns share the same name
[#1720] Improve performance by using Record.getValue(int) instead
of Record.getValue(Field) internally, where more than one value is
retrieved from a record
This commit is contained in:
Lukas Eder 2012-10-21 17:32:56 +02:00
parent 40f82257cd
commit 0bcf286986
2 changed files with 98 additions and 53 deletions

View File

@ -142,7 +142,13 @@ abstract class AbstractRecord extends AbstractStore<Object> implements Record {
@SuppressWarnings("unchecked")
final <T> Value<T> getValue0(int index) {
return (Value<T>) getValues()[index];
Value<?>[] v = getValues();
if (index >= v.length) {
throw new IllegalArgumentException("Field " + index + " is not contained in list");
}
return (Value<T>) v[index];
}
@SuppressWarnings("unchecked")
@ -380,7 +386,7 @@ abstract class AbstractRecord extends AbstractStore<Object> implements Record {
@Override
public final Object getValue(int index) {
return getValue(getField(index));
return getValue0(index).getValue();
}
@Override

View File

@ -54,7 +54,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@ -615,15 +614,10 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return get(index).getValueAsTime(fieldName, defaultValue);
}
@SuppressWarnings("unchecked")
@Override
public final <T> List<T> getValues(Field<T> field) {
List<T> result = new ArrayList<T>(size());
for (R record : this) {
result.add(record.getValue(field));
}
return result;
return (List<T>) getValues(fields.getIndex(field));
}
@Override
@ -638,7 +632,13 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final List<?> getValues(int fieldIndex) {
return getValues(getField(fieldIndex));
List<Object> result = new ArrayList<Object>(size());
for (R record : this) {
result.add(record.getValue(fieldIndex));
}
return result;
}
@Override
@ -939,8 +939,13 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
final int MAX_RECORDS = min(50, maxRecords);
// Get max decimal places for numeric type columns
Map<Field<?>, Integer> decimalPlacesMap = new HashMap<Field<?>, Integer>();
for (Field<?> f : getFields()) {
final int size = getFields().size();
final int[] decimalPlaces = new int[size];
final int[] widths = new int[size];
for (int index = 0; index < size; index++) {
Field<?> f = getField(index);
if (Number.class.isAssignableFrom(f.getType())) {
List<Integer> decimalPlacesList = new ArrayList<Integer>();
@ -950,19 +955,20 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
// Collect all decimal places for the column values
String value;
for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
value = format0(getValue(i, f));
value = format0(getValue(i, index));
decimalPlacesList.add(getDecimalPlaces(value));
}
// Find max
decimalPlacesMap.put(f, Collections.max(decimalPlacesList));
decimalPlaces[index] = Collections.max(decimalPlacesList);
}
}
// Get max column widths
Map<Field<?>, Integer> widthMap = new HashMap<Field<?>, Integer>();
int colMaxWidth;
for (Field<?> f : getFields()) {
for (int index = 0; index < size; index++) {
Field<?> f = getField(index);
// Is number column?
boolean isNumCol = Number.class.isAssignableFrom(f.getType());
@ -977,17 +983,17 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
// Add column values width
String value;
for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
value = format0(getValue(i, f));
value = format0(getValue(i, index));
// Align number values before width is calculated
if (isNumCol) {
value = alignNumberValue(decimalPlacesMap.get(f), value);
value = alignNumberValue(decimalPlaces[index], value);
}
widthList.add(min(colMaxWidth, value.length()));
}
// Find max
widthMap.put(f, Collections.max(widthList));
widths[index] = Collections.max(widthList);
}
// Begin the writing
@ -996,54 +1002,57 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
// Write top line
sb.append("+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widthMap.get(f), "-"));
for (int index = 0; index < size; index++) {
sb.append(rightPad("", widths[index], "-"));
sb.append("+");
}
// Write headers
sb.append("\n|");
for (Field<?> f : getFields()) {
for (int index = 0; index < size; index++) {
Field<?> f = getField(index);
String padded;
if (Number.class.isAssignableFrom(f.getType())) {
padded = leftPad(f.getName(), widthMap.get(f));
padded = leftPad(f.getName(), widths[index]);
}
else {
padded = rightPad(f.getName(), widthMap.get(f));
padded = rightPad(f.getName(), widths[index]);
}
sb.append(abbreviate(padded, widthMap.get(f)));
sb.append(abbreviate(padded, widths[index]));
sb.append("|");
}
// Write separator
sb.append("\n+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widthMap.get(f), "-"));
for (int index = 0; index < size; index++) {
sb.append(rightPad("", widths[index], "-"));
sb.append("+");
}
// Write columns
for (int i = 0; i < min(maxRecords, size()); i++) {
sb.append("\n|");
for (Field<?> f : getFields()) {
String value = format0(getValue(i, f)).replace("\n", "{lf}").replace("\r", "{cr}");
for (int index = 0; index < size; index++) {
Field<?> f = getField(index);
String value = format0(getValue(i, index)).replace("\n", "{lf}").replace("\r", "{cr}");
String padded;
if (Number.class.isAssignableFrom(f.getType())) {
// Align number value before left pad
value = alignNumberValue(decimalPlacesMap.get(f), value);
value = alignNumberValue(decimalPlaces[index], value);
// Left pad
padded = leftPad(value, widthMap.get(f));
padded = leftPad(value, widths[index]);
}
else {
// Right pad
padded = rightPad(value, widthMap.get(f));
padded = rightPad(value, widths[index]);
}
sb.append(abbreviate(padded, widthMap.get(f)));
sb.append(abbreviate(padded, widths[index]));
sb.append("|");
}
}
@ -1051,8 +1060,9 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
// Write bottom line
if (size() > 0) {
sb.append("\n+");
for (Field<?> f : getFields()) {
sb.append(rightPad("", widthMap.get(f), "-"));
for (int index = 0; index < size; index++) {
sb.append(rightPad("", widths[index], "-"));
sb.append("+");
}
}
@ -1097,6 +1107,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final String formatHTML() {
final int size = getFields().size();
StringBuilder sb = new StringBuilder();
sb.append("<table>");
@ -1116,9 +1128,9 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
for (Record record : this) {
sb.append("<tr>");
for (Field<?> field : getFields()) {
for (int index = 0; index < size; index++) {
sb.append("<td>");
sb.append(format0(record.getValue(field)));
sb.append(format0(record.getValue(index)));
sb.append("</td>");
}
@ -1143,6 +1155,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final String formatCSV(char delimiter, String nullString) {
final int size = getFields().size();
StringBuilder sb = new StringBuilder();
String sep1 = "";
@ -1157,9 +1171,10 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
for (Record record : this) {
String sep2 = "";
for (Field<?> field : getFields()) {
for (int index = 0; index < size; index++) {
sb.append(sep2);
sb.append(formatCSV0(record.getValue(field), nullString));
sb.append(formatCSV0(record.getValue(index), nullString));
sep2 = Character.toString(delimiter);
}
@ -1216,6 +1231,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final String formatJSON() {
final int size = getFields().size();
List<Map<String, String>> f = new ArrayList<Map<String, String>>();
List<List<Object>> r = new ArrayList<List<Object>>();
@ -1231,8 +1248,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
for (Record record : this) {
List<Object> list = new ArrayList<Object>();
for (Field<?> field : getFields()) {
list.add(record.getValue(field));
for (int index = 0; index < size; index++) {
list.add(record.getValue(index));
}
r.add(list);
@ -1248,6 +1265,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final String formatXML() {
final int size = getFields().size();
StringBuilder sb = new StringBuilder();
sb.append("<result xmlns=\"http://www.jooq.org/xsd/jooq-export-2.6.0.xsd\">");
@ -1268,8 +1287,9 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
for (Record record : this) {
sb.append("<record>");
for (Field<?> field : getFields()) {
Object value = record.getValue(field);
for (int index = 0; index < size; index++) {
Field<?> field = getField(index);
Object value = record.getValue(index);
sb.append("<value field=\"");
sb.append(escapeXML(field.getName()));
@ -1301,6 +1321,8 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
@Override
public final Document intoXML() {
final int size = getFields().size();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
@ -1327,8 +1349,9 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
Element eRecord = document.createElement("record");
eRecords.appendChild(eRecord);
for (Field<?> field : getFields()) {
Object value = record.getValue(field);
for (int index = 0; index < size; index++) {
Field<?> field = getField(index);
Object value = record.getValue(index);
Element eValue = document.createElement("value");
eValue.setAttribute("field", field.getName());
@ -1365,12 +1388,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
}
@SuppressWarnings("unchecked")
@Override
public final <K> Map<K, R> intoMap(Field<K> key) {
int index = getIndex(key);
Map<K, R> map = new LinkedHashMap<K, R>();
for (R record : this) {
if (map.put(record.getValue(key), record) != null) {
if (map.put((K) record.getValue(index), record) != null) {
throw new InvalidResultException("Key " + key + " is not unique in Result for " + this);
}
}
@ -1378,12 +1403,16 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, V> Map<K, V> intoMap(Field<K> key, Field<V> value) {
int kIndex = getIndex(key);
int vIndex = getIndex(value);
Map<K, V> map = new LinkedHashMap<K, V>();
for (R record : this) {
if (map.put(record.getValue(key), record.getValue(value)) != null) {
if (map.put((K) record.getValue(kIndex), (V) record.getValue(vIndex)) != null) {
throw new InvalidResultException("Key " + key + " is not unique in Result for " + this);
}
}
@ -1437,12 +1466,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, E> intoMap(Field<K> key, Class<? extends E> type) {
int index = getIndex(key);
Map<K, E> map = new LinkedHashMap<K, E>();
for (R record : this) {
if (map.put(record.getValue(key), record.into(type)) != null) {
if (map.put((K) record.getValue(index), record.into(type)) != null) {
throw new InvalidResultException("Key " + key + " is not unique in Result for " + this);
}
}
@ -1450,12 +1481,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K> Map<K, Result<R>> intoGroups(Field<K> key) {
int index = getIndex(key);
Map<K, Result<R>> map = new LinkedHashMap<K, Result<R>>();
for (R record : this) {
K val = record.getValue(key);
K val = (K) record.getValue(index);
Result<R> result = map.get(val);
if (result == null) {
@ -1469,13 +1502,17 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, V> Map<K, List<V>> intoGroups(Field<K> key, Field<V> value) {
int kIndex = getIndex(key);
int vIndex = getIndex(value);
Map<K, List<V>> map = new LinkedHashMap<K, List<V>>();
for (R record : this) {
K k = record.getValue(key);
V v = record.getValue(value);
K k = (K) record.getValue(kIndex);
V v = (V) record.getValue(vIndex);
List<V> result = map.get(k);
if (result == null) {
@ -1517,12 +1554,14 @@ class ResultImpl<R extends Record> implements Result<R>, AttachableInternal {
return map;
}
@SuppressWarnings("unchecked")
@Override
public final <K, E> Map<K, List<E>> intoGroups(Field<K> key, Class<? extends E> type) {
int index = getIndex(key);
Map<K, List<E>> map = new LinkedHashMap<K, List<E>>();
for (R record : this) {
K keyVal = record.getValue(key);
K keyVal = (K) record.getValue(index);
List<E> list = map.get(keyVal);
if (list == null) {