提交 877c03fb authored 作者: Sergi Vladykin's avatar Sergi Vladykin

Merge branch 'master' of https://github.com/h2database/h2database into lazyQuery

......@@ -872,7 +872,7 @@ public class Select extends Query {
Column column = ((ExpressionColumn) expr).getColumn();
int selectivity = column.getSelectivity();
Index columnIndex = topTableFilter.getTable().
getIndexForColumn(column);
getIndexForColumn(column, false, true);
if (columnIndex != null &&
selectivity != Constants.SELECTIVITY_DEFAULT &&
selectivity < 20) {
......
......@@ -287,7 +287,7 @@ public class Aggregate extends Expression {
case MIN:
case MAX:
boolean first = type == MIN;
Index index = getColumnIndex();
Index index = getMinMaxColumnIndex();
int sortType = index.getIndexColumns()[0].sortType;
if ((sortType & SortOrder.DESCENDING) != 0) {
first = !first;
......@@ -575,14 +575,14 @@ public class Aggregate extends Expression {
return text + StringUtils.enclose(on.getSQL());
}
private Index getColumnIndex() {
private Index getMinMaxColumnIndex() {
if (on instanceof ExpressionColumn) {
ExpressionColumn col = (ExpressionColumn) on;
Column column = col.getColumn();
TableFilter filter = col.getTableFilter();
if (filter != null) {
Table table = filter.getTable();
Index index = table.getIndexForColumn(column);
Index index = table.getIndexForColumn(column, true, false);
return index;
}
}
......@@ -602,7 +602,7 @@ public class Aggregate extends Expression {
return visitor.getTable().canGetRowCount();
case MIN:
case MAX:
Index index = getColumnIndex();
Index index = getMinMaxColumnIndex();
return index != null;
default:
return false;
......
......@@ -377,6 +377,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return column.equals(columns[0]);
}
/**
* Get the list of columns as a string.
*
......
......@@ -190,6 +190,14 @@ public interface Index extends SchemaObject {
*/
int getColumnIndex(Column col);
/**
* Check if the given column is the first for this index
*
* @param column the column
* @return true if the given columns is the first
*/
boolean isFirstColumn(Column column);
/**
* Get the indexed columns as index columns (with ordering information).
*
......
......@@ -82,6 +82,14 @@ public class MetaIndex extends BaseIndex {
return super.getColumnIndex(col);
}
@Override
public boolean isFirstColumn(Column column) {
if (scan) {
return false;
}
return super.isFirstColumn(column);
}
@Override
public void checkRename() {
throw DbException.getUnsupportedException("META");
......
......@@ -230,6 +230,11 @@ public class MultiVersionIndex implements Index {
return base.getColumnIndex(col);
}
@Override
public boolean isFirstColumn(Column column) {
return base.isFirstColumn(column);
}
@Override
public Column[] getColumns() {
return base.getColumns();
......
......@@ -464,6 +464,11 @@ public class PageDataIndex extends PageIndex {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return false;
}
@Override
public void close(Session session) {
if (trace.isDebugEnabled()) {
......
......@@ -96,6 +96,11 @@ public class PageDelegateIndex extends PageIndex {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return getColumnIndex(column) == 0;
}
@Override
public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder,
......
......@@ -222,6 +222,11 @@ public class ScanIndex extends BaseIndex {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return false;
}
@Override
public void checkRename() {
throw DbException.getUnsupportedException("SCAN");
......
......@@ -88,6 +88,11 @@ public class MVDelegateIndex extends BaseIndex implements MVIndex {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return getColumnIndex(column) == 0;
}
@Override
public double getCost(Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder,
......
......@@ -242,6 +242,11 @@ public class MVPrimaryIndex extends BaseIndex {
return -1;
}
@Override
public boolean isFirstColumn(Column column) {
return false;
}
@Override
public void remove(Session session) {
TransactionMap<Value, Value> map = getMap(session);
......
......@@ -1050,22 +1050,34 @@ public abstract class Table extends SchemaObjectBase {
* This method returns null if no matching index is found.
*
* @param column the column
* @param needGetFirstOrLast if the returned index must be able
* to do {@link Index#canGetFirstOrLast()}
* @param needFindNext if the returned index must be able to do
* {@link Index#findNext(Session, SearchRow, SearchRow)}
* @return the index or null
*/
public Index getIndexForColumn(Column column) {
public Index getIndexForColumn(Column column,
boolean needGetFirstOrLast, boolean needFindNext) {
ArrayList<Index> indexes = getIndexes();
Index result = null;
if (indexes != null) {
for (int i = 1, size = indexes.size(); i < size; i++) {
Index index = indexes.get(i);
if (index.canGetFirstOrLast()) {
int idx = index.getColumnIndex(column);
if (idx == 0) {
return index;
}
if (needGetFirstOrLast && !index.canGetFirstOrLast()) {
continue;
}
if (needFindNext && !index.canFindNext()) {
continue;
}
// choose the minimal covering index with the needed first column
// to work consistently with execution plan from Optimizer
if (index.isFirstColumn(column) && (result == null ||
result.getColumns().length > index.getColumns().length)) {
result = index;
}
}
}
return null;
return result;
}
public boolean getOnCommitDrop() {
......
......@@ -18,6 +18,8 @@ import java.sql.Statement;
*/
public class TestIndexHints extends TestBase {
private Connection conn;
/**
* Run just this test.
*
......@@ -39,11 +41,12 @@ public class TestIndexHints extends TestBase {
testPlanSqlHasIndexesInCorrectOrder();
testWithTableAlias();
testWithTableAliasCalledUse();
conn.close();
deleteDb("indexhints");
}
private void createDb() throws SQLException {
Connection conn = getConnection("indexhints");
conn = getConnection("indexhints");
Statement stat = conn.createStatement();
stat.execute("create table test (x int, y int)");
stat.execute("create index idx1 on test (x)");
......@@ -52,7 +55,6 @@ public class TestIndexHints extends TestBase {
}
private void testQuotedIdentifier() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("explain analyze select * " +
"from test use index(\"Idx3\") where x=1 and y=1");
......@@ -66,54 +68,44 @@ public class TestIndexHints extends TestBase {
plan = rs.getString(1);
assertTrue(plan.contains("/* PUBLIC.\"Idx3\":"));
assertTrue(plan.contains("USE INDEX (\"Idx3\")"));
conn.close();
}
private void testWithSingleIndexName() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("explain analyze select * " +
"from test use index(idx1) where x=1 and y=1");
rs.next();
String result = rs.getString(1);
assertTrue(result.contains("/* PUBLIC.IDX1:"));
conn.close();
}
private void testWithTableAlias() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("explain analyze select * " +
"from test t use index(idx2) where x=1 and y=1");
rs.next();
String result = rs.getString(1);
assertTrue(result.contains("/* PUBLIC.IDX2:"));
conn.close();
}
private void testWithTableAliasCalledUse() throws SQLException {
// make sure that while adding new syntax for table hints, code
// that uses "USE" as a table alias still works
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
stat.executeQuery("explain analyze select * " +
"from test use where use.x=1 and use.y=1");
conn.close();
}
private void testWithMultipleIndexNames() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("explain analyze select * " +
"from test use index(idx1, idx2) where x=1 and y=1");
rs.next();
String result = rs.getString(1);
assertTrue(result.contains("/* PUBLIC.IDX2:"));
conn.close();
}
private void testPlanSqlHasIndexesInCorrectOrder() throws SQLException {
Connection conn = getConnection("indexhints");
ResultSet rs = conn.createStatement().executeQuery("explain analyze select * " +
"from test use index(idx1, idx2) where x=1 and y=1");
rs.next();
......@@ -123,23 +115,18 @@ public class TestIndexHints extends TestBase {
"from test use index(idx2, idx1) where x=1 and y=1");
rs2.next();
assertTrue(rs2.getString(1).contains("USE INDEX (IDX2, IDX1)"));
conn.close();
}
private void testWithEmptyIndexHintsList() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("explain analyze select * " +
"from test use index () where x=1 and y=1");
rs.next();
String result = rs.getString(1);
assertTrue(result.contains("/* PUBLIC.TEST.tableScan"));
conn.close();
}
private void testWithInvalidIndexName() throws SQLException {
Connection conn = getConnection("indexhints");
Statement stat = conn.createStatement();
try {
stat.executeQuery("explain analyze select * " +
......@@ -148,8 +135,6 @@ public class TestIndexHints extends TestBase {
+ "Index \"IDX_DOESNT_EXIST\" not found");
} catch (SQLException e) {
assertEquals(ErrorCode.INDEX_NOT_FOUND_1, e.getErrorCode());
} finally {
conn.close();
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论