[#8040] Prevent excess loop in Fields.indexOf() methods
This commit is contained in:
parent
936da988ab
commit
5ff097fcbd
@ -84,46 +84,62 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T> Field<T> field(Field<T> field) {
|
||||
return (Field<T>) field0(field, RETURN_FIELD);
|
||||
}
|
||||
|
||||
private final <U> U field0(Field<?> field, FieldOrIndex<U> result) {
|
||||
if (field == null)
|
||||
return null;
|
||||
return result.resultNull();
|
||||
|
||||
// [#4540] Try finding a match by identity
|
||||
for (Field<?> f : fields)
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> f = fields[i];
|
||||
|
||||
if (f == field)
|
||||
return (Field<T>) f;
|
||||
return result.result(f, i);
|
||||
}
|
||||
|
||||
// [#1802] Try finding an exact match (e.g. exact matching qualified name)
|
||||
for (Field<?> f : fields)
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> f = fields[i];
|
||||
|
||||
if (f.equals(field))
|
||||
return (Field<T>) f;
|
||||
return result.result(f, i);
|
||||
}
|
||||
|
||||
// [#4283] table / column matches are better than only column matches
|
||||
Field<?> columnMatch = null;
|
||||
Field<?> columnMatch2 = null;
|
||||
int indexMatch = -1;
|
||||
|
||||
String tableName = tableName(field);
|
||||
String fieldName = field.getName();
|
||||
|
||||
for (Field<?> f : fields) {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> f = fields[i];
|
||||
String fName = f.getName();
|
||||
|
||||
if (tableName != null) {
|
||||
String tName = tableName(f);
|
||||
|
||||
if (tName != null && tableName.equals(tName) && fName.equals(fieldName))
|
||||
return (Field<T>) f;
|
||||
return result.result(f, i);
|
||||
}
|
||||
|
||||
// In case no exact match was found, return the first field with matching name
|
||||
if (fName.equals(fieldName)) {
|
||||
if (columnMatch == null)
|
||||
if (columnMatch == null) {
|
||||
columnMatch = f;
|
||||
else
|
||||
// [#4476] [#4477] This might be unintentional from a user
|
||||
// perspective, e.g. when ambiguous ID columns are present.
|
||||
// [#5578] Finish the loop, though, as we might have an exact match
|
||||
// despite some ambiguity
|
||||
indexMatch = i;
|
||||
}
|
||||
|
||||
// [#4476] [#4477] This might be unintentional from a user
|
||||
// perspective, e.g. when ambiguous ID columns are present.
|
||||
// [#5578] Finish the loop, though, as we might have an exact match
|
||||
// despite some ambiguity
|
||||
else {
|
||||
columnMatch2 = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +147,7 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
if (log.isInfoEnabled())
|
||||
log.info("Ambiguous match found for " + fieldName + ". Both " + columnMatch + " and " + columnMatch2 + " match.", new SQLWarning());
|
||||
|
||||
return (Field<T>) columnMatch;
|
||||
return result.result(columnMatch, indexMatch);
|
||||
}
|
||||
|
||||
private final String tableName(Field<?> field) {
|
||||
@ -147,21 +163,34 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
|
||||
@Override
|
||||
public final Field<?> field(String fieldName) {
|
||||
return field0(fieldName, RETURN_FIELD);
|
||||
}
|
||||
|
||||
private final <U> U field0(String fieldName, FieldOrIndex<U> result) {
|
||||
if (fieldName == null)
|
||||
return null;
|
||||
return result.resultNull();
|
||||
|
||||
Field<?> columnMatch = null;
|
||||
int indexMatch = -1;
|
||||
|
||||
for (Field<?> f : fields)
|
||||
if (f.getName().equals(fieldName))
|
||||
if (columnMatch == null)
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
Field<?> f = fields[i];
|
||||
|
||||
if (f.getName().equals(fieldName)) {
|
||||
if (columnMatch == null) {
|
||||
columnMatch = f;
|
||||
else
|
||||
// [#4476] [#4477] [#5046] This might be unintentional from a user
|
||||
// perspective, e.g. when ambiguous ID columns are present.
|
||||
log.info("Ambiguous match found for " + fieldName + ". Both " + columnMatch + " and " + f + " match.", new SQLWarning());
|
||||
indexMatch = i;
|
||||
}
|
||||
|
||||
return columnMatch;
|
||||
// [#4476] [#4477] [#5046] This might be unintentional from a user
|
||||
// perspective, e.g. when ambiguous ID columns are present.
|
||||
else {
|
||||
log.info("Ambiguous match found for " + fieldName + ". Both " + columnMatch + " and " + f + " match.", new SQLWarning());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.result(columnMatch, indexMatch);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -178,10 +207,14 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
|
||||
@Override
|
||||
public final Field<?> field(Name name) {
|
||||
if (name == null)
|
||||
return null;
|
||||
return field0(name, RETURN_FIELD);
|
||||
}
|
||||
|
||||
return field(DSL.field(name));
|
||||
private final <U> U field0(Name name, FieldOrIndex<U> result) {
|
||||
if (name == null)
|
||||
return result.resultNull();
|
||||
|
||||
return field0(DSL.field(name), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -263,34 +296,17 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
|
||||
@Override
|
||||
public final int indexOf(Field<?> field) {
|
||||
|
||||
// Get an exact match, or a field with a similar name
|
||||
Field<?> compareWith = field(field);
|
||||
|
||||
if (compareWith != null) {
|
||||
int size = fields.length;
|
||||
|
||||
// [#4540] Match by identity first
|
||||
for (int i = 0; i < size; i++)
|
||||
if (fields[i] == compareWith)
|
||||
return i;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
if (fields[i].equals(compareWith))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return field0(field, RETURN_INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int indexOf(String fieldName) {
|
||||
return indexOf(field(fieldName));
|
||||
return field0(fieldName, RETURN_INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int indexOf(Name fieldName) {
|
||||
return indexOf(field(fieldName));
|
||||
return field0(fieldName, RETURN_INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -397,6 +413,39 @@ final class Fields<R extends Record> extends AbstractQueryPart implements Record
|
||||
fields = result;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: [#8040] An abstraction over two possible return types.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static interface FieldOrIndex<U> {
|
||||
U result(Field<?> field, int index);
|
||||
U resultNull();
|
||||
}
|
||||
|
||||
private static final FieldOrIndex<Field<?>> RETURN_FIELD = new FieldOrIndex<Field<?>>() {
|
||||
@Override
|
||||
public Field<?> result(Field<?> field, int index) {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field<?> resultNull() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final FieldOrIndex<Integer> RETURN_INDEX = new FieldOrIndex<Integer>() {
|
||||
@Override
|
||||
public Integer result(Field<?> field, int index) {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer resultNull() {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Object API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user