提交 8efb6c8d authored 作者: Thomas Mueller's avatar Thomas Mueller

When concurrently preparing many statements with a subquery, in some cases the query didn't run.

上级 9e86397a
...@@ -427,20 +427,9 @@ public abstract class Query extends Prepared { ...@@ -427,20 +427,9 @@ public abstract class Query extends Prepared {
} }
public final long getMaxDataModificationId() { public final long getMaxDataModificationId() {
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID); ExpressionVisitor visitor = ExpressionVisitor.getMaxModificationIdVisitor();
isEverything(visitor); isEverything(visitor);
return visitor.getMaxDataModificationId(); return visitor.getMaxDataModificationId();
} }
/**
* Visit all expressions and subqueries in this query using the visitor pattern.
*
* @param expressionVisitorType the visitor type
* @return true if no component returned false
*/
public final boolean isEverything(int expressionVisitorType) {
ExpressionVisitor visitor = ExpressionVisitor.get(expressionVisitorType);
return isEverything(visitor);
}
} }
...@@ -789,8 +789,8 @@ public class Select extends Query { ...@@ -789,8 +789,8 @@ public class Select extends Query {
} }
if (isGroupQuery && groupIndex == null && havingIndex < 0 && filters.size() == 1) { if (isGroupQuery && groupIndex == null && havingIndex < 0 && filters.size() == 1) {
if (condition == null) { if (condition == null) {
ExpressionVisitor optimizable = ExpressionVisitor.get(ExpressionVisitor.OPTIMIZABLE_MIN_MAX_COUNT_ALL); Table t = filters.get(0).getTable();
optimizable.setTable((filters.get(0)).getTable()); ExpressionVisitor optimizable = ExpressionVisitor.getOptimizableVisitor(t);
isQuickAggregateQuery = isEverything(optimizable); isQuickAggregateQuery = isEverything(optimizable);
} }
} }
...@@ -1193,22 +1193,21 @@ public class Select extends Query { ...@@ -1193,22 +1193,21 @@ public class Select extends Query {
} }
default: default:
} }
visitor.incrementQueryLevel(1); ExpressionVisitor v2 = visitor.incrementQueryLevel(1);
boolean result = true; boolean result = true;
for (int i = 0, size = expressions.size(); i < size; i++) { for (int i = 0, size = expressions.size(); i < size; i++) {
Expression e = expressions.get(i); Expression e = expressions.get(i);
if (!e.isEverything(visitor)) { if (!e.isEverything(v2)) {
result = false; result = false;
break; break;
} }
} }
if (result && condition != null && !condition.isEverything(visitor)) { if (result && condition != null && !condition.isEverything(v2)) {
result = false; result = false;
} }
if (result && having != null && !having.isEverything(visitor)) { if (result && having != null && !having.isEverything(v2)) {
result = false; result = false;
} }
visitor.incrementQueryLevel(-1);
return result; return result;
} }
......
...@@ -356,14 +356,12 @@ public class Comparison extends Condition { ...@@ -356,14 +356,12 @@ public class Comparison extends Condition {
return; return;
} }
if (l == null) { if (l == null) {
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.NOT_FROM_RESOLVER); ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter);
visitor.setResolver(filter);
if (!left.isEverything(visitor)) { if (!left.isEverything(visitor)) {
return; return;
} }
} else if (r == null) { } else if (r == null) {
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.NOT_FROM_RESOLVER); ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter);
visitor.setResolver(filter);
if (!right.isEverything(visitor)) { if (!right.isEverything(visitor)) {
return; return;
} }
......
...@@ -110,8 +110,7 @@ public class ConditionIn extends Condition { ...@@ -110,8 +110,7 @@ public class ConditionIn extends Condition {
return; return;
} }
if (session.getDatabase().getSettings().optimizeInList) { if (session.getDatabase().getSettings().optimizeInList) {
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.NOT_FROM_RESOLVER); ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter);
visitor.setResolver(filter);
for (Expression e : valueList) { for (Expression e : valueList) {
if (!e.isEverything(visitor)) { if (!e.isEverything(visitor)) {
return; return;
......
...@@ -130,8 +130,7 @@ public class ConditionInSelect extends Condition { ...@@ -130,8 +130,7 @@ public class ConditionInSelect extends Condition {
if (filter != l.getTableFilter()) { if (filter != l.getTableFilter()) {
return; return;
} }
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.NOT_FROM_RESOLVER); ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter);
visitor.setResolver(filter);
if (!query.isEverything(visitor)) { if (!query.isEverything(visitor)) {
return; return;
} }
......
...@@ -128,18 +128,6 @@ public abstract class Expression { ...@@ -128,18 +128,6 @@ public abstract class Expression {
*/ */
public abstract int getCost(); public abstract int getCost();
/**
* Check if this expression and all sub-expressions can fulfill a criteria.
* This is a convenience function.
*
* @param expressionVisitorType the visitor type
* @return if the criteria can be fulfilled
*/
public final boolean isEverything(int expressionVisitorType) {
ExpressionVisitor visitor = ExpressionVisitor.get(expressionVisitorType);
return isEverything(visitor);
}
/** /**
* If it is possible, return the negated expression. This is used * If it is possible, return the negated expression. This is used
* to optimize NOT expressions: NOT ID>10 can be converted to * to optimize NOT expressions: NOT ID>10 can be converted to
......
...@@ -165,6 +165,7 @@ public class ExpressionColumn extends Expression { ...@@ -165,6 +165,7 @@ public class ExpressionColumn extends Expression {
} }
Value value = columnResolver.getValue(column); Value value = columnResolver.getValue(column);
if (value == null) { if (value == null) {
columnResolver.getValue(column);
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL()); throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
} }
return value; return value;
......
...@@ -7,10 +7,7 @@ ...@@ -7,10 +7,7 @@
package org.h2.expression; package org.h2.expression;
import java.util.HashSet; import java.util.HashSet;
import org.h2.constant.SysProperties;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.message.DbException;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
...@@ -98,15 +95,29 @@ public class ExpressionVisitor { ...@@ -98,15 +95,29 @@ public class ExpressionVisitor {
*/ */
public static final ExpressionVisitor QUERY_COMPARABLE_VISITOR = new ExpressionVisitor(QUERY_COMPARABLE); public static final ExpressionVisitor QUERY_COMPARABLE_VISITOR = new ExpressionVisitor(QUERY_COMPARABLE);
private int queryLevel; private final int type;
private Table table; private final int queryLevel;
private int type; private final HashSet<DbObject> dependencies;
private long maxDataModificationId; private final Table table;
private ColumnResolver resolver; private final long[] maxDataModificationId;
private HashSet<DbObject> dependencies; private final ColumnResolver resolver;
private ExpressionVisitor(int type, int queryLevel, HashSet<DbObject> dependencies, Table table, ColumnResolver resolver, long[] maxDataModificationId) {
this.type = type;
this.queryLevel = queryLevel;
this.dependencies = dependencies;
this.table = table;
this.resolver = resolver;
this.maxDataModificationId = maxDataModificationId;
}
private ExpressionVisitor(int type) { private ExpressionVisitor(int type) {
this.type = type; this.type = type;
this.queryLevel = 0;
this.dependencies = null;
this.table = null;
this.resolver = null;
this.maxDataModificationId = null;
} }
/** /**
...@@ -115,18 +126,22 @@ public class ExpressionVisitor { ...@@ -115,18 +126,22 @@ public class ExpressionVisitor {
* @param type the visitor type * @param type the visitor type
* @return the new visitor * @return the new visitor
*/ */
public static ExpressionVisitor get(int type) {
if (SysProperties.CHECK) {
switch (type) { public static ExpressionVisitor getDependenciesVisitor(HashSet<DbObject> dependencies) {
case INDEPENDENT: return new ExpressionVisitor(GET_DEPENDENCIES, 0, dependencies, null, null, null);
case DETERMINISTIC:
case EVALUATABLE:
case READONLY:
case QUERY_COMPARABLE:
throw DbException.throwInternalError("Singleton not used");
} }
public static ExpressionVisitor getOptimizableVisitor(Table table) {
return new ExpressionVisitor(OPTIMIZABLE_MIN_MAX_COUNT_ALL, 0, null, table, null, null);
} }
return new ExpressionVisitor(type);
public static ExpressionVisitor getNotFromResolverVisitor(ColumnResolver resolver) {
return new ExpressionVisitor(NOT_FROM_RESOLVER, 0, null, null, resolver, null);
}
public static ExpressionVisitor getMaxModificationIdVisitor() {
return new ExpressionVisitor(SET_MAX_DATA_MODIFICATION_ID, 0, null, null, null, new long[1]);
} }
/** /**
...@@ -149,23 +164,14 @@ public class ExpressionVisitor { ...@@ -149,23 +164,14 @@ public class ExpressionVisitor {
return dependencies; return dependencies;
} }
/**
* Set all dependencies.
* This is used for GET_DEPENDENCIES visitors.
*
* @param dependencies the dependency set
*/
public void setDependencies(HashSet<DbObject> dependencies) {
this.dependencies = dependencies;
}
/** /**
* Increment or decrement the query level. * Increment or decrement the query level.
* *
* @param offset 1 to increment, -1 to decrement * @param offset 1 to increment, -1 to decrement
* @return a clone of this expression visitor, with the changed query level
*/ */
public void incrementQueryLevel(int offset) { public ExpressionVisitor incrementQueryLevel(int offset) {
queryLevel += offset; return new ExpressionVisitor(type, queryLevel + offset, dependencies, table, resolver, maxDataModificationId);
} }
/** /**
...@@ -178,16 +184,6 @@ public class ExpressionVisitor { ...@@ -178,16 +184,6 @@ public class ExpressionVisitor {
return resolver; return resolver;
} }
/**
* Set the column resolver.
* This is used for NOT_FROM_RESOLVER visitors.
*
* @param resolver the column resolver
*/
public void setResolver(ColumnResolver resolver) {
this.resolver = resolver;
}
/** /**
* Update the field maxDataModificationId if this value is higher * Update the field maxDataModificationId if this value is higher
* than the current value. * than the current value.
...@@ -196,7 +192,10 @@ public class ExpressionVisitor { ...@@ -196,7 +192,10 @@ public class ExpressionVisitor {
* @param value the data modification id * @param value the data modification id
*/ */
public void addDataModificationId(long value) { public void addDataModificationId(long value) {
maxDataModificationId = Math.max(maxDataModificationId, value); long m = maxDataModificationId[0];
if (value > m) {
maxDataModificationId[0] = value;
}
} }
/** /**
...@@ -206,27 +205,13 @@ public class ExpressionVisitor { ...@@ -206,27 +205,13 @@ public class ExpressionVisitor {
* @return the maximum modification id * @return the maximum modification id
*/ */
public long getMaxDataModificationId() { public long getMaxDataModificationId() {
return maxDataModificationId; return maxDataModificationId[0];
} }
int getQueryLevel() { int getQueryLevel() {
return queryLevel; return queryLevel;
} }
void setQueryLevel(int queryLevel) {
this.queryLevel = queryLevel;
}
/**
* Set the table.
* This is used for OPTIMIZABLE_MIN_MAX_COUNT_ALL visitors.
*
* @param table the table
*/
public void setTable(Table table) {
this.table = table;
}
/** /**
* Get the table. * Get the table.
* This is used for OPTIMIZABLE_MIN_MAX_COUNT_ALL visitors. * This is used for OPTIMIZABLE_MIN_MAX_COUNT_ALL visitors.
......
...@@ -297,8 +297,7 @@ public abstract class Table extends SchemaObjectBase { ...@@ -297,8 +297,7 @@ public abstract class Table extends SchemaObjectBase {
dependencies.add(s); dependencies.add(s);
} }
} }
ExpressionVisitor visitor = ExpressionVisitor.get(ExpressionVisitor.GET_DEPENDENCIES); ExpressionVisitor visitor = ExpressionVisitor.getDependenciesVisitor(dependencies);
visitor.setDependencies(dependencies);
for (Column col : columns) { for (Column col : columns) {
col.isEverything(visitor); col.isEverything(visitor);
} }
......
...@@ -62,7 +62,11 @@ public class TestMultiConn extends TestBase implements DatabaseEventListener { ...@@ -62,7 +62,11 @@ public class TestMultiConn extends TestBase implements DatabaseEventListener {
} catch (SQLException e) { } catch (SQLException e) {
// ignore // ignore
} }
try {
t.get(); t.get();
} catch (Exception e) {
// ignore
}
} }
private void testThreeThreads() throws Exception { private void testThreeThreads() throws Exception {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论