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

--no commit message

--no commit message
上级 8bce218b
...@@ -1255,12 +1255,12 @@ a lot of data in a database), one sometimes wants to shrink the size of the data ...@@ -1255,12 +1255,12 @@ a lot of data in a database), one sometimes wants to shrink the size of the data
(compact a database). Here is a sample function to do this: (compact a database). Here is a sample function to do this:
<pre> <pre>
public static void compact(String dir, String dbName, public static void compact(String dir, String dbName,
String user, String password) throws Exception String user, String password) throws Exception {
String url = "jdbc:h2:" + dbName; String url = "jdbc:h2:" + dir + "/" + dbName;
String script = "test.sql"; String file = "data/test.sql";
Backup.execute(url, user, password, script); Script.execute(url, user, password, file);
DeleteDbFiles.execute(dir, dbName); DeleteDbFiles.execute(dir, dbName, true);
RunScript.execute(url, user, password, script); RunScript.execute(url, user, password, file, null, false);
} }
</pre> </pre>
See also the sample application org.h2.samples.Compact. See also the sample application org.h2.samples.Compact.
......
...@@ -36,6 +36,18 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -36,6 +36,18 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / 2007-TODO</h3><ul>
<li>Optimization for WHERE NOT(...) and WHERE [NOT] booleanFlagColumn.
This can be disabled using the system property h2.optimizeNot.
</li><li>Optimization for conditions like WHERE A=B AND B=X (A=X is added). This often appears in joins.
This can be disabled using the system property h2.optimizeTwoEquals.
</li><li>Documentation: the source code in 'Compacting a Database' was incorrect. Fixed.
</li><li>In the H2 Console, result sets could not be modified because the default result set type is now forward only.
For H2, now uses scrollable result sets. Also for other databases, but only when the query starts with @EDIT.
</li><li>Views using UNION did not work correctly. Fixed.
</li><li>Function tables did not work with views and EXPLAIN. Fixed.
</li></ul>
<h3>Version 1.0 / 2007-07-12 (Build 55)</h3><ul> <h3>Version 1.0 / 2007-07-12 (Build 55)</h3><ul>
<li>Support for the system property baseDir. This works for embedded databases as well. The setting is supported <li>Support for the system property baseDir. This works for embedded databases as well. The setting is supported
by the H2 Console using -Dh2.baseDir or -baseDir by the H2 Console using -Dh2.baseDir or -baseDir
......
...@@ -94,7 +94,7 @@ public class Delete extends Prepared { ...@@ -94,7 +94,7 @@ public class Delete extends Prepared {
if (condition != null) { if (condition != null) {
condition.mapColumns(tableFilter, 0); condition.mapColumns(tableFilter, 0);
condition = condition.optimize(session); condition = condition.optimize(session);
condition = condition.createIndexConditions(tableFilter); condition.createIndexConditions(tableFilter);
} }
PlanItem item = tableFilter.getBestPlanItem(session); PlanItem item = tableFilter.getBestPlanItem(session);
tableFilter.setPlanItem(item); tableFilter.setPlanItem(item);
......
...@@ -18,7 +18,6 @@ import org.h2.store.UndoLogRecord; ...@@ -18,7 +18,6 @@ import org.h2.store.UndoLogRecord;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -148,7 +147,7 @@ public class Insert extends Prepared { ...@@ -148,7 +147,7 @@ public class Insert extends Prepared {
if(e == null) { if(e == null) {
buff.append("DEFAULT"); buff.append("DEFAULT");
} else { } else {
buff.append(StringUtils.unEnclose(e.getSQL())); buff.append(e.getSQL());
} }
} }
buff.append(')'); buff.append(')');
......
...@@ -20,7 +20,6 @@ import org.h2.store.UndoLogRecord; ...@@ -20,7 +20,6 @@ import org.h2.store.UndoLogRecord;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
...@@ -213,7 +212,7 @@ public class Merge extends Prepared { ...@@ -213,7 +212,7 @@ public class Merge extends Prepared {
if(e == null) { if(e == null) {
buff.append("DEFAULT"); buff.append("DEFAULT");
} else { } else {
buff.append(StringUtils.unEnclose(e.getSQL())); buff.append(e.getSQL());
} }
} }
buff.append(')'); buff.append(')');
......
...@@ -476,7 +476,7 @@ public class Select extends Query { ...@@ -476,7 +476,7 @@ public class Select extends Query {
condition = condition.optimize(session); condition = condition.optimize(session);
for (int j = 0; j < filters.size(); j++) { for (int j = 0; j < filters.size(); j++) {
TableFilter f = (TableFilter) filters.get(j); TableFilter f = (TableFilter) filters.get(j);
condition = condition.createIndexConditions(f); condition.createIndexConditions(f);
} }
} }
if(condition == null && isGroupQuery && groupIndex == null && havingIndex<0 && filters.size()==1) { if(condition == null && isGroupQuery && groupIndex == null && havingIndex<0 && filters.size()==1) {
...@@ -564,7 +564,7 @@ public class Select extends Query { ...@@ -564,7 +564,7 @@ public class Select extends Query {
buff.append(", "); buff.append(", ");
} }
Expression expr = exprList[i]; Expression expr = exprList[i];
buff.append(StringUtils.unEnclose(expr.getSQL())); buff.append(expr.getSQL());
} }
buff.append("\nFROM "); buff.append("\nFROM ");
TableFilter filter = topTableFilter; TableFilter filter = topTableFilter;
...@@ -716,7 +716,6 @@ public class Select extends Query { ...@@ -716,7 +716,6 @@ public class Select extends Query {
} }
} }
public boolean isEverything(ExpressionVisitor visitor) { public boolean isEverything(ExpressionVisitor visitor) {
if(visitor.type == ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID) { if(visitor.type == ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID) {
for(int i=0; i<filters.size(); i++) { for(int i=0; i<filters.size(); i++) {
......
...@@ -131,7 +131,7 @@ public class Update extends Prepared { ...@@ -131,7 +131,7 @@ public class Update extends Prepared {
Column column = table.getColumn(i); Column column = table.getColumn(i);
buff.append(column.getName()); buff.append(column.getName());
buff.append(" = "); buff.append(" = ");
buff.append(StringUtils.unEnclose(newExpr.getSQL())); buff.append(newExpr.getSQL());
} }
} }
if(condition != null) { if(condition != null) {
...@@ -144,7 +144,7 @@ public class Update extends Prepared { ...@@ -144,7 +144,7 @@ public class Update extends Prepared {
if (condition != null) { if (condition != null) {
condition.mapColumns(tableFilter, 0); condition.mapColumns(tableFilter, 0);
condition = condition.optimize(session); condition = condition.optimize(session);
condition = condition.createIndexConditions(tableFilter); condition.createIndexConditions(tableFilter);
} }
for (int i = 0; i < expressions.length; i++) { for (int i = 0; i < expressions.length; i++) {
Expression expr = expressions[i]; Expression expr = expressions[i];
......
...@@ -251,6 +251,8 @@ public class Constants { ...@@ -251,6 +251,8 @@ public class Constants {
public static final int CACHE_SIZE_INDEX_DEFAULT = CACHE_SIZE_DEFAULT >> CACHE_SIZE_INDEX_SHIFT; public static final int CACHE_SIZE_INDEX_DEFAULT = CACHE_SIZE_DEFAULT >> CACHE_SIZE_INDEX_SHIFT;
public static String BASE_DIR = getStringSetting("h2.baseDir", null); public static String BASE_DIR = getStringSetting("h2.baseDir", null);
public static final int DEFAULT_MAX_MEMORY_UNDO = getIntSetting("h2.defaultMaxMemoryUndo", Integer.MAX_VALUE); public static final int DEFAULT_MAX_MEMORY_UNDO = getIntSetting("h2.defaultMaxMemoryUndo", Integer.MAX_VALUE);
public static final boolean OPTIMIZE_NOT = getBooleanSetting("h2.optimizeNot", true);
public static final boolean OPTIMIZE_2_EQUALS = getBooleanSetting("h2.optimizeTwoEquals", true);
public static void setBaseDir(String dir) { public static void setBaseDir(String dir) {
if(!dir.endsWith("/")) { if(!dir.endsWith("/")) {
......
...@@ -1499,4 +1499,8 @@ public class Database implements DataHandler { ...@@ -1499,4 +1499,8 @@ public class Database implements DataHandler {
return lobSyncObject; return lobSyncObject;
} }
public int getSessionCount() {
return sessions.size();
}
} }
...@@ -61,6 +61,8 @@ public class Session implements SessionInterface { ...@@ -61,6 +61,8 @@ public class Session implements SessionInterface {
private HashSet unlinkSet; private HashSet unlinkSet;
private int tempViewIndex; private int tempViewIndex;
private HashMap procedures; private HashMap procedures;
private static int nextSerialId;
private int serialId = nextSerialId++;
public Session() { public Session() {
} }
...@@ -514,4 +516,8 @@ public class Session implements SessionInterface { ...@@ -514,4 +516,8 @@ public class Session implements SessionInterface {
return schemaSearchPath; return schemaSearchPath;
} }
public int hashCode() {
return serialId;
}
} }
...@@ -103,14 +103,14 @@ public class CompareLike extends Condition { ...@@ -103,14 +103,14 @@ public class CompareLike extends Condition {
return esc; return esc;
} }
public Expression createIndexConditions(TableFilter filter) throws SQLException { public void createIndexConditions(TableFilter filter) throws SQLException {
Session session = filter.getSession(); Session session = filter.getSession();
if(!(left instanceof ExpressionColumn)) { if(!(left instanceof ExpressionColumn)) {
return this; return;
} }
ExpressionColumn l = (ExpressionColumn)left; ExpressionColumn l = (ExpressionColumn)left;
if(filter != l.getTableFilter()) { if(filter != l.getTableFilter()) {
return this; return;
} }
// parameters are always evaluatable, but // parameters are always evaluatable, but
// we need to check the actual value now // we need to check the actual value now
...@@ -119,10 +119,10 @@ public class CompareLike extends Condition { ...@@ -119,10 +119,10 @@ public class CompareLike extends Condition {
// which is maybe slower (but maybe not in this case!) // which is maybe slower (but maybe not in this case!)
// TODO optimizer: like: check what other databases do! // TODO optimizer: like: check what other databases do!
if(!right.isConstant()) { if(!right.isConstant()) {
return this; return;
} }
if(escape != null && !escape.isConstant()) { if(escape != null && !escape.isConstant()) {
return this; return;
} }
String p = right.getValue(session).getString(); String p = right.getValue(session).getString();
Value e = escape == null ? null : escape.getValue(session); Value e = escape == null ? null : escape.getValue(session);
...@@ -133,12 +133,12 @@ public class CompareLike extends Condition { ...@@ -133,12 +133,12 @@ public class CompareLike extends Condition {
initPattern(p, getEscapeChar(e)); initPattern(p, getEscapeChar(e));
if(patternLength <= 0 || types[0] != MATCH) { if(patternLength <= 0 || types[0] != MATCH) {
// can't use an index // can't use an index
return this; return;
} }
int dataType = l.getColumn().getType(); int dataType = l.getColumn().getType();
if(dataType != Value.STRING && dataType != Value.STRING_IGNORECASE && dataType != Value.STRING_FIXED) { if(dataType != Value.STRING && dataType != Value.STRING_IGNORECASE && dataType != Value.STRING_FIXED) {
// column is not a varchar - can't use the index // column is not a varchar - can't use the index
return this; return;
} }
int maxMatch = 0; int maxMatch = 0;
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
...@@ -146,26 +146,24 @@ public class CompareLike extends Condition { ...@@ -146,26 +146,24 @@ public class CompareLike extends Condition {
buff.append(pattern[maxMatch++]); buff.append(pattern[maxMatch++]);
} }
String begin = buff.toString(); String begin = buff.toString();
Expression condition = this;
if(maxMatch == patternLength) { if(maxMatch == patternLength) {
condition = filter.addIndexCondition(condition, new IndexCondition(Comparison.EQUAL, l, ValueExpression.get(ValueString.get(begin)))); filter.addIndexCondition(new IndexCondition(Comparison.EQUAL, l, ValueExpression.get(ValueString.get(begin))));
} else { } else {
// TODO check if this is correct according to Unicode rules (code points) // TODO check if this is correct according to Unicode rules (code points)
String end; String end;
if(begin.length()>0) { if(begin.length()>0) {
condition = filter.addIndexCondition(condition, new IndexCondition(Comparison.BIGGER_EQUAL, l, ValueExpression.get(ValueString.get(begin)))); filter.addIndexCondition(new IndexCondition(Comparison.BIGGER_EQUAL, l, ValueExpression.get(ValueString.get(begin))));
char next = begin.charAt(begin.length()-1); char next = begin.charAt(begin.length()-1);
// search the 'next' unicode character (or at least a character that is higher) // search the 'next' unicode character (or at least a character that is higher)
for(int i=1; i<2000; i++) { for(int i=1; i<2000; i++) {
end = begin.substring(0, begin.length()-1) + (char)(next+i); end = begin.substring(0, begin.length()-1) + (char)(next+i);
if(compareMode.compareString(begin, end, ignoreCase) == -1) { if(compareMode.compareString(begin, end, ignoreCase) == -1) {
condition = filter.addIndexCondition(condition, new IndexCondition(Comparison.SMALLER, l, ValueExpression.get(ValueString.get(end)))); filter.addIndexCondition(new IndexCondition(Comparison.SMALLER, l, ValueExpression.get(ValueString.get(end))));
break; break;
} }
} }
} }
} }
return condition;
} }
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
......
...@@ -199,10 +199,34 @@ public class Comparison extends Condition { ...@@ -199,10 +199,34 @@ public class Comparison extends Condition {
} }
} }
public Expression createIndexConditions(TableFilter filter) { private int getNotCompareType(int type) {
switch(compareType) {
case EQUAL:
return NOT_EQUAL;
case NOT_EQUAL:
return EQUAL;
case BIGGER_EQUAL:
return SMALLER;
case BIGGER:
return SMALLER_EQUAL;
case SMALLER_EQUAL:
return BIGGER;
case SMALLER:
return BIGGER_EQUAL;
default:
throw Message.getInternalError("type="+compareType);
}
}
public Expression getNotIfPossible(Session session) {
int type = getNotCompareType(compareType);
return new Comparison(session, type, left, right);
}
public void createIndexConditions(TableFilter filter) {
if(right==null) { if(right==null) {
// TODO index usage: IS [NOT] NULL index usage is possible // TODO index usage: IS [NOT] NULL index usage is possible
return this; return;
} }
ExpressionColumn l = null; ExpressionColumn l = null;
if(left instanceof ExpressionColumn) { if(left instanceof ExpressionColumn) {
...@@ -220,12 +244,22 @@ public class Comparison extends Condition { ...@@ -220,12 +244,22 @@ public class Comparison extends Condition {
} }
// one side must be from the current filter // one side must be from the current filter
if(l==null && r==null) { if(l==null && r==null) {
return this; return;
} }
// filter.addFilterCondition(this, join);
// if both sides are part of the same filter, it can't be used for index lookup
if(l!=null && r!=null) { if(l!=null && r!=null) {
return this; return;
}
if(l == null) {
if(!left.isEverything(ExpressionVisitor.getNotFromResolver(filter))) {
return;
}
} else if(r == null) {
if(!right.isEverything(ExpressionVisitor.getNotFromResolver(filter))) {
return;
}
} else {
// if both sides are part of the same filter, it can't be used for index lookup
return;
} }
boolean addIndex; boolean addIndex;
switch(compareType) { switch(compareType) {
...@@ -244,13 +278,13 @@ public class Comparison extends Condition { ...@@ -244,13 +278,13 @@ public class Comparison extends Condition {
} }
if(addIndex) { if(addIndex) {
if(l!=null) { if(l!=null) {
return filter.addIndexCondition(this, new IndexCondition(compareType, l, right)); filter.addIndexCondition(new IndexCondition(compareType, l, right));
} else if(r!=null) { } else if(r!=null) {
int compareRev = getReversedCompareType(compareType); int compareRev = getReversedCompareType(compareType);
return filter.addIndexCondition(this, new IndexCondition(compareRev, r, left)); filter.addIndexCondition(new IndexCondition(compareRev, r, left));
} }
} }
return this; return;
} }
public void setEvaluatable(TableFilter tableFilter, boolean b) { public void setEvaluatable(TableFilter tableFilter, boolean b) {
...@@ -293,4 +327,23 @@ public class Comparison extends Condition { ...@@ -293,4 +327,23 @@ public class Comparison extends Condition {
return left.getCost() + (right == null ? 0 : right.getCost()) + 1; return left.getCost() + (right == null ? 0 : right.getCost()) + 1;
} }
public Comparison getAdditional(Session session, Comparison other) {
if(compareType == other.compareType && compareType == EQUAL) {
String l = left.getSQL();
String l2 = other.left.getSQL();
String r = right.getSQL();
String r2 = other.right.getSQL();
if(l.equals(l2)) {
return new Comparison(session, EQUAL, right, other.right);
} else if(l.equals(r2)) {
return new Comparison(session, EQUAL, right, other.left);
} else if(r.equals(l2)) {
return new Comparison(session, EQUAL, left, other.right);
} else if(r.equals(r2)) {
return new Comparison(session, EQUAL, left, other.left);
}
}
return null;
}
} }
...@@ -51,12 +51,26 @@ public class ConditionAndOr extends Condition { ...@@ -51,12 +51,26 @@ public class ConditionAndOr extends Condition {
return "("+sql+")"; return "("+sql+")";
} }
public Expression createIndexConditions(TableFilter filter) throws SQLException { public void createIndexConditions(TableFilter filter) throws SQLException {
if (andOrType == AND) { if (andOrType == AND) {
left = left.createIndexConditions(filter); left.createIndexConditions(filter);
right = right.createIndexConditions(filter); right.createIndexConditions(filter);
} }
return this; }
public Expression getNotIfPossible(Session session) {
// (NOT (A OR B)) > (NOT(A) OR NOT(B))
// (NOT (A AND B)) > (NOT(A) OR NOT(B))
Expression l = left.getNotIfPossible(session);
if(l == null) {
l = new ConditionNot(left);
}
Expression r = right.getNotIfPossible(session);
if(r == null) {
r = new ConditionNot(right);
}
int reversed = andOrType == AND ? OR : AND;
return new ConditionAndOr(reversed, l, r);
} }
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
...@@ -112,6 +126,20 @@ public class ConditionAndOr extends Condition { ...@@ -112,6 +126,20 @@ public class ConditionAndOr extends Condition {
left = right; left = right;
right = t; right = t;
} }
// TODO optimization: convert ((A=1 AND B=2) OR (A=1 AND B=3)) to (A=1 AND (B=2 OR B=3))
if(Constants.OPTIMIZE_2_EQUALS && andOrType == AND) {
// try to add conditions (A=B AND B=1: add A=1)
if(left instanceof Comparison && right instanceof Comparison) {
Comparison compLeft = (Comparison) left;
Comparison compRight = (Comparison) right;
Expression added = compLeft.getAdditional(session, compRight);
if(added != null) {
added = added.optimize(session);
ConditionAndOr a = new ConditionAndOr(AND, this, added);
return a;
}
}
}
Value l = left.isConstant() ? left.getValue(session) : null; Value l = left.isConstant() ? left.getValue(session) : null;
Value r = right.isConstant() ? right.getValue(session) : null; Value r = right.isConstant() ? right.getValue(session) : null;
if(l==null && r==null) { if(l==null && r==null) {
......
...@@ -120,24 +120,22 @@ public class ConditionIn extends Condition { ...@@ -120,24 +120,22 @@ public class ConditionIn extends Condition {
return this; return this;
} }
public Expression createIndexConditions(TableFilter filter) { public void createIndexConditions(TableFilter filter) {
if(!Constants.OPTIMIZE_IN) { if(!Constants.OPTIMIZE_IN) {
return this; return;
} }
if(min == null && max == null) { if(min == null && max == null) {
return this; return;
} }
if(!(left instanceof ExpressionColumn)) { if(!(left instanceof ExpressionColumn)) {
return this; return;
} }
ExpressionColumn l = (ExpressionColumn)left; ExpressionColumn l = (ExpressionColumn)left;
if(filter != l.getTableFilter()) { if(filter != l.getTableFilter()) {
return this; return;
} }
Expression result = this; filter.addIndexCondition(new IndexCondition(Comparison.BIGGER_EQUAL, l, ValueExpression.get(min)));
result = filter.addIndexCondition(result, new IndexCondition(Comparison.BIGGER_EQUAL, l, ValueExpression.get(min))); filter.addIndexCondition(new IndexCondition(Comparison.SMALLER_EQUAL, l, ValueExpression.get(max)));
result = filter.addIndexCondition(result, new IndexCondition(Comparison.SMALLER_EQUAL, l, ValueExpression.get(max)));
return result;
} }
public void setEvaluatable(TableFilter tableFilter, boolean b) { public void setEvaluatable(TableFilter tableFilter, boolean b) {
......
...@@ -6,6 +6,7 @@ package org.h2.expression; ...@@ -6,6 +6,7 @@ package org.h2.expression;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -20,9 +21,8 @@ public class ConditionNot extends Condition { ...@@ -20,9 +21,8 @@ public class ConditionNot extends Condition {
this.condition = condition; this.condition = condition;
} }
public Expression createIndexConditions(TableFilter filter) { public Expression getNotIfPossible(Session session) {
// TODO optimization: in some cases, index conditions can be created here return condition;
return this;
} }
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
...@@ -38,8 +38,17 @@ public class ConditionNot extends Condition { ...@@ -38,8 +38,17 @@ public class ConditionNot extends Condition {
} }
public Expression optimize(Session session) throws SQLException { public Expression optimize(Session session) throws SQLException {
if(!Constants.OPTIMIZE_NOT) {
return this;
}
// TODO optimization: some cases are maybe possible to optimize further: (NOT ID >= 5) // TODO optimization: some cases are maybe possible to optimize further: (NOT ID >= 5)
Expression expr = condition.optimize(session); Expression expr = condition.optimize(session);
Expression e2 = expr.getNotIfPossible(session);
if(e2 != null) {
e2 = e2.optimize(session);
expr = e2;
return e2;
}
if(expr.isConstant()) { if(expr.isConstant()) {
Value v = expr.getValue(session); Value v = expr.getValue(session);
if(v == ValueNull.INSTANCE) { if(v == ValueNull.INSTANCE) {
......
...@@ -38,6 +38,11 @@ public abstract class Expression { ...@@ -38,6 +38,11 @@ public abstract class Expression {
return isEverything(visitor); return isEverything(visitor);
} }
public Expression getNotIfPossible(Session session) {
// by default it is not possible
return null;
}
public boolean isConstant() { public boolean isConstant() {
return false; return false;
} }
...@@ -51,9 +56,8 @@ public abstract class Expression { ...@@ -51,9 +56,8 @@ public abstract class Expression {
return getValue(session).getBoolean(); return getValue(session).getBoolean();
} }
public Expression createIndexConditions(TableFilter filter) throws SQLException { public void createIndexConditions(TableFilter filter) throws SQLException {
// default is do nothing // default is do nothing
return this;
} }
public String getColumnName() { public String getColumnName() {
......
...@@ -236,6 +236,8 @@ public class ExpressionColumn extends Expression { ...@@ -236,6 +236,8 @@ public class ExpressionColumn extends Expression {
case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID: case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
visitor.addDataModificationId(column.getTable().getMaxDataModificationId()); visitor.addDataModificationId(column.getTable().getMaxDataModificationId());
return true; return true;
case ExpressionVisitor.NOT_FROM_RESOLVER:
return resolver != visitor.getResolver();
default: default:
throw Message.getInternalError("type="+visitor.type); throw Message.getInternalError("type="+visitor.type);
} }
...@@ -245,16 +247,16 @@ public class ExpressionColumn extends Expression { ...@@ -245,16 +247,16 @@ public class ExpressionColumn extends Expression {
return 2; return 2;
} }
public Expression createIndexConditions(TableFilter filter) { public void createIndexConditions(TableFilter filter) {
TableFilter tf = getTableFilter(); TableFilter tf = getTableFilter();
if(filter != tf) { if(filter == tf && column.getType() == Value.BOOLEAN) {
return this;
}
if(column.getType() == Value.BOOLEAN) {
IndexCondition cond = new IndexCondition(Comparison.EQUAL, this, ValueExpression.get(ValueBoolean.get(true))); IndexCondition cond = new IndexCondition(Comparison.EQUAL, this, ValueExpression.get(ValueBoolean.get(true)));
return filter.addIndexCondition(this, cond); filter.addIndexCondition(cond);
} }
return this; }
public Expression getNotIfPossible(Session session) {
return new Comparison(session, Comparison.EQUAL, this, ValueExpression.get(ValueBoolean.get(false)));
} }
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.expression; package org.h2.expression;
import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
public class ExpressionVisitor { public class ExpressionVisitor {
...@@ -25,10 +26,14 @@ public class ExpressionVisitor { ...@@ -25,10 +26,14 @@ public class ExpressionVisitor {
// Does the expression have no side effects (change the data)? // Does the expression have no side effects (change the data)?
public static final int READONLY = 5; public static final int READONLY = 5;
// Does an expression have no relation to the given table filter?
public static final int NOT_FROM_RESOLVER = 6;
int queryLevel; int queryLevel;
public Table table; public Table table;
public int type; public int type;
private long maxDataModificationId; private long maxDataModificationId;
private ColumnResolver resolver;
public static ExpressionVisitor get(int type) { public static ExpressionVisitor get(int type) {
return new ExpressionVisitor(type); return new ExpressionVisitor(type);
...@@ -46,8 +51,18 @@ public class ExpressionVisitor { ...@@ -46,8 +51,18 @@ public class ExpressionVisitor {
queryLevel += offset; queryLevel += offset;
} }
public ColumnResolver getResolver() {
return resolver;
}
public void addDataModificationId(long v) { public void addDataModificationId(long v) {
maxDataModificationId = Math.max(maxDataModificationId, v); maxDataModificationId = Math.max(maxDataModificationId, v);
} }
public static ExpressionVisitor getNotFromResolver(ColumnResolver resolver) {
ExpressionVisitor v = new ExpressionVisitor(NOT_FROM_RESOLVER);
v.resolver = resolver;
return v;
}
} }
...@@ -1411,7 +1411,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1411,7 +1411,7 @@ public class Function extends Expression implements FunctionCall {
switch(info.type) { switch(info.type) {
case CAST: case CAST:
case CONVERT: { case CONVERT: {
buff.append(StringUtils.unEnclose(args[0].getSQL())); buff.append(args[0].getSQL());
buff.append(" AS "); buff.append(" AS ");
buff.append(new Column(null, dataType, precision, scale).getCreateSQL()); buff.append(new Column(null, dataType, precision, scale).getCreateSQL());
break; break;
...@@ -1420,7 +1420,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1420,7 +1420,7 @@ public class Function extends Expression implements FunctionCall {
ValueString v = (ValueString)((ValueExpression)args[0]).getValue(null); ValueString v = (ValueString)((ValueExpression)args[0]).getValue(null);
buff.append(v.getString()); buff.append(v.getString());
buff.append(" FROM "); buff.append(" FROM ");
buff.append(StringUtils.unEnclose(args[1].getSQL())); buff.append(args[1].getSQL());
break; break;
} }
case TABLE: { case TABLE: {
...@@ -1441,7 +1441,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1441,7 +1441,7 @@ public class Function extends Expression implements FunctionCall {
buff.append(", "); buff.append(", ");
} }
Expression e = args[i]; Expression e = args[i];
buff.append(StringUtils.unEnclose(e.getSQL())); buff.append(e.getSQL());
} }
} }
} }
......
...@@ -11,6 +11,7 @@ import org.h2.message.Message; ...@@ -11,6 +11,7 @@ import org.h2.message.Message;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
/** /**
...@@ -103,6 +104,8 @@ public class Parameter extends Expression implements ParameterInterface { ...@@ -103,6 +104,8 @@ public class Parameter extends Expression implements ParameterInterface {
case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID: case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
// it is checked independently if the value is the same as the last time // it is checked independently if the value is the same as the last time
return true; return true;
case ExpressionVisitor.NOT_FROM_RESOLVER:
return true;
default: default:
throw Message.getInternalError("type="+visitor.type); throw Message.getInternalError("type="+visitor.type);
} }
...@@ -112,4 +115,8 @@ public class Parameter extends Expression implements ParameterInterface { ...@@ -112,4 +115,8 @@ public class Parameter extends Expression implements ParameterInterface {
return 0; return 0;
} }
public Expression getNotIfPossible(Session session) {
return new Comparison(session, Comparison.EQUAL, this, ValueExpression.get(ValueBoolean.get(false)));
}
} }
...@@ -70,6 +70,8 @@ public class Rownum extends Expression { ...@@ -70,6 +70,8 @@ public class Rownum extends Expression {
return true; return true;
case ExpressionVisitor.READONLY: case ExpressionVisitor.READONLY:
return true; return true;
case ExpressionVisitor.NOT_FROM_RESOLVER:
return true;
default: default:
throw Message.getInternalError("type="+visitor.type); throw Message.getInternalError("type="+visitor.type);
} }
......
...@@ -79,6 +79,8 @@ public class SequenceValue extends Expression { ...@@ -79,6 +79,8 @@ public class SequenceValue extends Expression {
case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID: case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
visitor.addDataModificationId(sequence.getModificationId()); visitor.addDataModificationId(sequence.getModificationId());
return true; return true;
case ExpressionVisitor.NOT_FROM_RESOLVER:
return true;
default: default:
throw Message.getInternalError("type="+visitor.type); throw Message.getInternalError("type="+visitor.type);
} }
......
...@@ -39,14 +39,17 @@ public class ValueExpression extends Expression { ...@@ -39,14 +39,17 @@ public class ValueExpression extends Expression {
return value.getType(); return value.getType();
} }
public Expression createIndexConditions(TableFilter filter) { public void createIndexConditions(TableFilter filter) {
if(value.getType() == Value.BOOLEAN) { if(value.getType() == Value.BOOLEAN) {
boolean v = ((ValueBoolean)value).getBoolean().booleanValue(); boolean v = ((ValueBoolean)value).getBoolean().booleanValue();
if(!v) { if(!v) {
return filter.addIndexCondition(this, new IndexCondition(Comparison.FALSE, null, this)); filter.addIndexCondition(new IndexCondition(Comparison.FALSE, null, this));
} }
} }
return this; }
public Expression getNotIfPossible(Session session) {
return new Comparison(session, Comparison.EQUAL, this, ValueExpression.get(ValueBoolean.get(false)));
} }
public void mapColumns(ColumnResolver resolver, int level) throws SQLException { public void mapColumns(ColumnResolver resolver, int level) throws SQLException {
...@@ -91,6 +94,8 @@ public class ValueExpression extends Expression { ...@@ -91,6 +94,8 @@ public class ValueExpression extends Expression {
return true; return true;
case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID: case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
return true; return true;
case ExpressionVisitor.NOT_FROM_RESOLVER:
return true;
default: default:
throw Message.getInternalError("type="+visitor.type); throw Message.getInternalError("type="+visitor.type);
} }
......
...@@ -150,7 +150,7 @@ public class PgServerThread implements Runnable { ...@@ -150,7 +150,7 @@ public class PgServerThread implements Runnable {
println(" key: "+readInt()); println(" key: "+readInt());
error("CancelRequest", null); error("CancelRequest", null);
} else if(version == 80877103) { } else if(version == 80877103) {
println("SSLRequest"); // println("SSLRequest");
out.write('N'); out.write('N');
} else { } else {
// println("StartupMessage"); // println("StartupMessage");
...@@ -195,7 +195,6 @@ public class PgServerThread implements Runnable { ...@@ -195,7 +195,6 @@ public class PgServerThread implements Runnable {
Prepared p = new Prepared(); Prepared p = new Prepared();
p.name = readString(); p.name = readString();
p.sql = getSQL(readString()); p.sql = getSQL(readString());
println(p.sql + ";");
int count = readShort(); int count = readShort();
p.paramType = new int[count]; p.paramType = new int[count];
for(int i=0; i<count; i++) { for(int i=0; i<count; i++) {
...@@ -366,6 +365,7 @@ public class PgServerThread implements Runnable { ...@@ -366,6 +365,7 @@ public class PgServerThread implements Runnable {
} }
int todoNeedToSupportInParser; int todoNeedToSupportInParser;
s = StringUtils.replaceAll(s, "i.indkey[ia.attnum-1]", "0"); s = StringUtils.replaceAll(s, "i.indkey[ia.attnum-1]", "0");
println(s + ";");
return s; return s;
} }
......
...@@ -291,3 +291,5 @@ SELECT ...@@ -291,3 +291,5 @@ SELECT
AND n.nspname = 'PUBLIC' AND n.nspname = 'PUBLIC'
AND ct.relname = 'TEST' AND ct.relname = 'TEST'
ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION ; ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION ;
...@@ -878,7 +878,7 @@ class WebThread extends Thread { ...@@ -878,7 +878,7 @@ class WebThread extends Thread {
buff.append(PageParser.escapeHtml(s+";")); buff.append(PageParser.escapeHtml(s+";"));
buff.append("<br />"); buff.append("<br />");
} }
buff.append(getResult(conn, i+1, s, list.size()==1)); buff.append(getResult(conn, i+1, s, list.size()==1, false));
buff.append("<br />"); buff.append("<br />");
} }
result = buff.toString(); result = buff.toString();
...@@ -924,7 +924,7 @@ class WebThread extends Thread { ...@@ -924,7 +924,7 @@ class WebThread extends Thread {
} }
String sql = "@EDIT " + (String) session.get("resultSetSQL"); String sql = "@EDIT " + (String) session.get("resultSetSQL");
Connection conn = session.getConnection(); Connection conn = session.getConnection();
result = error + getResult(conn, -1, sql, true) + result; result = error + getResult(conn, -1, sql, true, true) + result;
session.put("result", result); session.put("result", result);
return "result.jsp"; return "result.jsp";
} }
...@@ -1153,7 +1153,7 @@ class WebThread extends Thread { ...@@ -1153,7 +1153,7 @@ class WebThread extends Thread {
return maxrows; return maxrows;
} }
private String getResult(Connection conn, int id, String sql, boolean allowEdit) { private String getResult(Connection conn, int id, String sql, boolean allowEdit, boolean forceEdit) {
try { try {
sql = sql.trim(); sql = sql.trim();
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
...@@ -1162,7 +1162,13 @@ class WebThread extends Thread { ...@@ -1162,7 +1162,13 @@ class WebThread extends Thread {
String sessionId = attributes.getProperty("jsessionid"); String sessionId = attributes.getProperty("jsessionid");
buff.append("<script type=\"text/javascript\">top['h2menu'].location='tables.do?jsessionid="+sessionId+"';</script>"); buff.append("<script type=\"text/javascript\">top['h2menu'].location='tables.do?jsessionid="+sessionId+"';</script>");
} }
Statement stat = conn.createStatement(); Statement stat;
DbContents contents = session.getContents();
if(forceEdit || (allowEdit && contents.isH2)) {
stat = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
} else {
stat = conn.createStatement();
}
ResultSet rs; ResultSet rs;
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
boolean metadata = false; boolean metadata = false;
...@@ -1441,7 +1447,7 @@ class WebThread extends Thread { ...@@ -1441,7 +1447,7 @@ class WebThread extends Thread {
buff.append("</tr>"); buff.append("</tr>");
} }
} }
boolean isUpdatable = rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE; boolean isUpdatable = rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE && rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
if(edit) { if(edit) {
ResultSet old = session.result; ResultSet old = session.result;
if(old != null) { if(old != null) {
......
...@@ -144,21 +144,7 @@ public class FunctionTable extends Table { ...@@ -144,21 +144,7 @@ public class FunctionTable extends Table {
} }
public String getSQL() { public String getSQL() {
int todoDocument;
return function.getSQL(); return function.getSQL();
// return super.getSQL();
// StringBuffer buff = new StringBuffer();
// buff.append(super.getSQL());
// buff.append('(');
// Expression[] args = function.getArgs();
// for (int i = 0; i < args.length; i++) {
// if (i > 0) {
// buff.append(", ");
// }
// buff.append(args[i].getSQL());
// }
// buff.append(')');
// return buff.toString();
} }
} }
...@@ -289,8 +289,7 @@ public class TableData extends Table implements RecordReader { ...@@ -289,8 +289,7 @@ public class TableData extends Table implements RecordReader {
session.addLock(this); session.addLock(this);
lockExclusive = session; lockExclusive = session;
return; return;
} else if (lockShared.size() == 1 } else if (lockShared.size() == 1 && lockShared.contains(session)) {
&& lockShared.contains(session)) {
traceLock(session, exclusive, "ok (upgrade)"); traceLock(session, exclusive, "ok (upgrade)");
lockExclusive = session; lockExclusive = session;
return; return;
...@@ -388,13 +387,17 @@ public class TableData extends Table implements RecordReader { ...@@ -388,13 +387,17 @@ public class TableData extends Table implements RecordReader {
if(lockExclusive == s) { if(lockExclusive == s) {
lockExclusive = null; lockExclusive = null;
} }
if(lockShared.size() > 0) {
lockShared.remove(s); lockShared.remove(s);
}
// TODO lock: maybe we need we fifo-queue to make sure nobody starves. check what other databases do // TODO lock: maybe we need we fifo-queue to make sure nobody starves. check what other databases do
synchronized(database) { synchronized(database) {
if(database.getSessionCount() > 1) {
database.notifyAll(); database.notifyAll();
} }
} }
} }
}
public Record read(DataPage s) throws SQLException { public Record read(DataPage s) throws SQLException {
int len = s.readInt(); int len = s.readInt();
......
...@@ -5,13 +5,11 @@ ...@@ -5,13 +5,11 @@
package org.h2.table; package org.h2.table;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.command.dml.Select; import org.h2.command.dml.Select;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr; import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.index.Cursor; import org.h2.index.Cursor;
...@@ -323,21 +321,8 @@ public class TableFilter implements ColumnResolver { ...@@ -323,21 +321,8 @@ public class TableFilter implements ColumnResolver {
return table.getName(); return table.getName();
} }
public Expression addIndexCondition(Expression expr, IndexCondition condition) { public void addIndexCondition(IndexCondition condition) {
for(int i=0; i<indexConditions.size(); i++) {
IndexCondition c = (IndexCondition) indexConditions.get(i);
if(c.getColumn() == condition.getColumn()) {
if(c.getMask() == IndexCondition.EQUALITY && condition.getMask() == IndexCondition.EQUALITY) {
Expression e1 = c.getExpression();
Expression e2 = condition.getExpression();
// Comparison comp = new Comparison();
System.out.println("add: " + e1.getSQL() + " = " + e2.getSQL());
}
}
}
indexConditions.add(condition); indexConditions.add(condition);
return expr;
} }
public void addFilterCondition(Expression condition, boolean join) { public void addFilterCondition(Expression condition, boolean join) {
...@@ -380,7 +365,7 @@ public class TableFilter implements ColumnResolver { ...@@ -380,7 +365,7 @@ public class TableFilter implements ColumnResolver {
private void mapAndAddFilter(Expression on) throws SQLException { private void mapAndAddFilter(Expression on) throws SQLException {
on.mapColumns(this, 0); on.mapColumns(this, 0);
addFilterCondition(on, true); addFilterCondition(on, true);
on = on.createIndexConditions(this); on.createIndexConditions(this);
for(int i=0; joins != null && i<joins.size(); i++) { for(int i=0; joins != null && i<joins.size(); i++) {
TableFilter join = getTableFilter(i); TableFilter join = getTableFilter(i);
join.mapAndAddFilter(on); join.mapAndAddFilter(on);
......
...@@ -319,7 +319,7 @@ public class Server implements Runnable { ...@@ -319,7 +319,7 @@ public class Server implements Runnable {
} }
/** /**
* Create a new TCP server, but does not start it yet. * Create a new ODBC server, but does not start it yet.
* @param args * @param args
* @return the server * @return the server
*/ */
......
...@@ -260,7 +260,6 @@ public class StringUtils { ...@@ -260,7 +260,6 @@ public class StringUtils {
} }
public static String unEnclose(String s) { public static String unEnclose(String s) {
int todoNotCorrectForArrays;
if(s.startsWith("(") && s.endsWith(")")) { if(s.startsWith("(") && s.endsWith(")")) {
return s.substring(1, s.length()-1); return s.substring(1, s.length()-1);
} else { } else {
......
...@@ -94,54 +94,12 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -94,54 +94,12 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
/* /*
H2 Console: the result set is not updatable by default. Need to change in web console, and test other databases
drop table tc, ts, tx;
CREATE MEMORY TABLE tc(ARG0 INT, ARG1 INT);
-- 8 = SELECT COUNT(*) FROM tc;
INSERT INTO tc(ARG0, ARG1) VALUES(1, 0);
INSERT INTO tc(ARG0, ARG1) VALUES(2, 0);
INSERT INTO tc(ARG0, ARG1) VALUES(3, 0);
INSERT INTO tc(ARG0, ARG1) VALUES(4, 0);
INSERT INTO tc(ARG0, ARG1) VALUES(5, 0);
INSERT INTO tc(ARG0, ARG1) VALUES(7, 6);
INSERT INTO tc(ARG0, ARG1) VALUES(8, 6);
INSERT INTO tc(ARG0, ARG1) VALUES(5, 6);
CREATE INDEX tc01 ON tc(ARG0, ARG1);
CREATE INDEX tc1 ON tc(ARG1);
CREATE MEMORY TABLE ts(ARG0 INT, ARG1 INT, ARG2 INT);
-- 0 = SELECT COUNT(*) FROM ts;
CREATE INDEX ts02 ON ts(ARG0, ARG2);
CREATE INDEX ts12 ON ts(ARG1, ARG2);
CREATE INDEX ts2 ON ts(ARG2);
CREATE FORCE VIEW v1(ARG0, ARG1) AS (SELECT ARG0, ARG1 FROM tc UNION SELECT ARG0, ARG2 FROM ts);
create table tx (ARG1 int);
insert into tx values (0),(6);
-- This query produce the correct results only with -Dh2.indexOld=true
select * from v1 natural join tx;
drop view V;
drop table A, B;
CREATE TABLE A(A INT);
INSERT INTO A(A) VALUES(6);
CREATE TABLE B(B INT PRIMARY KEY);
CREATE VIEW V(V) AS (SELECT A FROM A UNION SELECT B FROM B);
drop table C;
create table C(C int);
delete from C;
insert into C values (0), (6);
select * from V, C where V.V = C.C;
I forgot to mention a litte documentation bug.
In the code sample of the feature section "Compacting a Database" there is the line
Backup.execute(url, user, password, script);
Correctly it should be
Script.execute(url, user, password, script);
database is not closed when killing the process (but should? why not?)
set read-committed as the default
SELECT rolcreaterole, rolcreatedb FROM pg_roles WHERE rolname = current_user;
check trace.db/ number of files, limit to 1000 or so check trace.db/ number of files, limit to 1000 or so
...@@ -169,8 +127,6 @@ make sure INDEX_LOOKUP_NEW = is true by default. ...@@ -169,8 +127,6 @@ make sure INDEX_LOOKUP_NEW = is true by default.
Test Console (batch, javaw, different platforms) Test Console (batch, javaw, different platforms)
test with openoffice (metadata changes) test with openoffice (metadata changes)
set read-committed as the default
testHalt testHalt
java org.h2.test.TestAll halt java org.h2.test.TestAll halt
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
explain select * from system_range(1, 2) where x=x+1 and x=1;
> PLAN
> -------------------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */ WHERE (X <> 1) OR ((X * 2) <> 2)
> rows: 1
explain select * from system_range(1, 2) where not (x = 1 and x*2 = 2);
> PLAN
> -------------------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */ WHERE (X <> 1) OR ((X * 2) <> 2)
> rows: 1
explain select * from system_range(1, 10) where (NOT x >= 5);
> PLAN
> ------------------------------------------------------------------------------------------
> SELECT SYSTEM_RANGE.X FROM SYSTEM_RANGE(1, 10) /* PUBLIC.RANGE_INDEX: X < 5 */ WHERE X < 5
> rows: 1
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255));
> ok
INSERT INTO TEST VALUES(1, 'Hello'), (-1, '-1');
> update count: 2
select * from test where name = -1 and name = id;
> ID NAME
> -- ----
> -1 -1
> rows: 1
explain select * from test where name = -1 and name = id;
> PLAN
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT TEST.ID, TEST.NAME FROM PUBLIC.TEST /* PUBLIC.PRIMARY_KEY_1: ID = -1 */ WHERE ((CAST(NAME AS INTEGER) = -1) AND (CAST(NAME AS INTEGER) = ID)) AND (-1 = ID)
> rows: 1
DROP TABLE TEST;
> ok
select * from system_range(1, 2) where x=x+1 and x=1;
> X
> -
> rows: 0
CREATE TABLE A as select 6 a;
> ok
CREATE TABLE B(B INT PRIMARY KEY);
> ok
CREATE VIEW V(V) AS (SELECT A FROM A UNION SELECT B FROM B);
> ok
create table C as select * from table(c int = (0,6));
> ok
select * from V, C where V.V = C.C;
> V C
> - -
> 6 6
> rows: 1
drop table A, B, C, V;
> ok
explain select * from table(id int = (1, 2), name varchar=('Hello', 'World'));
> PLAN
> ------------------------------------------------------------------------------------------------------
> SELECT TABLE.ID, TABLE.NAME FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World')) /* PUBLIC."" */
> rows: 1
CREATE TABLE TEST(ID INT PRIMARY KEY, FLAG BOOLEAN, NAME VARCHAR); CREATE TABLE TEST(ID INT PRIMARY KEY, FLAG BOOLEAN, NAME VARCHAR);
> ok > ok
...@@ -6,13 +77,19 @@ CREATE INDEX IDXFLAG ON TEST(FLAG, NAME); ...@@ -6,13 +77,19 @@ CREATE INDEX IDXFLAG ON TEST(FLAG, NAME);
> ok > ok
INSERT INTO TEST VALUES(1, TRUE, 'Hello'), (2, FALSE, 'World'); INSERT INTO TEST VALUES(1, TRUE, 'Hello'), (2, FALSE, 'World');
> ok > update count: 2
EXPLAIN SELECT * FROM TEST WHERE FLAG; EXPLAIN SELECT * FROM TEST WHERE FLAG;
> ok > PLAN
> --------------------------------------------------------------------------------------------------
> SELECT TEST.ID, TEST.FLAG, TEST.NAME FROM PUBLIC.TEST /* PUBLIC.IDXFLAG: FLAG = TRUE */ WHERE FLAG
> rows: 1
EXPLAIN SELECT * FROM TEST WHERE FLAG AND NAME>'I'; EXPLAIN SELECT * FROM TEST WHERE FLAG AND NAME>'I';
> ok > PLAN
> ----------------------------------------------------------------------------------------------------------------------------------
> SELECT TEST.ID, TEST.FLAG, TEST.NAME FROM PUBLIC.TEST /* PUBLIC.IDXFLAG: FLAG = TRUE AND NAME > 'I' */ WHERE FLAG AND (NAME > 'I')
> rows: 1
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
...@@ -1060,8 +1137,8 @@ insert into x values(0), (1), (10); ...@@ -1060,8 +1137,8 @@ insert into x values(0), (1), (10);
> update count: 3 > update count: 3
SELECT t1.ID, (SELECT t1.id || ':' || AVG(t2.ID) FROM X t2) FROM X t1; SELECT t1.ID, (SELECT t1.id || ':' || AVG(t2.ID) FROM X t2) FROM X t1;
> ID SELECT (T1.ID || ':') || AVG(T2.ID) FROM PUBLIC.X T2 /* PUBLIC.X_TABLE_SCAN */ LIMIT 2 > ID SELECT ((T1.ID || ':') || AVG(T2.ID)) FROM PUBLIC.X T2 /* PUBLIC.X_TABLE_SCAN */ LIMIT 2
> -- -------------------------------------------------------------------------------------- > -- ----------------------------------------------------------------------------------------
> 0 0:3 > 0 0:3
> 1 1:3 > 1 1:3
> 10 10:3 > 10 10:3
...@@ -1620,8 +1697,8 @@ SELECT CASE WHEN NOT (false IN (null)) THEN false END; ...@@ -1620,8 +1697,8 @@ SELECT CASE WHEN NOT (false IN (null)) THEN false END;
> rows: 1 > rows: 1
select a.v as av, b.v as bv, a.v IN (b.v), not a.v IN (b.v) from test a, test b; select a.v as av, b.v as bv, a.v IN (b.v), not a.v IN (b.v) from test a, test b;
> AV BV A.V = B.V NOT (A.V = B.V) > AV BV A.V = B.V A.V <> B.V
> ----- ----- --------- --------------- > ----- ----- --------- ----------
> FALSE FALSE TRUE FALSE > FALSE FALSE TRUE FALSE
> FALSE TRUE FALSE TRUE > FALSE TRUE FALSE TRUE
> FALSE null null null > FALSE null null null
...@@ -3255,14 +3332,14 @@ update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id ...@@ -3255,14 +3332,14 @@ update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id
explain update test set (id, name)=(id+1, name || 'Hi'); explain update test set (id, name)=(id+1, name || 'Hi');
> PLAN > PLAN
> ---------------------------------------------------------------------------------------------------------------------------------------------- > --------------------------------------------------------------------------------------------------------------------------------------------------
> UPDATE PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ SET ID = ARRAY_GET((ID + 1), (NAME || 'Hi'), 1), NAME = ARRAY_GET((ID + 1), (NAME || 'Hi'), 2) > UPDATE PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ SET ID = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 1), NAME = ARRAY_GET(((ID + 1), (NAME || 'Hi')), 2)
> rows: 1 > rows: 1
explain update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id=t1.id); explain update test set (id, name)=(select id+1, name || 'Ho' from test t1 where test.id=t1.id);
> PLAN > PLAN
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> UPDATE PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ SET ID = ARRAY_GET(SELECT ID + 1, NAME || 'Ho' FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_1: ID = TEST.ID */ WHERE TEST.ID = T1.ID, 1), NAME = ARRAY_GET(SELECT ID + 1, NAME || 'Ho' FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_1: ID = TEST.ID */ WHERE TEST.ID = T1.ID, 2) > UPDATE PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ SET ID = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_1: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 1), NAME = ARRAY_GET((SELECT (ID + 1), (NAME || 'Ho') FROM PUBLIC.TEST T1 /* PUBLIC.PRIMARY_KEY_1: ID = TEST.ID */ WHERE TEST.ID = T1.ID), 2)
> rows: 1 > rows: 1
select * from test; select * from test;
...@@ -4033,8 +4110,8 @@ SELECT * FROM TEST2COL WHERE A=0 AND B=0; ...@@ -4033,8 +4110,8 @@ SELECT * FROM TEST2COL WHERE A=0 AND B=0;
EXPLAIN SELECT * FROM TEST2COL WHERE A=0 AND B=0; EXPLAIN SELECT * FROM TEST2COL WHERE A=0 AND B=0;
> PLAN > PLAN
> ------------------------------------------------------------------------------------------------------------------------------------ > --------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT TEST2COL.A, TEST2COL.B, TEST2COL.C FROM PUBLIC.TEST2COL /* PUBLIC.PRIMARY_KEY_1: A = 0 AND B = 0 */ WHERE (A = 0) AND (B = 0) > SELECT TEST2COL.A, TEST2COL.B, TEST2COL.C FROM PUBLIC.TEST2COL /* PUBLIC.PRIMARY_KEY_1: A = 0 AND B = 0 */ WHERE ((A = 0) AND (B = 0)) AND (A = B)
> rows: 1 > rows: 1
SELECT * FROM TEST2COL WHERE A=0; SELECT * FROM TEST2COL WHERE A=0;
...@@ -4202,14 +4279,14 @@ EXPLAIN INSERT INTO TEST VALUES(1, 'Test'), (2, 'World'); ...@@ -4202,14 +4279,14 @@ EXPLAIN INSERT INTO TEST VALUES(1, 'Test'), (2, 'World');
EXPLAIN INSERT INTO TEST SELECT DISTINCT ID+1, NAME FROM TEST; EXPLAIN INSERT INTO TEST SELECT DISTINCT ID+1, NAME FROM TEST;
> PLAN > PLAN
> ------------------------------------------------------------------------------------------------------------ > --------------------------------------------------------------------------------------------------------------
> INSERT INTO PUBLIC.TEST(ID, NAME) SELECT DISTINCT ID + 1, NAME FROM PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ > INSERT INTO PUBLIC.TEST(ID, NAME) SELECT DISTINCT (ID + 1), NAME FROM PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */
> rows: 1 > rows: 1
EXPLAIN SELECT DISTINCT ID + 1, NAME FROM TEST; EXPLAIN SELECT DISTINCT ID + 1, NAME FROM TEST;
> PLAN > PLAN
> -------------------------------------------------------------------------- > ----------------------------------------------------------------------------
> SELECT DISTINCT ID + 1, NAME FROM PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */ > SELECT DISTINCT (ID + 1), NAME FROM PUBLIC.TEST /* PUBLIC.TEST_TABLE_SCAN */
> rows: 1 > rows: 1
EXPLAIN SELECT * FROM TEST WHERE 1=0; EXPLAIN SELECT * FROM TEST WHERE 1=0;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论