[jOOQ/jOOQ#11143] ParserWithMetaLookups reports ambiguous column in correlated subquery, when there is none
This commit is contained in:
parent
f02fa963ba
commit
005f0ef426
@ -561,6 +561,7 @@ import org.jooq.conf.RenderQuotedNames;
|
||||
import org.jooq.conf.Settings;
|
||||
import org.jooq.conf.SettingsTools;
|
||||
import org.jooq.impl.JSONNull.JSONNullType;
|
||||
import org.jooq.impl.ScopeStack.Value;
|
||||
import org.jooq.impl.XMLParse.DocumentOrContent;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.tools.reflect.Reflect;
|
||||
@ -12527,7 +12528,7 @@ final class ParserContext {
|
||||
List<FieldProxy<?>> retain = new ArrayList<>();
|
||||
|
||||
for (FieldProxy<?> lookup : lookupFields) {
|
||||
Field<?> found = null;
|
||||
Value<Field<?>> found = null;
|
||||
|
||||
for (Field<?> f : fieldScope) {
|
||||
if (f.getName().equals(lookup.getName())) {
|
||||
@ -12536,13 +12537,14 @@ final class ParserContext {
|
||||
throw exception("Ambiguous field identifier");
|
||||
}
|
||||
|
||||
found = f;
|
||||
// TODO: Does this instance of "found" really interact with the one below?
|
||||
found = new Value<>(0, f);
|
||||
}
|
||||
}
|
||||
|
||||
found = resolveInTableScope(tableScope, lookup.getQualifiedName(), lookup, found);
|
||||
found = resolveInTableScope(tableScope.valueIterable(), lookup.getQualifiedName(), lookup, found);
|
||||
if (found != null)
|
||||
lookup.delegate((AbstractField) found);
|
||||
lookup.delegate((AbstractField) found.value);
|
||||
else
|
||||
retain.add(lookup);
|
||||
}
|
||||
@ -12559,14 +12561,20 @@ final class ParserContext {
|
||||
unknownField(r);
|
||||
}
|
||||
|
||||
private final Field<?> resolveInTableScope(Iterable<Table<?>> tables, Name lookupName, FieldProxy<?> lookup, Field<?> found) {
|
||||
private final Value<Field<?>> resolveInTableScope(Iterable<Value<Table<?>>> tables, Name lookupName, FieldProxy<?> lookup, Value<Field<?>> found) {
|
||||
|
||||
tableScopeLoop:
|
||||
for (Table<?> t : tables) {
|
||||
Field<?> f;
|
||||
for (Value<Table<?>> t : tables) {
|
||||
Value<Field<?>> f;
|
||||
|
||||
if (t instanceof JoinTable) {
|
||||
found = resolveInTableScope(Arrays.asList(((JoinTable) t).lhs, ((JoinTable) t).rhs), lookupName, lookup, found);
|
||||
if (t.value instanceof JoinTable) {
|
||||
found = resolveInTableScope(
|
||||
Arrays.asList(
|
||||
new Value<>(t.scopeLevel, ((JoinTable) t.value).lhs),
|
||||
new Value<>(t.scopeLevel, ((JoinTable) t.value).rhs)
|
||||
),
|
||||
lookupName, lookup, found
|
||||
);
|
||||
}
|
||||
else if (lookupName.qualified()) {
|
||||
|
||||
@ -12576,17 +12584,18 @@ final class ParserContext {
|
||||
// - Test fully qualified column names vs partially qualified column names
|
||||
Name q = lookupName.qualifier();
|
||||
boolean x = q.qualified();
|
||||
if (x && q.equals(t.getQualifiedName()) || !x && q.last().equals(t.getName()))
|
||||
if ((found = t.field(lookup.getName())) != null)
|
||||
if (x && q.equals(t.value.getQualifiedName()) || !x && q.last().equals(t.value.getName()))
|
||||
if ((found = Value.of(t.scopeLevel, t.value.field(lookup.getName()))) != null)
|
||||
break tableScopeLoop;
|
||||
}
|
||||
else if ((f = t.field(lookup.getName())) != null) {
|
||||
if (found != null) {
|
||||
else if ((f = Value.of(t.scopeLevel, t.value.field(lookup.getName()))) != null) {
|
||||
if (found == null || found.scopeLevel < f.scopeLevel) {
|
||||
found = f;
|
||||
}
|
||||
else {
|
||||
position(lookup.position());
|
||||
throw exception("Ambiguous field identifier");
|
||||
}
|
||||
|
||||
found = f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -94,45 +94,91 @@ final class ScopeStack<K, V> implements Iterable<V> {
|
||||
return !iterator().hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterator<V> iterator() {
|
||||
return new Iterator<V>() {
|
||||
Iterator<List<V>> it = stack().values().iterator();
|
||||
V next;
|
||||
|
||||
final Iterable<Value<V>> valueIterable() {
|
||||
return new Iterable<Value<V>>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return move() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V next() {
|
||||
if (next == null) {
|
||||
return move();
|
||||
}
|
||||
else {
|
||||
V result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private V move() {
|
||||
List<V> list;
|
||||
while (it.hasNext())
|
||||
if (!(list = it.next()).isEmpty() && (next = list.get(list.size() - 1)) != null)
|
||||
break;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
public Iterator<Value<V>> iterator() {
|
||||
return new ScopeStackIterator<Value<V>>(new F.F1<List<V>, Value<V>>() {
|
||||
@Override
|
||||
public Value<V> apply(List<V> list) {
|
||||
return Value.lastOf(list);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Iterator<V> iterator() {
|
||||
return new ScopeStackIterator<>(new F.F1<List<V>, V>() {
|
||||
@Override
|
||||
public V apply(List<V> list) {
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static final class Value<V> {
|
||||
final int scopeLevel;
|
||||
final V value;
|
||||
|
||||
Value(int scopeLevel, V value) {
|
||||
this.scopeLevel = scopeLevel;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
static <V> Value<V> of(int scopeLevel, V value) {
|
||||
return value == null ? null : new Value<>(scopeLevel, value);
|
||||
}
|
||||
|
||||
static <V> Value<V> lastOf(List<V> list) {
|
||||
int size = list.size();
|
||||
V value = list.get(size - 1);
|
||||
return of(size - 1, value);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ScopeStackIterator<U> implements Iterator<U> {
|
||||
final Iterator<List<V>> it = stack().values().iterator();
|
||||
final F.F1<List<V>, U> valueExtractor;
|
||||
U next;
|
||||
|
||||
ScopeStackIterator(F.F1<List<V>, U> valueExtractor) {
|
||||
this.valueExtractor = valueExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return move() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public U next() {
|
||||
if (next == null) {
|
||||
return move();
|
||||
}
|
||||
else {
|
||||
U result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private U move() {
|
||||
List<V> list;
|
||||
while (it.hasNext())
|
||||
if (!(list = it.next()).isEmpty() && ((next = valueExtractor.apply(list)) != null))
|
||||
break;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
}
|
||||
|
||||
final void setAll(V value) {
|
||||
for (K key : stack().keySet())
|
||||
set(key, value);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user