提交 eed6fa58 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 c12cf0a7
......@@ -109,6 +109,7 @@ import org.h2.expression.ValueExpression;
import org.h2.expression.Wildcard;
import org.h2.index.Index;
import org.h2.message.Message;
import org.h2.result.SortOrder;
import org.h2.schema.Schema;
import org.h2.schema.Sequence;
import org.h2.schema.TriggerObject;
......@@ -137,6 +138,9 @@ import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
/**
* The parser is used to convert a SQL statement string to an command object.
*/
public class Parser {
// used during the tokenizer phase
......@@ -677,10 +681,19 @@ public class Parser {
column.columnName = readColumnIdentifier();
columns.add(column);
if (readIf("ASC")) {
// ignore
// ignore
} else if (readIf("DESC")) {
column.sortType = SortOrder.DESCENDING;
}
if (readIf("NULLS")) {
if (readIf("FIRST")) {
column.sortType |= SortOrder.NULLS_FIRST;
} else {
read("LAST");
column.sortType |= SortOrder.NULLS_LAST;
}
} else {
readIf("DESC");
column.descending = true;
}
} while (readIf(","));
read(")");
......
......@@ -15,6 +15,9 @@ import org.h2.table.PlanItem;
import org.h2.table.TableFilter;
import org.h2.util.Permutations;
/**
* The optimizer is responsible to find the best execution plan for a given query.
*/
public class Optimizer {
private static final int MAX_BRUTE_FORCE_FILTERS = 7;
......
......@@ -22,6 +22,7 @@ import org.h2.result.LocalResult;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.IndexColumn;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.ObjectArray;
......@@ -32,6 +33,8 @@ import org.h2.value.ValueArray;
import org.h2.value.ValueNull;
/**
* This class represents a simple SELECT statement.
*
* visibleColumnCount <= distinctColumnCount <= expressionCount
* Sortable count could include ORDER BY expressions that are not in the select list
* Expression count could include GROUP BY expressions
......@@ -60,6 +63,7 @@ public class Select extends Query {
private double cost;
private boolean isQuickQuery;
private boolean isPrepared, checkInit;
private boolean sortUsingIndex;
private SortOrder sort;
public Select(Session session) {
......@@ -190,16 +194,18 @@ public class Select extends Query {
}
}
/**
* Get the index that matches the ORDER BY list, if one exists.
* This is to avoid running a separate ORDER BY if an index can be used.
* This is specially important for large result sets, if only the first few rows are important
* (LIMIT is used)
*
* @return the index if one is found
*/
private Index getSortIndex() throws SQLException {
if (sort == null) {
return null;
}
int[] sortTypes = sort.getSortTypes();
for (int i = 0; i < sortTypes.length; i++) {
if ((sortTypes[i] & (SortOrder.DESCENDING | SortOrder.NULLS_LAST)) != 0) {
return null;
}
}
int[] indexes = sort.getIndexes();
ObjectArray sortColumns = new ObjectArray();
for (int i = 0; i < indexes.length; i++) {
......@@ -223,6 +229,7 @@ public class Select extends Query {
}
Column[] sortCols = new Column[sortColumns.size()];
sortColumns.toArray(sortCols);
int[] sortTypes = sort.getSortTypes();
if (sortCols.length == 0) {
// sort just on constants - can use scan index
return topTableFilter.getTable().getScanIndex(session);
......@@ -237,15 +244,22 @@ public class Select extends Query {
if (index.getIndexType().isHash()) {
continue;
}
Column[] indexCols = index.getColumns();
IndexColumn[] indexCols = index.getIndexColumns();
if (indexCols.length < sortCols.length) {
continue;
}
boolean ok = true;
for (int j = 0; j < sortCols.length; j++) {
// the index and the sort order must start with the exact same
// columns
if (indexCols[j] != sortCols[j]) {
// the index and the sort order must start
// with the exact same columns
IndexColumn idxCol = indexCols[j];
Column sortCol = sortCols[j];
if (idxCol.column != sortCol) {
ok = false;
break;
}
if (idxCol.sortType != sortTypes[j]) {
// TODO NULL FIRST for ascending and NULLS LAST for descending would actually match the default
ok = false;
break;
}
......@@ -274,7 +288,7 @@ public class Select extends Query {
}
result.addRow(row);
rowNumber++;
if (sort == null && limitRows != 0 && result.getRowCount() >= limitRows) {
if ((sort == null || sortUsingIndex) && limitRows != 0 && result.getRowCount() >= limitRows) {
break;
}
if (sampleSize > 0 && rowNumber >= sampleSize) {
......@@ -311,7 +325,9 @@ public class Select extends Query {
}
int columnCount = expressions.size();
LocalResult result = new LocalResult(session, expressions, visibleColumnCount);
result.setSortOrder(sort);
if (!sortUsingIndex) {
result.setSortOrder(sort);
}
if (distinct) {
result.setDistinct();
}
......@@ -489,7 +505,7 @@ public class Select extends Query {
Index current = topTableFilter.getIndex();
if (index != null && (current.getIndexType().isScan() || current == index)) {
topTableFilter.setIndex(index);
sort = null;
sortUsingIndex = true;
}
}
}
......
......@@ -64,6 +64,9 @@ import org.h2.constant.SysProperties;
*
* @author Thomas
*/
/**
* Constants are fixed values that are used in the whole database code.
*/
public class Constants {
public static final int BUILD_ID = 60;
......@@ -82,9 +85,6 @@ public class Constants {
return VERSION_MAJOR + "." + VERSION_MINOR + "." + BUILD_ID + " (" + BUILD + ")";
}
public static final int NULL_SORT_LOW = 1, NULL_SORT_HIGH = 2;
public static final int NULL_SORT_START = 3, NULL_SORT_END = 4;
public static final int NULL_SORT_DEFAULT = NULL_SORT_LOW;
public static final int DEFAULT_SERVER_PORT = 9092; // this is also in the docs
public static final String START_URL = "jdbc:h2:";
public static final String URL_FORMAT = START_URL + "{ {.|mem:}[name] | [file:]fileName | {tcp|ssl}:[//]server[:port][,server2[:port]]/name }[;key=value...]";
......
......@@ -59,10 +59,11 @@ import org.h2.value.Value;
import org.h2.value.ValueInt;
/**
* There is one database object per open database.
*
* @author Thomas
* @since 2004-04-15 22:49
*/
/*
* MetaData format: int id int headPos (for indexes) int objectType String sql
*/
......
......@@ -6,6 +6,9 @@ package org.h2.engine;
import java.lang.ref.WeakReference;
/**
* This class is reponsible to close a database if the application did not close a connection.
*/
public class DatabaseCloser extends Thread {
private final boolean shutdownHook;
......@@ -52,14 +55,15 @@ public class DatabaseCloser extends Thread {
return;
}
}
Database database = null;
synchronized (this) {
if (databaseRef != null) {
Database database = (Database) databaseRef.get();
if (database != null) {
database.close(shutdownHook);
}
database = (Database) databaseRef.get();
}
}
if (database != null) {
database.close(shutdownHook);
}
}
}
......@@ -161,6 +161,10 @@ public class Aggregate extends Expression {
case MAX:
boolean first = type == MIN;
Index index = getColumnIndex(first);
int sortType = index.getIndexColumns()[0].sortType;
if ((sortType & SortOrder.DESCENDING) != 0) {
first = !first;
}
SearchRow row = index.findFirstOrLast(session, first);
Value v;
if (row == null) {
......
......@@ -19,7 +19,7 @@ import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull;
/**
* @author Thomas
* Example comparison expressions are ID=1, NAME=NAME, NAME IS NULL.
*/
public class Comparison extends Condition {
......
......@@ -15,7 +15,7 @@ import org.h2.value.Value;
/**
* @author Thomas
* An expression is a operation, a value, or a function in a query.
*/
public abstract class Expression {
......
......@@ -22,9 +22,6 @@ import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
/**
* @author Thomas
*/
public class ExpressionColumn extends Expression {
private Database database;
private String schemaName;
......
......@@ -14,6 +14,7 @@ import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.schema.SchemaObjectBase;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
......@@ -23,7 +24,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* @author Thomas
* Most index implementations extend the base index.
*/
public abstract class BaseIndex extends SchemaObjectBase implements Index {
......@@ -90,7 +91,7 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
public abstract void truncate(Session session) throws SQLException;
public abstract boolean canGetFirstOrLast(boolean first);
public abstract boolean canGetFirstOrLast();
public abstract SearchRow findFirstOrLast(Session session, boolean first) throws SQLException;
......@@ -144,14 +145,14 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
}
public int compareRows(SearchRow rowData, SearchRow compare) throws SQLException {
for (int i = 0; i < columns.length; i++) {
for (int i = 0; i < indexColumns.length; i++) {
int index = columnIds[i];
Value v = compare.getValue(index);
if (v == null) {
// can't compare further
return 0;
}
int c = compareValues(rowData.getValue(index), v);
int c = compareValues(rowData.getValue(index), v, indexColumns[i].sortType);
if (c != 0) {
return c;
}
......@@ -179,17 +180,19 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
return k1 > k2 ? 1 : -1;
}
private int compareValues(Value v1, Value v2) throws SQLException {
if (v1 == null) {
if (v2 == null) {
private int compareValues(Value a, Value b, int sortType) throws SQLException {
boolean aNull = a == null, bNull = b == null;
if (aNull || bNull) {
if (aNull == bNull) {
return 0;
}
return 1;
return SortOrder.compareNull(aNull, bNull, sortType);
}
if (v2 == null) {
return -1;
int comp = database.compareTypeSave(a, b);
if ((sortType & SortOrder.DESCENDING) != 0) {
comp = -comp;
}
return database.compareTypeSave(v1, v2);
return comp;
}
public int getColumnIndex(Column col) {
......
......@@ -25,7 +25,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* @author Thomas
* This is the most common type of index, a b tree index.
*/
public class BtreeIndex extends BaseIndex implements RecordReader {
......@@ -284,7 +284,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
return lastChange;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return true;
}
......
......@@ -65,7 +65,7 @@ public class FunctionIndex extends BaseIndex {
throw Message.getUnsupportedException();
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -142,7 +142,7 @@ public class HashIndex extends BaseIndex {
return true;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -36,7 +36,7 @@ public interface Index extends SchemaObject {
void truncate(Session session) throws SQLException;
boolean canGetFirstOrLast(boolean first);
boolean canGetFirstOrLast();
SearchRow findFirstOrLast(Session session, boolean first) throws SQLException;
......
......@@ -15,9 +15,9 @@ import org.h2.message.Message;
import org.h2.table.Column;
import org.h2.value.Value;
/**
* @author Thomas
* A index condition object is made for each condition that can potentially use an index.
* This class does not extend expression, but in general there is one expression that maps to each index condition.
*/
public class IndexCondition {
public static final int EQUALITY = 1, START = 2, END = 4, RANGE = START | END, ALWAYS_FALSE = 8;
......
......@@ -532,7 +532,7 @@ public class LinearHashIndex extends BaseIndex implements RecordReader {
return bucketSize;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -157,7 +157,7 @@ public class LinkedIndex extends BaseIndex {
return false;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -82,7 +82,7 @@ public class MetaIndex extends BaseIndex {
return null;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -120,9 +120,6 @@ public class MultiVersionCursor implements Cursor {
return true;
}
}
int test;
this.index.debug("error", session, deltaRow);
System.exit(1);
throw Message.getInternalError();
}
int compare = index.compareRows(deltaRow, baseRow);
......
......@@ -33,8 +33,6 @@ public class MultiVersionIndex implements Index {
}
public void add(Session session, Row row) throws SQLException {
int test;
debug("add", session, row);
synchronized (sync) {
base.add(session, row);
if (removeIfExists(session, row)) {
......@@ -53,8 +51,6 @@ debug("add", session, row);
}
public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException {
int test;
debug("find", session, first);
synchronized (sync) {
Cursor baseCursor = base.find(session, first, last);
Cursor deltaCursor = delta.find(session, first, last);
......@@ -62,7 +58,7 @@ debug("find", session, first);
}
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
// TODO in many cases possible, but more complicated
return false;
}
......@@ -80,26 +76,19 @@ debug("find", session, first);
}
private boolean removeIfExists(Session session, Row row) throws SQLException {
int test;
debug("removeIfExists ", session, row);
// maybe it was inserted by the same session just before
Cursor c = delta.find(session, row, row);
while (c.next()) {
Row r = c.get();
if (r.getPos() == row.getPos()) {
debug(" >remove", session, null);
delta.remove(session, row);
debug(" >return true", session, null);
return true;
}
}
debug(" >return false", session, null);
return false;
}
public void remove(Session session, Row row) throws SQLException {
int test;
debug("remove", session, row);
synchronized (sync) {
base.remove(session, row);
if (removeIfExists(session, row)) {
......@@ -117,8 +106,6 @@ debug("remove", session, row);
}
public void truncate(Session session) throws SQLException {
int test;
debug("truncate", session, null);
synchronized (sync) {
delta.truncate(session);
base.truncate(session);
......@@ -126,8 +113,6 @@ debug("truncate", session, null);
}
public void commit(int operation, Row row) throws SQLException {
int test;
debug("commit", null, row);
synchronized (sync) {
removeIfExists(null, row);
}
......@@ -273,7 +258,7 @@ debug("commit", null, row);
}
void debug(String s, Session session, SearchRow row) throws SQLException {
// System.out.println(this + " " + s + " sess:" + (session == null ? -1: session.getId()) + " " + (row == null ? "" : row.getValue(0).getString()));
// System.out.println(this + " " + s + " sess:" + (session == null ? -1: session.getId()) + " " + (row == null ? "" : row.getValue(0).getString()));
}
}
......@@ -66,7 +66,7 @@ public class RangeIndex extends BaseIndex {
throw Message.getUnsupportedException();
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return true;
}
......
......@@ -253,7 +253,7 @@ public class ScanIndex extends BaseIndex {
return false;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -341,7 +341,7 @@ public class TreeIndex extends BaseIndex {
return true;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return true;
}
......
......@@ -21,6 +21,11 @@ import org.h2.util.ObjectArray;
import org.h2.util.SmallLRUCache;
import org.h2.value.Value;
/**
* This object represents a virtual index for a query.
* Actually it only represents a prepared statement that is
* a SELECT statement.
*/
public class ViewIndex extends BaseIndex {
private String querySQL;
......@@ -233,7 +238,7 @@ public class ViewIndex extends BaseIndex {
return false;
}
public boolean canGetFirstOrLast(boolean first) {
public boolean canGetFirstOrLast() {
return false;
}
......
......@@ -420,41 +420,41 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
/**
* Checks is NULL values are sorted high (bigger than any non-null values).
*
* @return true or false
* @return false
*/
public boolean nullsAreSortedHigh() {
debugCodeCall("nullsAreSortedHigh");
return Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_HIGH;
return false;
}
/**
* Checks is NULL values are sorted low (smaller than any non-null values).
*
* @return true or false
* @return true
*/
public boolean nullsAreSortedLow() {
debugCodeCall("nullsAreSortedLow");
return Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_LOW;
return true;
}
/**
* Checks is NULL values are sorted at the beginning (no matter if ASC or DESC is used).
*
* @return true or false
* @return false
*/
public boolean nullsAreSortedAtStart() {
debugCodeCall("nullsAreSortedAtStart");
return Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_START;
return false;
}
/**
* Checks is NULL values are sorted at the end (no matter if ASC or DESC is used).
*
* @return true or false
* @return false
*/
public boolean nullsAreSortedAtEnd() {
debugCodeCall("nullsAreSortedAtEnd");
return Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_END;
return false;
}
/**
......
......@@ -6,7 +6,6 @@ package org.h2.result;
import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.expression.Expression;
import org.h2.util.ObjectArray;
......@@ -15,10 +14,10 @@ import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* @author Thomas
* A sort order represents an ORDER BY clause in a query.
*/
public class SortOrder {
public static final int ASCENDING = 0, DESCENDING = 1;
public static final int NULLS_FIRST = 2, NULLS_LAST = 4;
......@@ -60,39 +59,33 @@ public class SortOrder {
}
return buff.toString();
}
public static int compareNull(boolean aNull, boolean bNull, int type) {
if ((type & NULLS_FIRST) != 0) {
return aNull ? -1 : 1;
} else if ((type & NULLS_LAST) != 0) {
return aNull ? 1 : -1;
} else {
// see also JdbcDatabaseMetaData.nullsAreSorted*
int comp = aNull ? -1 : 1;
return (type & DESCENDING) == 0 ? comp : -comp;
}
}
public int compare(Value[] a, Value[] b) throws SQLException {
for (int i = 0; i < len; i++) {
int idx = indexes[i];
int type = sortTypes[i];
Value o1 = a[idx];
Value o2 = b[idx];
boolean b1 = o1 == ValueNull.INSTANCE, b2 = o2 == ValueNull.INSTANCE;
if (b1 || b2) {
if (b1 == b2) {
Value ao = a[idx];
Value bo = b[idx];
boolean aNull = ao == ValueNull.INSTANCE, bNull = bo == ValueNull.INSTANCE;
if (aNull || bNull) {
if (aNull == bNull) {
continue;
}
if ((type & NULLS_FIRST) != 0) {
return b1 ? -1 : 1;
} else if ((type & NULLS_LAST) != 0) {
return b1 ? 1 : -1;
} else {
// this depends on NULL_SORT_DEFAULT
int comp;
if (Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_LOW) {
comp = b1 ? -1 : 1;
return (type & DESCENDING) == 0 ? comp : -comp;
} else if (Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_HIGH) {
comp = b1 ? 1 : -1;
return (type & DESCENDING) == 0 ? comp : -comp;
} else if (Constants.NULL_SORT_DEFAULT == Constants.NULL_SORT_START) {
return b1 ? 1 : -1;
} else {
return b1 ? -1 : 1;
}
}
return compareNull(aNull, bNull, type);
}
int comp = database.compare(o1, o2);
int comp = database.compare(ao, bo);
if (comp != 0) {
return (type & DESCENDING) == 0 ? comp : -comp;
}
......
......@@ -33,7 +33,7 @@ import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;
/**
* @author Thomas
* This class represents a column in a table.
*/
public class Column {
private final int type;
......
......@@ -9,6 +9,10 @@ import java.sql.SQLException;
import org.h2.command.dml.Select;
import org.h2.value.Value;
/**
* A column resolver is list of column (for example, a table) that can map a
* column name to an actual column.
*/
public interface ColumnResolver {
String getTableAlias();
......
......@@ -6,16 +6,27 @@ package org.h2.table;
import java.sql.SQLException;
import org.h2.result.SortOrder;
/**
* This represents a column item of an index. This is required because some
* indexes support descending sorted columns.
*/
public class IndexColumn {
public String columnName;
public Column column;
public boolean descending;
public int sortType = SortOrder.ASCENDING;
public String getSQL() {
StringBuffer buff = new StringBuffer(column.getSQL());
if (descending) {
if ((sortType & SortOrder.DESCENDING) != 0) {
buff.append(" DESC");
}
if ((sortType & SortOrder.NULLS_FIRST) != 0) {
buff.append(" NULLS FIRST");
} else if ((sortType & SortOrder.NULLS_LAST) != 0) {
buff.append(" NULLS LAST");
}
return buff.toString();
}
......
......@@ -22,6 +22,7 @@ import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SimpleRow;
import org.h2.result.SimpleRowValue;
import org.h2.result.SortOrder;
import org.h2.schema.Schema;
import org.h2.schema.SchemaObjectBase;
import org.h2.schema.Sequence;
......@@ -32,9 +33,8 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* @author Thomas
* A table contains a list of columns and a list of rows.
*/
public abstract class Table extends SchemaObjectBase {
public static final int TYPE_CACHED = 0, TYPE_MEMORY = 1;
......@@ -489,7 +489,12 @@ public abstract class Table extends SchemaObjectBase {
ObjectArray indexes = getIndexes();
for (int i = 1; indexes != null && i < indexes.size(); i++) {
Index index = (Index) indexes.get(i);
if (index.canGetFirstOrLast(first)) {
if (index.canGetFirstOrLast()) {
IndexColumn idxCol = index.getIndexColumns()[0];
if ((idxCol.sortType & SortOrder.DESCENDING) != 0 && (idxCol.sortType & SortOrder.NULLS_FIRST) == 0) {
// for descending sorted columns, if the NULLs are at the end, it does not work for some index types
continue;
}
int idx = index.getColumnIndex(column);
if (idx == 0) {
return index;
......
......@@ -20,13 +20,16 @@ import org.h2.index.IndexCondition;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueInt;
/**
* @author Thomas
* A table filter represents a table that is used in a query. There is one such object whenever a table
* (or view) is used in a query. For example the following query has 2 table filters:
* SELECT * FROM TEST T1, TEST T2.
*/
public class TableFilter implements ColumnResolver {
private static final int BEFORE_FIRST = 0, FOUND = 1, AFTER_LAST = 2, NULL_ROW = 3;
......@@ -35,6 +38,7 @@ public class TableFilter implements ColumnResolver {
private final Select select;
private Session session;
private Index index;
private IndexColumn[] indexColumns;
private Cursor cursor;
private int scanCount;
private boolean used; // used in the plan
......@@ -134,7 +138,7 @@ public class TableFilter implements ColumnResolver {
}
public void setPlanItem(PlanItem item) {
this.index = item.getIndex();
setIndex(item.getIndex());
for (int i = 0; joins != null && i < joins.size(); i++) {
TableFilter join = getTableFilter(i);
if (item.getJoinPlan() != null) {
......@@ -204,17 +208,24 @@ public class TableFilter implements ColumnResolver {
int type = column.getType();
int id = column.getColumnId();
Value v = condition.getCurrentValue(session).convertTo(type);
if (condition.isStart()) {
// TODO index: start.setExpression(id,
// bigger(start.getValue(id), e));
boolean isStart = condition.isStart(), isEnd = condition.isEnd();
IndexColumn idxCol = indexColumns[id];
if (idxCol != null && (idxCol.sortType & SortOrder.DESCENDING) != 0) {
// if the index column is sorted the other way, we swap end and start
// NULLS_FIRST / NULLS_LAST is not a problem, as nulls never match anyway
boolean temp = isStart;
isStart = isEnd;
isEnd = temp;
}
if (isStart) {
// TODO index: start.setExpression(id, bigger(start.getValue(id), e));
if (start == null) {
start = table.getTemplateRow();
}
start.setValue(id, v);
}
if (condition.isEnd()) {
// TODO index: end.setExpression(id,
// smaller(end.getExpression(id), e));
if (isEnd) {
// TODO index: end.setExpression(id, smaller(end.getExpression(id), e));
if (end == null) {
end = table.getTemplateRow();
}
......@@ -459,6 +470,17 @@ public class TableFilter implements ColumnResolver {
public void setIndex(Index index) {
this.index = index;
Column[] columns = table.getColumns();
indexColumns = new IndexColumn[columns.length];
IndexColumn[] idxCols = index.getIndexColumns();
if (idxCols != null) {
for (int i = 0; i < columns.length; i++) {
int idx = index.getColumnIndex(columns[i]);
if (idx >= 0) {
indexColumns[i] = idxCols[idx];
}
}
}
}
public void setUsed(boolean used) {
......
......@@ -7,7 +7,6 @@ package org.h2.test;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.constant.SysProperties;
import org.h2.server.TcpServer;
import org.h2.test.db.TestAutoRecompile;
import org.h2.test.db.TestBackup;
......@@ -142,10 +141,12 @@ java org.h2.test.TestAll timer
/*
----
A file is sent although the Japanese translation has not been completed yet.
----
reverse index
Code coverage
At startup, when corrupted, say if LOG=0 was used before
......
......@@ -41,6 +41,7 @@ public class TestCluster extends TestBase {
prep.setString(2, "Data" + i);
prep.executeUpdate();
}
check(conn, len);
conn.close();
CreateCluster.main(new String[] { "-urlSource", "jdbc:h2:file:" + baseDir + "/node1/test", "-urlTarget",
......
CREATE TABLE TEST(ID INT);
INSERT INTO TEST VALUES(1), (2), (3);
create index idxdesc on test(id desc);
select * from test where id between 0 and 1;
> 1;
select * from test where id between 3 and 4;
> 3;
drop table test;
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255));
INSERT INTO TEST VALUES(1, 'Hello'), (2, 'HelloWorld'), (3, 'HelloWorldWorld');
SELECT COUNT(*) FROM TEST WHERE NAME REGEXP 'World';
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论