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