提交 769aafc5 authored 作者: Thomas Mueller's avatar Thomas Mueller

Issue 304: The condition [NOT] IN (SELECT ...) could throw the exception…

Issue 304: The condition [NOT] IN (SELECT ...) could throw the exception "Unexpected code path" if the subquery contained ORDER BY.
上级 46c1e5e6
...@@ -18,7 +18,8 @@ Change Log ...@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>ALTER TABLE ALTER ADD / REMOVE /ALTER COLUMN dropped some dependent objects <ul><li>Issue 304: The condition [NOT] IN (SELECT ...) could throw the exception "Unexpected code path" if the subquery contained ORDER BY.
</li><li>ALTER TABLE ALTER ADD / REMOVE /ALTER COLUMN dropped some dependent objects
(access rights, triggers) of views that depend on the modified table. (access rights, triggers) of views that depend on the modified table.
</li><li>CREATE OR REPLACE VIEW dropped some dependent objects (access rights, triggers) </li><li>CREATE OR REPLACE VIEW dropped some dependent objects (access rights, triggers)
if the view already existed before. if the view already existed before.
......
...@@ -51,6 +51,16 @@ public abstract class Query extends Prepared { ...@@ -51,6 +51,16 @@ public abstract class Query extends Prepared {
*/ */
protected int sampleSize; protected int sampleSize;
/**
* Whether the result must only contain distinct rows.
*/
protected boolean distinct;
/**
* Whether the result needs to support random access.
*/
protected boolean randomAccessResult;
private int lastLimit; private int lastLimit;
private long lastEvaluated; private long lastEvaluated;
private LocalResult lastResult; private LocalResult lastResult;
...@@ -161,13 +171,6 @@ public abstract class Query extends Prepared { ...@@ -161,13 +171,6 @@ public abstract class Query extends Prepared {
*/ */
public abstract void addGlobalCondition(Parameter param, int columnId, int comparisonType); public abstract void addGlobalCondition(Parameter param, int columnId, int comparisonType);
/**
* Set the distinct flag.
*
* @param b the new value
*/
public abstract void setDistinct(boolean b);
/** /**
* Check if this expression and all sub-expressions can fulfill a criteria. * Check if this expression and all sub-expressions can fulfill a criteria.
* If any part returns false, the result is false. * If any part returns false, the result is false.
...@@ -189,6 +192,24 @@ public abstract class Query extends Prepared { ...@@ -189,6 +192,24 @@ public abstract class Query extends Prepared {
*/ */
public abstract void fireBeforeSelectTriggers(); public abstract void fireBeforeSelectTriggers();
/**
* Set the distinct flag.
*
* @param b the new value
*/
public void setDistinct(boolean b) {
distinct = b;
}
/**
* Whether results need to support random access.
*
* @param b the new value
*/
public void setRandomAccessResult(boolean b) {
randomAccessResult = b;
}
public boolean isQuery() { public boolean isQuery() {
return true; return true;
} }
......
...@@ -72,7 +72,6 @@ public class Select extends Query { ...@@ -72,7 +72,6 @@ public class Select extends Query {
private ArrayList<Expression> group; private ArrayList<Expression> group;
private int[] groupIndex; private int[] groupIndex;
private boolean[] groupByExpression; private boolean[] groupByExpression;
private boolean distinct;
private HashMap<Expression, Object> currentGroup; private HashMap<Expression, Object> currentGroup;
private int havingIndex; private int havingIndex;
private boolean isGroupQuery, isGroupSortedQuery; private boolean isGroupQuery, isGroupSortedQuery;
...@@ -575,6 +574,10 @@ public class Select extends Query { ...@@ -575,6 +574,10 @@ public class Select extends Query {
result = createLocalResult(result); result = createLocalResult(result);
result.setDistinct(); result.setDistinct();
} }
if (randomAccessResult) {
result = createLocalResult(result);
result.setRandomAccess();
}
if (isGroupQuery && !isGroupSortedQuery) { if (isGroupQuery && !isGroupSortedQuery) {
result = createLocalResult(result); result = createLocalResult(result);
} }
...@@ -1068,10 +1071,6 @@ public class Select extends Query { ...@@ -1068,10 +1071,6 @@ public class Select extends Query {
return buff.toString(); return buff.toString();
} }
public void setDistinct(boolean b) {
distinct = b;
}
public void setHaving(Expression having) { public void setHaving(Expression having) {
this.having = having; this.having = having;
} }
......
...@@ -63,7 +63,6 @@ public class SelectUnion extends Query { ...@@ -63,7 +63,6 @@ public class SelectUnion extends Query {
private Expression[] expressionArray; private Expression[] expressionArray;
private ArrayList<SelectOrderBy> orderList; private ArrayList<SelectOrderBy> orderList;
private SortOrder sort; private SortOrder sort;
private boolean distinct;
private boolean isPrepared, checkInit; private boolean isPrepared, checkInit;
private boolean isForUpdate; private boolean isForUpdate;
...@@ -157,6 +156,9 @@ public class SelectUnion extends Query { ...@@ -157,6 +156,9 @@ public class SelectUnion extends Query {
right.setDistinct(true); right.setDistinct(true);
result.setDistinct(); result.setDistinct();
} }
if (randomAccessResult) {
result.setRandomAccess();
}
switch (unionType) { switch (unionType) {
case UNION: case UNION:
case EXCEPT: case EXCEPT:
...@@ -200,6 +202,7 @@ public class SelectUnion extends Query { ...@@ -200,6 +202,7 @@ public class SelectUnion extends Query {
case INTERSECT: { case INTERSECT: {
LocalResult temp = new LocalResult(session, expressionArray, columnCount); LocalResult temp = new LocalResult(session, expressionArray, columnCount);
temp.setDistinct(); temp.setDistinct();
temp.setRandomAccess();
while (l.next()) { while (l.next()) {
temp.addRow(convert(l.currentRow(), columnCount)); temp.addRow(convert(l.currentRow(), columnCount));
} }
...@@ -301,10 +304,6 @@ public class SelectUnion extends Query { ...@@ -301,10 +304,6 @@ public class SelectUnion extends Query {
return set; return set;
} }
public void setDistinct(boolean b) {
distinct = b;
}
public ArrayList<Expression> getExpressions() { public ArrayList<Expression> getExpressions() {
return expressions; return expressions;
} }
......
...@@ -119,6 +119,7 @@ public class ConditionInSelect extends Condition { ...@@ -119,6 +119,7 @@ public class ConditionInSelect extends Condition {
public Expression optimize(Session session) { public Expression optimize(Session session) {
left = left.optimize(session); left = left.optimize(session);
query.setDistinct(true); query.setDistinct(true);
query.setRandomAccessResult(true);
query.prepare(); query.prepare();
if (query.getColumnCount() != 1) { if (query.getColumnCount() != 1) {
throw DbException.get(ErrorCode.SUBQUERY_IS_NOT_SINGLE_COLUMN); throw DbException.get(ErrorCode.SUBQUERY_IS_NOT_SINGLE_COLUMN);
......
...@@ -41,6 +41,7 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -41,6 +41,7 @@ public class LocalResult implements ResultInterface, ResultTarget {
private ResultExternal external; private ResultExternal external;
private int diskOffset; private int diskOffset;
private boolean distinct; private boolean distinct;
private boolean randomAccess;
private boolean closed; private boolean closed;
/** /**
...@@ -127,6 +128,7 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -127,6 +128,7 @@ public class LocalResult implements ResultInterface, ResultTarget {
copy.sort = this.sort; copy.sort = this.sort;
copy.distinctRows = this.distinctRows; copy.distinctRows = this.distinctRows;
copy.distinct = distinct; copy.distinct = distinct;
copy.randomAccess = randomAccess;
copy.currentRow = null; copy.currentRow = null;
copy.offset = 0; copy.offset = 0;
copy.limit = -1; copy.limit = -1;
...@@ -152,6 +154,13 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -152,6 +154,13 @@ public class LocalResult implements ResultInterface, ResultTarget {
distinctRows = ValueHashMap.newInstance(); distinctRows = ValueHashMap.newInstance();
} }
/**
* Random access is required (containsDistinct).
*/
public void setRandomAccess() {
this.randomAccess = true;
}
/** /**
* Remove the row from the result set if it exists. * Remove the row from the result set if it exists.
* *
...@@ -249,7 +258,11 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -249,7 +258,11 @@ public class LocalResult implements ResultInterface, ResultTarget {
rowCount++; rowCount++;
if (rows.size() > maxMemoryRows && session.getDatabase().isPersistent()) { if (rows.size() > maxMemoryRows && session.getDatabase().isPersistent()) {
if (external == null) { if (external == null) {
external = new ResultDiskBuffer(session, sort, values.length); if (randomAccess) {
external = new ResultTempTable(session, sort);
} else {
external = new ResultDiskBuffer(session, sort, values.length);
}
} }
addRowsToDisk(); addRowsToDisk();
} }
...@@ -285,7 +298,11 @@ public class LocalResult implements ResultInterface, ResultTarget { ...@@ -285,7 +298,11 @@ public class LocalResult implements ResultInterface, ResultTarget {
break; break;
} }
if (external == null) { if (external == null) {
external = new ResultDiskBuffer(session, sort, list.length); if (randomAccess) {
external = new ResultTempTable(session, sort);
} else {
external = new ResultDiskBuffer(session, sort, list.length);
}
} }
rows.add(list); rows.add(list);
if (rows.size() > maxMemoryRows) { if (rows.size() > maxMemoryRows) {
......
...@@ -544,16 +544,14 @@ public abstract class Table extends SchemaObjectBase { ...@@ -544,16 +544,14 @@ public abstract class Table extends SchemaObjectBase {
return new SimpleRow(new Value[columns.length]); return new SimpleRow(new Value[columns.length]);
} }
Row getNullRow() { synchronized Row getNullRow() {
synchronized (this) { if (nullRow == null) {
if (nullRow == null) { nullRow = new Row(new Value[columns.length], 1);
nullRow = new Row(new Value[columns.length], 1); for (int i = 0; i < columns.length; i++) {
for (int i = 0; i < columns.length; i++) { nullRow.setValue(i, ValueNull.INSTANCE);
nullRow.setValue(i, ValueNull.INSTANCE);
}
} }
return nullRow;
} }
return nullRow;
} }
public Column[] getColumns() { public Column[] getColumns() {
......
...@@ -36,6 +36,7 @@ public class TestCases extends TestBase { ...@@ -36,6 +36,7 @@ public class TestCases extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testMaxMemoryRowsDistinct();
testDeleteTop(); testDeleteTop();
testUnicode(); testUnicode();
testOuterJoin(); testOuterJoin();
...@@ -88,6 +89,18 @@ public class TestCases extends TestBase { ...@@ -88,6 +89,18 @@ public class TestCases extends TestBase {
deleteDb("cases"); deleteDb("cases");
} }
private void testMaxMemoryRowsDistinct() throws SQLException {
deleteDb("cases");
Connection conn = getConnection("cases;max_memory_rows_distinct=1");
Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key)");
stat.execute("insert into test values(1), (2)");
stat.execute("select * from dual where x not in (select id from test order by id)");
stat.execute("select * from dual where x not in (select id from test union select id from test)");
stat.execute("(select id from test order by id) intersect (select id from test order by id)");
conn.close();
}
private void testUnicode() throws SQLException { private void testUnicode() throws SQLException {
deleteDb("cases"); deleteDb("cases");
Connection conn = getConnection("cases"); Connection conn = getConnection("cases");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论