提交 3c6ce034 authored 作者: S.Vladykin's avatar S.Vladykin

Merge branch 'viewindex' into batchview2

...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Server mode: executing "shutdown" left a thread on the server.
</li>
<li>The condition "in(select...)" did not work correctly in some cases if the subquery had an "order by". <li>The condition "in(select...)" did not work correctly in some cases if the subquery had an "order by".
</li> </li>
<li>Issue #184: The Platform-independent zip had Windows line endings in Linux scripts. <li>Issue #184: The Platform-independent zip had Windows line endings in Linux scripts.
......
...@@ -177,10 +177,9 @@ When using one of the following features for production, please ensure your use ...@@ -177,10 +177,9 @@ When using one of the following features for production, please ensure your use
is well tested (if possible with automated test cases). The areas that are not well tested are: is well tested (if possible with automated test cases). The areas that are not well tested are:
</p> </p>
<ul> <ul>
<li>Platforms other than Windows XP, Linux, Mac OS X, or JVMs other than Sun 1.6 or 1.7 <li>Platforms other than Windows, Linux, Mac OS X, or JVMs other than Oracle 1.6, 1.7, 1.8.
</li><li>The features <code>AUTO_SERVER</code> and <code>AUTO_RECONNECT</code>. </li><li>The features <code>AUTO_SERVER</code> and <code>AUTO_RECONNECT</code>.
</li><li>Cluster mode, 2-phase commit, savepoints. </li><li>Cluster mode, 2-phase commit, savepoints.
</li><li>24/7 operation.
</li><li>Fulltext search. </li><li>Fulltext search.
</li><li>Operations on LOBs over 2 GB. </li><li>Operations on LOBs over 2 GB.
</li><li>The optimizer may not always select the best plan. </li><li>The optimizer may not always select the best plan.
......
...@@ -4729,8 +4729,14 @@ public class Parser { ...@@ -4729,8 +4729,14 @@ public class Parser {
.substring(parseIndex)); .substring(parseIndex));
read("AS"); read("AS");
try { try {
Query query = parseSelect(); Query query;
query.prepare(); session.setParsingView(true);
try {
query = parseSelect();
query.prepare();
} finally {
session.setParsingView(false);
}
command.setSelect(query); command.setSelect(query);
} catch (DbException e) { } catch (DbException e) {
if (force) { if (force) {
......
...@@ -905,8 +905,8 @@ public class Select extends Query { ...@@ -905,8 +905,8 @@ public class Select extends Query {
} }
if (sort != null && !isQuickAggregateQuery && !isGroupQuery) { if (sort != null && !isQuickAggregateQuery && !isGroupQuery) {
Index index = getSortIndex(); Index index = getSortIndex();
if (index != null) { Index current = topTableFilter.getIndex();
Index current = topTableFilter.getIndex(); if (index != null && current != null) {
if (current.getIndexType().isScan() || current == index) { if (current.getIndexType().isScan() || current == index) {
topTableFilter.setIndex(index); topTableFilter.setIndex(index);
if (!topTableFilter.hasInComparisons()) { if (!topTableFilter.hasInComparisons()) {
...@@ -939,7 +939,7 @@ public class Select extends Query { ...@@ -939,7 +939,7 @@ public class Select extends Query {
getGroupByExpressionCount() > 0) { getGroupByExpressionCount() > 0) {
Index index = getGroupSortedIndex(); Index index = getGroupSortedIndex();
Index current = topTableFilter.getIndex(); Index current = topTableFilter.getIndex();
if (index != null && (current.getIndexType().isScan() || if (index != null && current != null && (current.getIndexType().isScan() ||
current == index)) { current == index)) {
topTableFilter.setIndex(index); topTableFilter.setIndex(index);
isGroupSortedQuery = true; isGroupSortedQuery = true;
......
...@@ -10,6 +10,7 @@ import java.util.HashMap; ...@@ -10,6 +10,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map;
import java.util.Random; import java.util.Random;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Command; import org.h2.command.Command;
...@@ -19,6 +20,7 @@ import org.h2.command.Prepared; ...@@ -19,6 +20,7 @@ import org.h2.command.Prepared;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.ViewIndex;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
...@@ -111,6 +113,8 @@ public class Session extends SessionWithState { ...@@ -111,6 +113,8 @@ public class Session extends SessionWithState {
private long modificationMetaID = -1; private long modificationMetaID = -1;
private SubQueryInfo subQueryInfo; private SubQueryInfo subQueryInfo;
private int parsingView; private int parsingView;
private volatile SmallLRUCache<Object, ViewIndex> viewIndexCache;
private HashMap<Object, ViewIndex> subQueryIndexCache;
/** /**
* Temporary LOBs from result sets. Those are kept for some time. The * Temporary LOBs from result sets. Those are kept for some time. The
...@@ -1313,6 +1317,22 @@ public class Session extends SessionWithState { ...@@ -1313,6 +1317,22 @@ public class Session extends SessionWithState {
} }
} }
public Map<Object, ViewIndex> getViewIndexCache(boolean subQuery) {
if (subQuery) {
// for sub-queries we don't need to use LRU because it should not grow too large
// for a single query and by the end of the statement we will drop the whole cache
if (subQueryIndexCache == null) {
subQueryIndexCache = New.hashMap();
}
return subQueryIndexCache;
}
SmallLRUCache<Object, ViewIndex> cache = viewIndexCache;
if (cache == null) {
viewIndexCache = cache = SmallLRUCache.newInstance(Constants.VIEW_INDEX_CACHE_SIZE);
}
return cache;
}
/** /**
* Remember the result set and close it as soon as the transaction is * Remember the result set and close it as soon as the transaction is
* committed (if it needs to be closed). This is done to delete temporary * committed (if it needs to be closed). This is done to delete temporary
...@@ -1490,9 +1510,14 @@ public class Session extends SessionWithState { ...@@ -1490,9 +1510,14 @@ public class Session extends SessionWithState {
*/ */
public void endStatement() { public void endStatement() {
startStatement = -1; startStatement = -1;
subQueryIndexCache = null;
closeTemporaryResults(); closeTemporaryResults();
} }
public void clearViewIndexCache() {
viewIndexCache = null;
}
@Override @Override
public void addTemporaryLob(Value v) { public void addTemporaryLob(Value v) {
if (v.getType() != Value.CLOB && v.getType() != Value.BLOB) { if (v.getType() != Value.CLOB && v.getType() != Value.BLOB) {
...@@ -1549,5 +1574,4 @@ public class Session extends SessionWithState { ...@@ -1549,5 +1574,4 @@ public class Session extends SessionWithState {
} }
} }
} }
...@@ -122,7 +122,7 @@ public class SysProperties { ...@@ -122,7 +122,7 @@ public class SysProperties {
//*/ //*/
/** /**
* System property <code>h2.check2</code> (default: true).<br /> * System property <code>h2.check2</code> (default: false).<br />
* Additional assertions in the database engine. * Additional assertions in the database engine.
*/ */
//## CHECK ## //## CHECK ##
......
...@@ -248,6 +248,7 @@ public class ViewIndex extends BaseIndex implements SpatialIndex { ...@@ -248,6 +248,7 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
private static Query prepareSubQuery(String sql, Session session, int[] masks, private static Query prepareSubQuery(String sql, Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder, boolean preliminary) { TableFilter[] filters, int filter, SortOrder sortOrder, boolean preliminary) {
assert filters != null;
Prepared p; Prepared p;
SubQueryInfo upper = session.getSubQueryInfo(); SubQueryInfo upper = session.getSubQueryInfo();
SubQueryInfo info = new SubQueryInfo(upper, SubQueryInfo info = new SubQueryInfo(upper,
......
...@@ -12,6 +12,9 @@ import java.nio.ByteBuffer; ...@@ -12,6 +12,9 @@ import java.nio.ByteBuffer;
*/ */
public class WriteBuffer { public class WriteBuffer {
/**
* The maximum size of the buffer in order to be re-used after a clear operation.
*/
private static final int MAX_REUSE_CAPACITY = 4 * 1024 * 1024; private static final int MAX_REUSE_CAPACITY = 4 * 1024 * 1024;
/** /**
...@@ -19,9 +22,24 @@ public class WriteBuffer { ...@@ -19,9 +22,24 @@ public class WriteBuffer {
*/ */
private static final int MIN_GROW = 1024 * 1024; private static final int MIN_GROW = 1024 * 1024;
private ByteBuffer reuse = ByteBuffer.allocate(MIN_GROW); /**
* The buffer that is used after a clear operation.
*/
private ByteBuffer reuse;
/**
* The current buffer (may be replaced if it is too small).
*/
private ByteBuffer buff;
private ByteBuffer buff = reuse; public WriteBuffer(int initialSize) {
reuse = ByteBuffer.allocate(initialSize);
buff = reuse;
}
public WriteBuffer() {
this(MIN_GROW);
}
/** /**
* Write a variable size integer. * Write a variable size integer.
......
...@@ -347,6 +347,7 @@ public class TcpServerThread implements Runnable { ...@@ -347,6 +347,7 @@ public class TcpServerThread implements Runnable {
int status; int status;
if (session.isClosed()) { if (session.isClosed()) {
status = SessionRemote.STATUS_CLOSED; status = SessionRemote.STATUS_CLOSED;
stop = true;
} else { } else {
status = getState(old); status = getState(old);
} }
......
...@@ -236,6 +236,11 @@ public abstract class Table extends SchemaObjectBase { ...@@ -236,6 +236,11 @@ public abstract class Table extends SchemaObjectBase {
*/ */
public abstract Index getScanIndex(Session session); public abstract Index getScanIndex(Session session);
public Index getScanIndex(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) {
return getScanIndex(session);
}
/** /**
* Get any unique index for this table if one exists. * Get any unique index for this table if one exists.
* *
......
...@@ -172,10 +172,14 @@ public class TableFilter implements ColumnResolver { ...@@ -172,10 +172,14 @@ public class TableFilter implements ColumnResolver {
*/ */
public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter) { public PlanItem getBestPlanItem(Session s, TableFilter[] filters, int filter) {
PlanItem item; PlanItem item;
SortOrder sortOrder = null;
if (select != null) {
sortOrder = select.getSortOrder();
}
if (indexConditions.size() == 0) { if (indexConditions.size() == 0) {
item = new PlanItem(); item = new PlanItem();
item.setIndex(table.getScanIndex(s)); item.setIndex(table.getScanIndex(s, null, filters, filter, sortOrder));
item.cost = item.getIndex().getCost(s, null, filters, filter, null); item.cost = item.getIndex().getCost(s, null, filters, filter, sortOrder);
} else { } else {
int len = table.getColumns().length; int len = table.getColumns().length;
int[] masks = new int[len]; int[] masks = new int[len];
...@@ -191,10 +195,6 @@ public class TableFilter implements ColumnResolver { ...@@ -191,10 +195,6 @@ public class TableFilter implements ColumnResolver {
} }
} }
} }
SortOrder sortOrder = null;
if (select != null) {
sortOrder = select.getSortOrder();
}
item = table.getBestPlanItem(s, masks, filters, filter, sortOrder); item = table.getBestPlanItem(s, masks, filters, filter, sortOrder);
item.setMasks(masks); item.setMasks(masks);
// The more index conditions, the earlier the table. // The more index conditions, the earlier the table.
...@@ -211,8 +211,9 @@ public class TableFilter implements ColumnResolver { ...@@ -211,8 +211,9 @@ public class TableFilter implements ColumnResolver {
} }
if (join != null) { if (join != null) {
setEvaluatable(join); setEvaluatable(join);
filter += nestedJoin == null ? 1 : 2; do {
assert filters[filter] == join; filter++;
} while (filters[filter] != join);
item.setJoinPlan(join.getBestPlanItem(s, filters, filter)); item.setJoinPlan(join.getBestPlanItem(s, filters, filter));
// TODO optimizer: calculate cost of a join: should use separate // TODO optimizer: calculate cost of a join: should use separate
// expected row number and lookup cost // expected row number and lookup cost
......
...@@ -8,6 +8,7 @@ package org.h2.table; ...@@ -8,6 +8,7 @@ package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
...@@ -29,10 +30,8 @@ import org.h2.result.Row; ...@@ -29,10 +30,8 @@ import org.h2.result.Row;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.SmallLRUCache;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.SynchronizedVerifier;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -51,8 +50,6 @@ public class TableView extends Table { ...@@ -51,8 +50,6 @@ public class TableView extends Table {
private ViewIndex index; private ViewIndex index;
private boolean recursive; private boolean recursive;
private DbException createException; private DbException createException;
private final SmallLRUCache<CacheKey, ViewIndex> indexCache =
SmallLRUCache.newInstance(Constants.VIEW_INDEX_CACHE_SIZE);
private long lastModificationCheck; private long lastModificationCheck;
private long maxDataModificationId; private long maxDataModificationId;
private User owner; private User owner;
...@@ -97,8 +94,6 @@ public class TableView extends Table { ...@@ -97,8 +94,6 @@ public class TableView extends Table {
this.columnNames = columnNames; this.columnNames = columnNames;
this.recursive = recursive; this.recursive = recursive;
index = new ViewIndex(this, querySQL, params, recursive); index = new ViewIndex(this, querySQL, params, recursive);
SynchronizedVerifier.check(indexCache);
indexCache.clear();
initColumnsAndTables(session); initColumnsAndTables(session);
} }
...@@ -136,8 +131,6 @@ public class TableView extends Table { ...@@ -136,8 +131,6 @@ public class TableView extends Table {
if (views != null) { if (views != null) {
views = New.arrayList(views); views = New.arrayList(views);
} }
SynchronizedVerifier.check(indexCache);
indexCache.clear();
initColumnsAndTables(session); initColumnsAndTables(session);
if (views != null) { if (views != null) {
for (TableView v : views) { for (TableView v : views) {
...@@ -234,30 +227,14 @@ public class TableView extends Table { ...@@ -234,30 +227,14 @@ public class TableView extends Table {
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder) {
PlanItem item = new PlanItem(); PlanItem item = new PlanItem();
item.cost = index.getCost(session, masks, filters, filter, sortOrder); item.cost = index.getCost(session, masks, filters, filter, sortOrder);
final CacheKey cacheKey = new CacheKey(masks, session); final CacheKey cacheKey = new CacheKey(masks, this);
Map<Object, ViewIndex> indexCache = session.getViewIndexCache(topQuery != null);
synchronized (this) { ViewIndex i = indexCache.get(cacheKey);
SynchronizedVerifier.check(indexCache); if (i == null) {
ViewIndex i2 = indexCache.get(cacheKey); i = new ViewIndex(this, index, session, masks, filters, filter, sortOrder);
if (i2 != null) { indexCache.put(cacheKey, i);
item.setIndex(i2);
return item;
}
}
// We cannot hold the lock during the ViewIndex creation or we risk ABBA
// deadlocks if the view creation calls back into H2 via something like
// a FunctionTable.
ViewIndex i2 = new ViewIndex(this, index, session, masks, filters, filter, sortOrder);
synchronized (this) {
// have to check again in case another session has beat us to it
ViewIndex i3 = indexCache.get(cacheKey);
if (i3 != null) {
item.setIndex(i3);
return item;
}
indexCache.put(cacheKey, i2);
item.setIndex(i2);
} }
item.setIndex(i);
return item; return item;
} }
...@@ -278,6 +255,10 @@ public class TableView extends Table { ...@@ -278,6 +255,10 @@ public class TableView extends Table {
return true; return true;
} }
public Query getTopQuery() {
return topQuery;
}
@Override @Override
public String getDropSQL() { public String getDropSQL() {
return "DROP VIEW IF EXISTS " + getSQL() + " CASCADE"; return "DROP VIEW IF EXISTS " + getSQL() + " CASCADE";
...@@ -418,6 +399,9 @@ public class TableView extends Table { ...@@ -418,6 +399,9 @@ public class TableView extends Table {
database.removeMeta(session, getId()); database.removeMeta(session, getId());
querySQL = null; querySQL = null;
index = null; index = null;
for (Session s : database.getSessions(true)) {
s.clearViewIndexCache();
}
invalidate(); invalidate();
} }
...@@ -435,12 +419,18 @@ public class TableView extends Table { ...@@ -435,12 +419,18 @@ public class TableView extends Table {
@Override @Override
public Index getScanIndex(Session session) { public Index getScanIndex(Session session) {
return getBestPlanItem(session, null, null, -1, null).getIndex();
}
@Override
public Index getScanIndex(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) {
if (createException != null) { if (createException != null) {
String msg = createException.getMessage(); String msg = createException.getMessage();
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, throw DbException.get(ErrorCode.VIEW_IS_INVALID_2,
createException, getSQL(), msg); createException, getSQL(), msg);
} }
PlanItem item = getBestPlanItem(session, null, null, -1, null); PlanItem item = getBestPlanItem(session, masks, filters, filter, sortOrder);
return item.getIndex(); return item.getIndex();
} }
...@@ -590,11 +580,11 @@ public class TableView extends Table { ...@@ -590,11 +580,11 @@ public class TableView extends Table {
private static final class CacheKey { private static final class CacheKey {
private final int[] masks; private final int[] masks;
private final Session session; private final TableView view;
public CacheKey(int[] masks, Session session) { public CacheKey(int[] masks, TableView view) {
this.masks = masks; this.masks = masks;
this.session = session; this.view = view;
} }
@Override @Override
...@@ -602,7 +592,7 @@ public class TableView extends Table { ...@@ -602,7 +592,7 @@ public class TableView extends Table {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + Arrays.hashCode(masks); result = prime * result + Arrays.hashCode(masks);
result = prime * result + session.hashCode(); result = prime * result + view.hashCode();
return result; return result;
} }
...@@ -618,7 +608,7 @@ public class TableView extends Table { ...@@ -618,7 +608,7 @@ public class TableView extends Table {
return false; return false;
} }
CacheKey other = (CacheKey) obj; CacheKey other = (CacheKey) obj;
if (session != other.session) { if (view != other.view) {
return false; return false;
} }
if (!Arrays.equals(masks, other.masks)) { if (!Arrays.equals(masks, other.masks)) {
......
...@@ -332,21 +332,20 @@ public class ToChar { ...@@ -332,21 +332,20 @@ public class ToChar {
private static String zeroesAfterDecimalSeparator(BigDecimal number) { private static String zeroesAfterDecimalSeparator(BigDecimal number) {
final String numberStr = number.toString(); final String numberStr = number.toString();
final int idx = numberStr.indexOf('.'); final int idx = numberStr.indexOf('.');
if (idx >= 0 ) { if (idx < 0) {
int i = idx + 1;
boolean allZeroes = true;
for (; i < numberStr.length(); i++) {
if (numberStr.charAt(i) != '0') {
allZeroes = false;
break;
}
}
final char[] zeroes = new char[allZeroes ? numberStr.length() - idx - 1: i - 1 - idx];
Arrays.fill(zeroes, '0');
return String.valueOf(zeroes);
} else {
return ""; return "";
} }
int i = idx + 1;
boolean allZeroes = true;
for (; i < numberStr.length(); i++) {
if (numberStr.charAt(i) != '0') {
allZeroes = false;
break;
}
}
final char[] zeroes = new char[allZeroes ? numberStr.length() - idx - 1: i - 1 - idx];
Arrays.fill(zeroes, '0');
return String.valueOf(zeroes);
} }
private static void addSign(StringBuilder output, int signum, private static void addSign(StringBuilder output, int signum,
......
...@@ -41,6 +41,7 @@ import org.h2.result.Row; ...@@ -41,6 +41,7 @@ import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.SubQueryInfo;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableBase; import org.h2.table.TableBase;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -350,11 +351,20 @@ public class TestTableEngines extends TestBase { ...@@ -350,11 +351,20 @@ public class TestTableEngines extends TestBase {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table SUB_QUERY_TEST(id int primary key, name varchar) ENGINE \"" + stat.execute("create table SUB_QUERY_TEST(id int primary key, name varchar) ENGINE \"" +
TreeSetIndexTableEngine.class.getName() + "\""); TreeSetIndexTableEngine.class.getName() + "\"");
stat.execute("create table t1(id int, birthday date)"); // test sub-queries
stat.executeQuery("select t1.birthday from t1, " stat.executeQuery("select * from "
+ "(select t2.id from sub_query_test t2, " + "(select t2.id from "
+ "(select t3.id from sub_query_test t3 where t3.name = '') t4 " + "(select t3.id from sub_query_test t3 where t3.name = '') t4, "
+ "where t2.id = t4.id) t5 where t1.id = t5.id"); + "sub_query_test t2 "
+ "where t2.id = t4.id) t5").next();
// test view 1
stat.execute("create view t4 as (select t3.id from sub_query_test t3 where t3.name = '')");
stat.executeQuery("select * from "
+ "(select t2.id from t4, sub_query_test t2 where t2.id = t4.id) t5").next();
// test view 2
stat.execute("create view t5 as "
+ "(select t2.id from t4, sub_query_test t2 where t2.id = t4.id)");
stat.executeQuery("select * from t5").next();
deleteDb("testSubQueryInfo"); deleteDb("testSubQueryInfo");
} }
...@@ -477,7 +487,13 @@ public class TestTableEngines extends TestBase { ...@@ -477,7 +487,13 @@ public class TestTableEngines extends TestBase {
} }
} }
} }
private static void assert0(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
private static void setBatchSize(ArrayList<TreeSetTable> tables, int... batchSizes) { private static void setBatchSize(ArrayList<TreeSetTable> tables, int... batchSizes) {
for (int i = 0; i < batchSizes.length; i++) { for (int i = 0; i < batchSizes.length; i++) {
int batchSize = batchSizes[i]; int batchSize = batchSizes[i];
...@@ -1224,13 +1240,26 @@ public class TestTableEngines extends TestBase { ...@@ -1224,13 +1240,26 @@ public class TestTableEngines extends TestBase {
return new IteratorCursor(subSet.iterator()); return new IteratorCursor(subSet.iterator());
} }
private void checkInfo(SubQueryInfo info) {
if (info.getUpper() == null) {
// check 1st level info
assert0(info.getFilters().length == 1, "getFilters().length " + info.getFilters().length);
String alias = info.getFilters()[info.getFilter()].getTableAlias();
assert0("T5".equals(alias), "alias: " + alias);
} else {
// check 2nd level info
assert0(info.getFilters().length == 2, "getFilters().length " + info.getFilters().length);
String alias = info.getFilters()[info.getFilter()].getTableAlias();
assert0("T4".equals(alias), "alias: " + alias);
checkInfo(info.getUpper());
}
}
@Override @Override
public double getCost(Session session, int[] masks, public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder) {
if (getTable().getName().equals("SUB_QUERY_TEST")) { if (getTable().getName().equals("SUB_QUERY_TEST")) {
if (session.getSubQueryInfo() == null) { checkInfo(session.getSubQueryInfo());
throw new IllegalStateException("No qubquery info found.");
}
} }
return getCostRangeIndex(masks, set.size(), filters, filter, sortOrder); return getCostRangeIndex(masks, set.size(), filters, filter, sortOrder);
} }
......
...@@ -1805,8 +1805,8 @@ explain select * from (select dir_num, count(*) as cnt from multi_pages t, b_ho ...@@ -1805,8 +1805,8 @@ explain select * from (select dir_num, count(*) as cnt from multi_pages t, b_ho
where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc; where cnt < 1000 order by dir_num asc;
> PLAN > PLAN
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT X.DIR_NUM, X.CNT FROM ( SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /* PUBLIC.MULTI_PAGES.tableScan */ INNER JOIN PUBLIC.B_HOLDING BH /* PUBLIC.PRIMARY_KEY_3: ID = T.BH_ID */ ON 1=1 WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM ) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES.tableScan ++/ INNER JOIN PUBLIC.B_HOLDING BH /++ PUBLIC.PRIMARY_KEY_3: ID = T.BH_ID ++/ ON 1=1 WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= ?1: CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1 > SELECT X.DIR_NUM, X.CNT FROM ( SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T INNER JOIN PUBLIC.B_HOLDING BH ON 1=1 WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM ) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES.tableScan ++/ INNER JOIN PUBLIC.B_HOLDING BH /++ PUBLIC.PRIMARY_KEY_3: ID = T.BH_ID ++/ ON 1=1 WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= ?1: CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1
> rows (ordered): 1 > rows (ordered): 1
select dir_num, count(*) as cnt from multi_pages t, b_holding bh select dir_num, count(*) as cnt from multi_pages t, b_holding bh
...@@ -6892,9 +6892,9 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2; ...@@ -6892,9 +6892,9 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2;
SELECT TABLE_NAME, SQL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW'; SELECT TABLE_NAME, SQL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW';
> TABLE_NAME SQL > TABLE_NAME SQL
> ---------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > ---------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> TEST_ALL CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AS AID, A.NAME AS A_NAME, B.ID AS BID, B.NAME AS B_NAME FROM PUBLIC.TEST_A A /* PUBLIC.TEST_A.tableScan */ INNER JOIN PUBLIC.TEST_B B /* PUBLIC.PRIMARY_KEY_93: ID = A.ID */ ON 1=1 WHERE A.ID = B.ID > TEST_ALL CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AS AID, A.NAME AS A_NAME, B.ID AS BID, B.NAME AS B_NAME FROM PUBLIC.TEST_A A INNER JOIN PUBLIC.TEST_B B ON 1=1 WHERE A.ID = B.ID
> TEST_A_SUB CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT TEST_A.ID, TEST_A.NAME FROM PUBLIC.TEST_A /* PUBLIC.PRIMARY_KEY_9: ID < 2 */ WHERE ID < 2 > TEST_A_SUB CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT TEST_A.ID, TEST_A.NAME FROM PUBLIC.TEST_A WHERE ID < 2
> rows: 2 > rows: 2
SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL; SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL;
......
...@@ -203,8 +203,8 @@ public class BinaryArithmeticStream { ...@@ -203,8 +203,8 @@ public class BinaryArithmeticStream {
Node n = tree; Node n = tree;
for (int i = bitCount; i >= 0; i--) { for (int i = bitCount; i >= 0; i--) {
boolean goRight = ((code >> i) & 1) == 1; boolean goRight = ((code >> i) & 1) == 1;
int prob = MAX_PROBABILITY * int prob = (int) ((long) MAX_PROBABILITY *
n.right.frequency / n.frequency; n.right.frequency / n.frequency);
out.writeBit(goRight, prob); out.writeBit(goRight, prob);
n = goRight ? n.right : n.left; n = goRight ? n.right : n.left;
} }
...@@ -219,8 +219,8 @@ public class BinaryArithmeticStream { ...@@ -219,8 +219,8 @@ public class BinaryArithmeticStream {
public int read(In in) throws IOException { public int read(In in) throws IOException {
Node n = tree; Node n = tree;
while (n.left != null) { while (n.left != null) {
int prob = MAX_PROBABILITY * int prob = (int) ((long) MAX_PROBABILITY *
n.right.frequency / n.frequency; n.right.frequency / n.frequency);
boolean goRight = in.readBit(prob); boolean goRight = in.readBit(prob);
n = goRight ? n.right : n.left; n = goRight ? n.right : n.left;
} }
......
...@@ -245,6 +245,17 @@ public class BitStream { ...@@ -245,6 +245,17 @@ public class BitStream {
return n.value; return n.value;
} }
/**
* Get the number of bits of the Huffman code for this value.
*
* @param value the value
* @return the number of bits
*/
public int getBitCount(int value) {
int code = codes[value];
return 30 - Integer.numberOfLeadingZeros(code);
}
} }
/** /**
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论