提交 624fa6ba authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 a55cd699
......@@ -58,7 +58,7 @@
<arg line="+JDK13 -JDK14 -JDK16 -AWT ../src/main/org/h2"/>
</java>
</target>
<target name="codeswitchJdk13" depends="codeswitchPrepare">
<propertyfile file="ant-build.properties">
<entry key="jdk" value="1.3" />
......@@ -97,26 +97,26 @@
<fileset dir="bin" includes="org/h2/util/ResourceData.java"/>
</delete>
</target>
<target name="compileFullTextLucene" depends="compileFullTextLuceneTest, compile" if="lucene.jar.present">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/main" destdir="bin" debug="true">
<classpath location="${path.lucene.jar}" />
<include name="org/h2/fulltext/FullTextLucene.java"/>
</javac>
</target>
<target name="compileFullTextLuceneTest" depends="init" unless="lucene.jar.present">
<echo message="Lucene jar not found, LuceneFullText not compiled."/>
<echo message="Please set ant-build.properties / path.lucene.jar"/>
</target>
</target>
<target name="compileServlet" depends="compileServletTest, compile" if="servlet.jar.present">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/tools" destdir="bin" debug="true">
<classpath location="${path.servlet.jar}" />
<include name="org/h2/server/web/*.*"/>
</javac>
</target>
<target name="compileServletTest" depends="init" unless="servlet.jar.present">
<echo message="Servlet API jar not found, console servlet not compiled."/>
<echo message="Please set ant-build.properties / path.servlet.jar"/>
......@@ -139,7 +139,7 @@
<fileset dir="src/test" includes="**/*.properties"/>
</copy>
</target>
<target name="compileCoverage" depends="compile">
<copy todir="bin" overwrite="true">
<fileset dir="src/main"/>
......@@ -149,19 +149,12 @@
</java>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="bin" destdir="bin" debug="true" includes="org/h2/**"/>
</target>
<target name="compileTest" unless="java.version.ok">
<echo message="Java version is ${java.specification.version} but source code is switched to ${jdk}."/>
<echo message="Run ant codeswitchJdk... first."/>
</target>
<target name="createPatch" depends="clean">
<delete file="../h2-patch.*"/>
<tar destfile="../h2-patch.tar" basedir="." includes="src/**/*.java,build.xml"/>
<bzip2 destfile="../h2-patch.tar.bz2" src="../h2-patch.tar"/>
<delete file="../h2-patch.tar"/>
</target>
<target name="docs" depends="clean,javadoc,compile">
<copy todir="docs">
<fileset dir="src/docsrc" includes="index.html"/>
......@@ -204,7 +197,7 @@
</condition>
<echo message="build-jdk:${java.specification.version} ant-build.properties/jdk:${jdk}"></echo>
</target>
<target name="jar" depends="compile, compileServlet, compileFullTextLucene, manifest">
<manifest file="bin/META-INF/MANIFEST.MF" mode="update">
<attribute name="Main-Class" value="org.h2.tools.Console"/>
......@@ -225,7 +218,7 @@
<target name="jarClient" depends="compileResources, manifest">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/main" destdir="bin" debug="true">
<include name="org/h2/*" />
<include name="org/h2/jdbc/**" />
<include name="org/h2/jdbc/**" />
<include name="org/h2/jdbcx/**" />
</javac>
<jar jarfile="bin/h2client.jar" basedir="bin" manifest="bin/META-INF/MANIFEST.MF">
......@@ -233,19 +226,19 @@
<exclude name="**/*.bat"/>
</jar>
</target>
<target name="jarDb" depends="compileResources, manifest">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/main" destdir="bin" debug="true">
<include name="org/h2/*" />
<include name="org/h2/engine/**" />
<include name="org/h2/jdbc/**" />
<include name="org/h2/engine/**" />
<include name="org/h2/jdbc/**" />
<include name="org/h2/jdbcx/**" />
</javac>
<jar jarfile="bin/h2db.jar" basedir="bin" manifest="bin/META-INF/MANIFEST.MF">
<include name="**/*.*"/>
<exclude name="**/*.bat"/>
</jar>
</target>
</target>
<target name="javadoc">
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="src/test" destdir="bin" debug="true" includes="org/h2/test/bnf/*.java"/>
......@@ -261,7 +254,7 @@
<fileset dir="src/docsrc/javadoc" includes="**/*"/>
</copy>
</target>
<target name="javadocImpl">
<mkdir dir="docs/javadocImpl"/>
<javadoc
......@@ -272,8 +265,8 @@
<copy todir="docs/javadoc">
<fileset dir="src/docsrc/javadoc" includes="**/*"/>
</copy>
</target>
</target>
<target name="manifest">
<mkdir dir="bin/META-INF"/>
<manifest file="bin/META-INF/MANIFEST.MF">
......@@ -286,7 +279,7 @@
<attribute name="Build-Jdk" value="${jdk}"/>
</manifest>
</target>
<target name="mavenBuildCentral">
<copy tofile="bin/h2-${version.name.maven}.jar" file="bin/h2.jar" />
<copy tofile="bin/pom.xml" filtering="true" file="src/installer/pom.xml">
......@@ -347,7 +340,7 @@
<!-- <jvmarg value="-agentlib:hprof=help"/> -->
</java>
</target>
<target name="warConsole" depends="compileServlet, jar">
<fail unless="servlet.jar.present" message="Servlet API jar not found"/>
<war destfile="bin/h2console.war" webxml="src/tools/WEB-INF/web.xml" basedir="src/tools/WEB-INF" includes="console.html">
......
......@@ -551,7 +551,7 @@ public class Parser {
command.setSavepointName(readUniqueIdentifier());
return command;
}
private Prepared parseReleaseSavepoint() throws SQLException {
Prepared command = new NoOperation(session);
readIf("SAVEPOINT");
......@@ -673,7 +673,7 @@ public class Parser {
setSQL(command, "DELETE", start);
return command;
}
private IndexColumn[] parseIndexColumnList() throws SQLException {
ObjectArray columns = new ObjectArray();
do {
......@@ -693,7 +693,7 @@ public class Parser {
column.sortType |= SortOrder.NULLS_LAST;
}
} else {
}
} while (readIf(","));
read(")");
......@@ -833,19 +833,13 @@ public class Parser {
if (readIf("(")) {
if (isToken("SELECT") || isToken("FROM")) {
Query query = parseSelect();
String querySQL = query.getSQL();
Session s;
if (prepared != null && prepared instanceof CreateView) {
s = database.getSystemSession();
} else {
s = session;
}
String tempViewName = s.getNextTempViewName();
TableView v = new TableView(mainSchema, 0, tempViewName, querySQL, query.getParameters(), null, s,
false);
v.setOwner(session.getUser());
v.setTemporary(true);
table = v;
table = TableView.createTempView(s, session.getUser(), query);
read(")");
} else {
TableFilter top = readTableFilter(fromOuter);
......@@ -1076,7 +1070,7 @@ public class Parser {
command.setIfExists(ifExists);
return command;
}
DropAggregate parseDropAggregate() throws SQLException {
boolean ifExists = readIfExists(false);
DropAggregate command = new DropAggregate(session);
......@@ -1148,9 +1142,9 @@ public class Parser {
for (int j = 0; j < joinCols.length; j++) {
String joinColumnName = joinCols[j].getName();
if (tableColumnName.equals(joinColumnName)) {
Expression tableExpr = new ExpressionColumn(database, currentSelect, tableSchema, last
Expression tableExpr = new ExpressionColumn(database, tableSchema, last
.getTableAlias(), tableColumnName);
Expression joinExpr = new ExpressionColumn(database, currentSelect, joinSchema, join
Expression joinExpr = new ExpressionColumn(database, joinSchema, join
.getTableAlias(), joinColumnName);
Expression equal = new Comparison(session, Comparison.EQUAL, tableExpr, joinExpr);
if (on == null) {
......@@ -1759,7 +1753,7 @@ public class Parser {
JavaFunction func = new JavaFunction(functionAlias, args);
return func;
}
private JavaAggregate readJavaAggregate(UserAggregate aggregate) throws SQLException {
ObjectArray params = new ObjectArray();
do {
......@@ -1955,11 +1949,11 @@ public class Parser {
return expr;
}
name = readColumnIdentifier();
return new ExpressionColumn(database, currentSelect, schemaName, objectName, name);
return new ExpressionColumn(database, schemaName, objectName, name);
}
return new ExpressionColumn(database, currentSelect, schemaName, objectName, name);
return new ExpressionColumn(database, schemaName, objectName, name);
}
return new ExpressionColumn(database, currentSelect, null, objectName, name);
return new ExpressionColumn(database, null, objectName, name);
}
private Expression readTerm() throws SQLException {
......@@ -2014,7 +2008,7 @@ public class Parser {
} else if (readIf(".")) {
r = readTermObjectDot(name);
} else {
r = new ExpressionColumn(database, currentSelect, null, null, name);
r = new ExpressionColumn(database, null, null, name);
}
} else {
read();
......@@ -2046,7 +2040,7 @@ public class Parser {
} else if (readIf("DATE")) {
r = readFunctionWithoutParameters("CURRENT_DATE");
} else {
r = new ExpressionColumn(database, currentSelect, null, null, name);
r = new ExpressionColumn(database, null, null, name);
}
} else if ("NEXT".equals(name) && readIf("VALUE")) {
read("FOR");
......@@ -2070,7 +2064,7 @@ public class Parser {
read();
r = ValueExpression.get(ValueString.get(text));
} else {
r = new ExpressionColumn(database, currentSelect, null, null, name);
r = new ExpressionColumn(database, null, null, name);
}
}
break;
......@@ -3352,7 +3346,7 @@ public class Parser {
command.setIfNotExists(ifNotExists);
return command;
}
private CreateAggregate parseCreateAggregate(boolean force) throws SQLException {
boolean ifNotExists = readIfNoExists();
CreateAggregate command = new CreateAggregate(session);
......@@ -3365,7 +3359,7 @@ public class Parser {
command.setIfNotExists(ifNotExists);
read("FOR");
command.setJavaClassMethod(readUniqueIdentifier());
return command;
return command;
}
private CreateUserDataType parseCreateUserDataType() throws SQLException {
......
......@@ -46,7 +46,7 @@ public class Call extends Prepared {
for (int i = 0; i < list.length; i++) {
Value e = list[i];
Column col = new Column("C" + (i + 1), e.getType(), e.getPrecision(), e.getScale(), e.getDisplaySize());
expr.add(new ExpressionColumn(session.getDatabase(), null, col));
expr.add(new ExpressionColumn(session.getDatabase(), col));
}
LocalResult result = new LocalResult(session, expr, list.length);
result.addRow(list);
......
......@@ -22,19 +22,19 @@ public class ExplainPlan extends Prepared {
private Prepared command;
private LocalResult result;
public ExplainPlan(Session session) {
super(session);
}
public void setCommand(Prepared command) {
this.command = command;
}
public void prepare() throws SQLException {
command.prepare();
}
public LocalResult queryMeta() throws SQLException {
return query(-1);
}
......@@ -43,7 +43,7 @@ public class ExplainPlan extends Prepared {
// TODO rights: are rights required for explain?
ObjectArray expressions = new ObjectArray();
Column column = new Column("PLAN", Value.STRING);
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), null, column);
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), column);
expressions.add(expr);
result = new LocalResult(session, expressions, 1);
if (maxrows >= 0) {
......@@ -53,18 +53,18 @@ public class ExplainPlan extends Prepared {
result.done();
return result;
}
private void add(String text) throws SQLException {
Value[] row = new Value[1];
Value value = ValueString.get(text);
row[0] = value;
result.addRow(row);
}
public boolean isQuery() {
return true;
}
}
public boolean isTransactional() {
return true;
}
......
......@@ -31,21 +31,21 @@ import org.h2.value.ValueNull;
* Represents a SELECT statement (simple, or union).
*/
public abstract class Query extends Prepared {
protected Expression limit, offset;
protected int sampleSize;
private int lastLimit;
private long lastEvaluated;
private LocalResult lastResult;
private Value[] lastParameters;
abstract LocalResult queryWithoutCache(int limit) throws SQLException;
public Query(Session session) {
super(session);
}
public boolean isQuery() {
return true;
}
......@@ -53,7 +53,7 @@ public abstract class Query extends Prepared {
public boolean isTransactional() {
return true;
}
public final boolean sameResultAsLast(Session session, Value[] params, Value[] lastParams, long lastEvaluated)
throws SQLException {
Database db = session.getDatabase();
......@@ -70,7 +70,7 @@ public abstract class Query extends Prepared {
}
return true;
}
public final Value[] getParameterValues() throws SQLException {
ObjectArray list = getParameters();
if (list == null) {
......@@ -83,7 +83,7 @@ public abstract class Query extends Prepared {
}
return params;
}
public final LocalResult query(int limit) throws SQLException {
if (!session.getDatabase().getOptimizeReuseResults()) {
return queryWithoutCache(limit);
......@@ -105,7 +105,7 @@ public abstract class Query extends Prepared {
lastLimit = limit;
return lastResult;
}
protected void initOrder(ObjectArray expressions, ObjectArray expressionSQL, ObjectArray orderList, int visible,
boolean mustBeInResult) throws SQLException {
for (int i = 0; i < orderList.size(); i++) {
......@@ -185,7 +185,7 @@ public abstract class Query extends Prepared {
o.columnIndexExpr = ValueExpression.get(ValueInt.get(idx + 1));
}
}
public SortOrder prepareOrder(ObjectArray expressions, ObjectArray orderList) throws SQLException {
int[] index = new int[orderList.size()];
int[] sortType = new int[orderList.size()];
......@@ -228,11 +228,11 @@ public abstract class Query extends Prepared {
}
return new SortOrder(session.getDatabase(), index, sortType);
}
public void setOffset(Expression offset) {
this.offset = offset;
}
public void setLimit(Expression limit) {
this.limit = limit;
}
......@@ -248,6 +248,7 @@ public abstract class Query extends Prepared {
public abstract void setEvaluatable(TableFilter tableFilter, boolean b);
public abstract void addGlobalCondition(Expression expr, int columnId, int comparisonType) throws SQLException;
public abstract void setDistinct(boolean b);
public abstract String getFirstColumnAlias(Session session);
public void setSampleSize(int sampleSize) {
this.sampleSize = sampleSize;
......@@ -260,7 +261,7 @@ public abstract class Query extends Prepared {
}
public abstract boolean isEverything(ExpressionVisitor visitor);
public final boolean isEverything(int expressionVisitorType) {
ExpressionVisitor visitor = ExpressionVisitor.get(expressionVisitorType);
return isEverything(visitor);
......
......@@ -77,7 +77,7 @@ public class ScriptCommand extends ScriptBase {
public boolean isQuery() {
return true;
}
// TODO lock all tables for 'script' command
public void setData(boolean data) {
......@@ -91,24 +91,24 @@ public class ScriptCommand extends ScriptBase {
public void setSettings(boolean settings) {
this.settings = settings;
}
public void setLobBlockSize(long blockSize) {
this.lobBlockSize = MathUtils.convertLongToInt(blockSize);
}
public void setDrop(boolean drop) {
this.drop = drop;
}
public LocalResult queryMeta() throws SQLException {
LocalResult result = createResult();
result.done();
return result;
}
private LocalResult createResult() {
ObjectArray cols = new ObjectArray();
cols.add(new ExpressionColumn(session.getDatabase(), null, new Column("SCRIPT", Value.STRING)));
cols.add(new ExpressionColumn(session.getDatabase(), new Column("SCRIPT", Value.STRING)));
return new LocalResult(session, cols, 1);
}
......@@ -314,7 +314,7 @@ public class ScriptCommand extends ScriptBase {
reset();
return r;
}
private int writeLobStream(ValueLob v) throws IOException, SQLException {
if (!tempLobTableCreated) {
add("CREATE TABLE IF NOT EXISTS SYSTEM_LOB_STREAM(ID INT, PART INT, CDATA VARCHAR, BDATA BINARY, PRIMARY KEY(ID, PART))", true);
......@@ -371,7 +371,7 @@ public class ScriptCommand extends ScriptBase {
}
return id;
}
// called from the script
public static InputStream combineBlob(Connection conn, int id) throws SQLException, IOException {
if (id < 0) {
......
......@@ -10,6 +10,7 @@ import java.util.HashSet;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Session;
import org.h2.expression.Alias;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
......@@ -34,12 +35,12 @@ import org.h2.value.ValueNull;
/**
* This class represents a simple SELECT statement.
*
*
* For each 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.
*
*
* The call sequence is init(), mapColumns() if it's a subquery, prepare().
*/
public class Select extends Query {
......@@ -198,7 +199,7 @@ public class Select extends Query {
* 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 {
......@@ -249,7 +250,7 @@ public class Select extends Query {
}
boolean ok = true;
for (int j = 0; j < sortCols.length; j++) {
// the index and the sort order must start
// the index and the sort order must start
// with the exact same columns
IndexColumn idxCol = indexCols[j];
Column sortCol = sortCols[j];
......@@ -270,8 +271,9 @@ public class Select extends Query {
return null;
}
private void queryFlat(int columnCount, LocalResult result, int limitRows) throws SQLException {
private void queryFlat(int columnCount, LocalResult result, long limitRows) throws SQLException {
if (limitRows != 0 && offset != null) {
// limitRows must be long, otherwise we get an int overflow if limitRows is at or near Integer.MAX_VALUE
limitRows += offset.getValue(session).getInt();
}
int rowNumber = 0;
......@@ -386,7 +388,7 @@ public class Select extends Query {
Column[] columns = t.getColumns();
for (int j = 0; j < columns.length; j++) {
Column c = columns[j];
ExpressionColumn ec = new ExpressionColumn(session.getDatabase(), this, null, alias, c.getName());
ExpressionColumn ec = new ExpressionColumn(session.getDatabase(), null, alias, c.getName());
expressions.add(i++, ec);
}
i--;
......@@ -425,8 +427,8 @@ public class Select extends Query {
havingIndex = -1;
}
// first visible columns, then order by, then having, and then group by
// at the end
// first visible columns, then order by, then having,
// and group by at the end
if (group != null) {
groupIndex = new int[group.size()];
for (int i = 0; i < group.size(); i++) {
......@@ -486,6 +488,9 @@ public class Select extends Query {
}
if (condition != null) {
condition = condition.optimize(session);
if (SysProperties.OPTIMIZE_IN_JOIN) {
condition = condition.optimizeInJoin(session, this);
}
for (int j = 0; j < filters.size(); j++) {
TableFilter f = (TableFilter) filters.get(j);
condition.createIndexConditions(session, f);
......@@ -561,7 +566,7 @@ public class Select extends Query {
for (int i = 0; i < expressions.size(); i++) {
Expression e = (Expression) expressions.get(i);
e.setEvaluatable(f, true);
}
}
f = f.getJoin();
}
topTableFilter.prepare();
......@@ -638,7 +643,7 @@ public class Select extends Query {
if (isForUpdate) {
buff.append("\nFOR UPDATE");
}
if (isQuickQuery) {
buff.append("\n/* direct lookup query */");
}
......@@ -777,4 +782,20 @@ public class Select extends Query {
return isEverything(ExpressionVisitor.READONLY);
}
public String getFirstColumnAlias(Session session) {
if (SysProperties.CHECK) {
if (visibleColumnCount > 1) {
throw Message.getInternalError("" + visibleColumnCount);
}
}
Expression expr = (Expression) expressions.get(0);
if (expr instanceof Alias) {
return expr.getAlias();
} else {
expr = new Alias(expr, session.getNextTempViewName() + "_X");
expressions.set(0, expr);
}
return expr.getAlias();
}
}
......@@ -35,28 +35,28 @@ public class SelectUnion extends Query {
private Query left, right;
private ObjectArray expressions;
private ObjectArray orderList;
private SortOrder sort;
private SortOrder sort;
private boolean distinct;
private boolean isPrepared, checkInit;
private boolean isForUpdate;
public SelectUnion(Session session, Query query) {
super(session);
this.left = query;
}
public void setUnionType(int type) {
this.unionType = type;
}
public void setRight(Query select) throws JdbcSQLException {
right = select;
}
public void setSQL(String sql) {
this.sql = sql;
}
}
public void setOrder(ObjectArray order) {
orderList = order;
}
......@@ -207,7 +207,7 @@ public class SelectUnion extends Query {
int scale = Math.max(l.getScale(), r.getScale());
int displaySize = Math.max(l.getDisplaySize(), r.getDisplaySize());
Column col = new Column(l.getAlias(), type, prec, scale, displaySize);
Expression e = new ExpressionColumn(session.getDatabase(), null, col);
Expression e = new ExpressionColumn(session.getDatabase(), col);
expressions.add(e);
}
if (orderList != null) {
......@@ -331,5 +331,9 @@ public class SelectUnion extends Query {
left.updateAggregate(session);
right.updateAggregate(session);
}
public String getFirstColumnAlias(Session session) {
return null;
}
}
......@@ -27,6 +27,10 @@ public class SysProperties {
public static final boolean OPTIMIZE_EVALUATABLE_SUBQUERIES = getBooleanSetting("h2.optimizeEvaluatableSubqueries", true);
public static final boolean OPTIMIZE_IN = getBooleanSetting("h2.optimizeIn", true);
private int testing;
public static final boolean OPTIMIZE_IN_JOIN = getBooleanSetting("h2.optimizeInJoin", true);
public static final boolean OPTIMIZE_MIN_MAX = getBooleanSetting("h2.optimizeMinMax", true);
public static final boolean OPTIMIZE_SUBQUERY_CACHE = getBooleanSetting("h2.optimizeSubqueryCache", true);
public static final boolean OPTIMIZE_NOT = getBooleanSetting("h2.optimizeNot", true);
......@@ -62,7 +66,7 @@ public class SysProperties {
public static final int LOB_FILES_PER_DIRECTORY = getIntSetting("h2.lobFilesPerDirectory", 256);
public static final boolean NEW_DISPLAY_SIZE = getBooleanSetting("h2.newDisplaySize", true);
public static final int DEFAULT_MAX_OPERATION_MEMORY = getIntSetting("h2.defaultMaxOperationMemory", 100000);
private static boolean getBooleanSetting(String name, boolean defaultValue) {
String s = System.getProperty(name);
if (s != null) {
......@@ -73,12 +77,12 @@ public class SysProperties {
}
return defaultValue;
}
private static String getStringSetting(String name, String defaultValue) {
String s = System.getProperty(name);
return s == null ? defaultValue : s;
}
private static int getIntSetting(String name, int defaultValue) {
String s = System.getProperty(name);
if (s != null) {
......@@ -89,7 +93,7 @@ public class SysProperties {
}
return defaultValue;
}
/**
* INTERNAL
*/
......@@ -99,7 +103,7 @@ public class SysProperties {
}
baseDir = dir;
}
/**
* INTERNAL
*/
......
......@@ -6,6 +6,7 @@ package org.h2.expression;
import java.sql.SQLException;
import org.h2.command.dml.Select;
import org.h2.constant.SysProperties;
import org.h2.engine.Session;
import org.h2.message.Message;
......@@ -20,9 +21,6 @@ import org.h2.value.ValueNull;
*/
public class ConditionAndOr extends Condition {
// TODO optimization: we could extend (ID=1 AND ID=B) to (ID=1 AND ID=B AND
// B=1)
public static final int AND = 0, OR = 1;
private final int andOrType;
......@@ -221,5 +219,20 @@ public class ConditionAndOr extends Condition {
public int getCost() {
return left.getCost() + right.getCost();
}
public Expression optimizeInJoin(Session session, Select select) throws SQLException {
if (andOrType == AND) {
Expression l = left.optimizeInJoin(session, select);
Expression r = right.optimizeInJoin(session, select);
if (l != left || r != right) {
left = l;
right = r;
// only optimize again if there was some change
// otherwise some expressions are 'over-optimized'
return optimize(session);
}
}
return this;
}
}
......@@ -6,12 +6,16 @@ package org.h2.expression;
import java.sql.SQLException;
import org.h2.command.dml.Select;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.index.IndexCondition;
import org.h2.schema.Schema;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.FunctionTable;
import org.h2.table.TableFilter;
import org.h2.util.ObjectArray;
import org.h2.value.CompareMode;
......@@ -200,4 +204,36 @@ public class ConditionIn extends Condition {
return cost;
}
public Expression optimizeInJoin(Session session, Select select) throws SQLException {
if (!areAllValues(ExpressionVisitor.get(ExpressionVisitor.EVALUATABLE))) {
return this;
}
Database db = session.getDatabase();
Schema mainSchema = db.getSchema(Constants.SCHEMA_MAIN);
Function function = Function.getFunction(database, "TABLE_DISTINCT");
Expression[] array = new Expression[values.size()];
for (int i = 0; i < values.size(); i++) {
Expression e = (Expression) values.get(i);
array[i] = e;
}
ExpressionList list = new ExpressionList(array);
function.setParameter(0, list);
function.doneWithParameters();
ObjectArray columns = new ObjectArray();
int dataType = left.getType();
String columnName = session.getNextTempViewName() + "_X";
Column col = new Column(columnName, dataType);
columns.add(col);
function.setColumns(columns);
FunctionTable table = new FunctionTable(mainSchema, session, function);
String viewName = session.getNextTempViewName();
TableFilter filter = new TableFilter(session, table, viewName, false, select);
select.addTableFilter(filter, true);
ExpressionColumn column = new ExpressionColumn(db, null, viewName, columnName);
Comparison on = new Comparison(session, Comparison.EQUAL, left, column);
on.mapColumns(filter, 0);
filter.addFilterCondition(on, true);
return ValueExpression.get(ValueBoolean.get(true));
}
}
......@@ -7,6 +7,7 @@ package org.h2.expression;
import java.sql.SQLException;
import org.h2.command.dml.Query;
import org.h2.command.dml.Select;
import org.h2.constant.ErrorCode;
import org.h2.engine.Database;
import org.h2.engine.Session;
......@@ -14,6 +15,7 @@ import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.table.TableView;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull;
......@@ -122,4 +124,26 @@ public class ConditionInSelect extends Condition {
return left.getCost() + 10 + (int) (10 * query.getCost());
}
public Expression optimizeInJoin(Session session, Select select) throws SQLException {
if (all || compareType != Comparison.EQUAL) {
return this;
}
if (!query.isEverything(ExpressionVisitor.EVALUATABLE)) {
return this;
}
String alias = query.getFirstColumnAlias(session);
query.setDistinct(true);
if (alias == null) {
return this;
}
TableView view = TableView.createTempView(session, session.getUser(), query);
TableFilter filter = new TableFilter(session, view, view.getName(), false, select);
select.addTableFilter(filter, true);
ExpressionColumn column = new ExpressionColumn(session.getDatabase(), null, view.getName(), alias);
Comparison on = new Comparison(session, Comparison.EQUAL, left, column);
on.mapColumns(filter, 0);
filter.addFilterCondition(on, true);
return ValueExpression.get(ValueBoolean.get(true));
}
}
......@@ -6,6 +6,7 @@ package org.h2.expression;
import java.sql.SQLException;
import org.h2.command.dml.Select;
import org.h2.engine.Session;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
......@@ -103,4 +104,12 @@ public abstract class Expression {
addedToFilter = true;
}
}
public String toString() {
return getSQL();
}
public Expression optimizeInJoin(Session session, Select select) throws SQLException {
return this;
}
}
......@@ -32,12 +32,12 @@ public class ExpressionColumn extends Expression {
private Column column;
private boolean evaluatable;
public ExpressionColumn(Database database, Select select, Column column) {
public ExpressionColumn(Database database, Column column) {
this.database = database;
this.column = column;
}
public ExpressionColumn(Database database, Select select, String schemaName, String tableAlias, String columnName) {
public ExpressionColumn(Database database, String schemaName, String tableAlias, String columnName) {
this.database = database;
this.schemaName = schemaName;
this.tableAlias = tableAlias;
......@@ -184,7 +184,7 @@ public class ExpressionColumn extends Expression {
public long getPrecision() {
return column.getPrecision();
}
public int getDisplaySize() {
return column.getDisplaySize();
}
......
......@@ -21,6 +21,7 @@ import org.h2.engine.Database;
import org.h2.engine.Mode;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.schema.Sequence;
import org.h2.security.BlockCipher;
import org.h2.security.CipherFactory;
......@@ -31,14 +32,12 @@ import org.h2.table.LinkSchema;
import org.h2.table.TableFilter;
import org.h2.tools.CompressTool;
import org.h2.tools.Csv;
import org.h2.tools.SimpleResultSet;
import org.h2.util.ObjectUtils;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.util.RandomUtils;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
......@@ -85,7 +84,7 @@ public class Function extends Expression implements FunctionCall {
public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, COALESCE = 204, NULLIF = 205,
CASE = 206, NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211,
MEMORY_FREE = 212, MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217,
LINK_SCHEMA = 218, TABLE = 219, LEAST = 220, GREATEST = 221;
LINK_SCHEMA = 218, TABLE = 219, LEAST = 220, GREATEST = 221, TABLE_DISTINCT = 222;
private static final int VAR_ARGS = -1;
......@@ -286,6 +285,7 @@ public class Function extends Expression implements FunctionCall {
addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET);
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT, VAR_ARGS, Value.RESULT_SET);
addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL);
}
......@@ -817,14 +817,16 @@ public class Function extends Expression implements FunctionCall {
return ValueResultSet.get(rs);
}
case TABLE:
return getTable(session, args, false);
return getTable(session, args, false, false);
case TABLE_DISTINCT:
return getTable(session, args, false, true);
case CSVWRITE: {
session.getUser().checkAdmin();
Connection conn = session.createConnection(false);
String charset = v2 == null ? null : v2.getString();
String fieldSeparatorWrite = v3 == null ? null : v3.getString();
String fieldDelimiter = v4 == null ? null : v4.getString();
String escapeCharacter = v5 == null ? null : v5.getString();
String escapeCharacter = v5 == null ? null : v5.getString();
Csv csv = Csv.getInstance();
setCsvDelimiterEscape(csv, fieldSeparatorWrite, fieldDelimiter, escapeCharacter);
int rows = csv.write(conn, v0.getString(), v1.getString(), charset);
......@@ -1266,6 +1268,7 @@ public class Function extends Expression implements FunctionCall {
case COALESCE:
case CSVREAD:
case TABLE:
case TABLE_DISTINCT:
case LEAST:
case GREATEST:
min = 1;
......@@ -1438,14 +1441,14 @@ public class Function extends Expression implements FunctionCall {
}
return precision;
}
public int getDisplaySize() {
if (precision == 0) {
calculatePrecisionAndDisplaySize();
}
return displaySize;
}
private void calculatePrecisionAndDisplaySize() {
switch (info.type) {
case ENCRYPT:
......@@ -1529,6 +1532,7 @@ public class Function extends Expression implements FunctionCall {
buff.append(args[1].getSQL());
break;
}
case TABLE_DISTINCT:
case TABLE: {
for (int i = 0; i < args.length; i++) {
if (i > 0) {
......@@ -1597,14 +1601,17 @@ public class Function extends Expression implements FunctionCall {
return vr;
}
case TABLE: {
return getTable(session, args, true);
return getTable(session, args, true, false);
}
case TABLE_DISTINCT: {
return getTable(session, args, true, true);
}
default:
break;
}
return (ValueResultSet) getValueWithArgs(session, args);
}
private void setCsvDelimiterEscape(Csv csv, String fieldSeparator, String fieldDelimiter, String escapeCharacter) {
if (fieldSeparator != null) {
csv.setFieldSeparatorWrite(fieldSeparator);
......@@ -1648,19 +1655,21 @@ public class Function extends Expression implements FunctionCall {
return cost;
}
public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList) throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList, boolean distinct) throws SQLException {
int len = columnList.length;
Expression[] header = new Expression[len];
Database db = session.getDatabase();
for (int i = 0; i < len; i++) {
Column c = columnList[i];
String columnName = c.getName();
int dataType = DataType.convertTypeToSQLType(c.getType());
int precision = MathUtils.convertLongToInt(c.getPrecision());
int scale = c.getScale();
rs.addColumn(columnName, dataType, precision, scale);
ExpressionColumn col = new ExpressionColumn(db, c);
header[i] = col;
}
LocalResult result = new LocalResult(session, header, len);
if (distinct) {
result.setDistinct();
}
if (!onlyColumnList) {
Value[][] list = new Value[args.length][];
Value[][] list = new Value[len][];
int rowCount = 0;
for (int i = 0; i < len; i++) {
Value v = args[i].getValue(session);
......@@ -1674,7 +1683,7 @@ public class Function extends Expression implements FunctionCall {
}
}
for (int row = 0; row < rowCount; row++) {
Object[] r = new Object[len];
Value[] r = new Value[len];
for (int j = 0; j < len; j++) {
Value[] l = list[j];
Value v;
......@@ -1687,12 +1696,13 @@ public class Function extends Expression implements FunctionCall {
v = v.convertPrecision(c.getPrecision());
v = v.convertScale(true, c.getScale());
}
r[j] = v.getObject();
r[j] = v;
}
rs.addRow(r);
result.addRow(r);
}
}
ValueResultSet vr = ValueResultSet.get(rs);
result.done();
ValueResultSet vr = ValueResultSet.getCopy(result, Integer.MAX_VALUE);
return vr;
}
......
......@@ -391,7 +391,7 @@ userString, passwordString, originalTableString)
","
Creates a table link to an external table.
The driver name may be empty if the driver is already loaded.
Usually, for update statements, the old rows are deleted first
Usually, for update statements, the old rows are deleted first
and then the new rows inserted. It is possible to emit update
statements (however this is not possible on rollback), however
in this case multi-row unique key updates may not always work.
......@@ -426,7 +426,7 @@ CREATE SEQUENCE [IF NOT EXISTS] newSequenceName
[CACHE long]
","
Creates a new sequence. The data type of a sequence is BIGINT.
The cache is the number of pre-allocated numbers. If the system crashes without closing the
The cache is the number of pre-allocated numbers. If the system crashes without closing the
database, at most this many numbers are lost. The default cache size is 32.
","
CREATE SEQUENCE SEQ_ID
......@@ -933,7 +933,7 @@ SET MAX_MEMORY_ROWS 1000
SET MAX_MEMORY_UNDO int
","
The maximum number of undo records per a session that are kept in-memory.
If a transaction is larger, the records are buffered to disk. The default value is 100000.
If a transaction is larger, the records are buffered to disk. The default value is 100000.
Changes to tables without a primary key can not be buffered to disk.
This setting is persistent.
Admin rights are required to execute this command.
......@@ -1177,7 +1177,7 @@ TEST AS T LEFT JOIN TEST AS T1 ON T.ID = T1.ID
{int | expression} [ASC | DESC]
[NULLS {FIRST | LAST}]
","
Sorts the result by the given column number, or by an expression.
Sorts the result by the given column number, or by an expression.
If the expression is a single parameter, then the value is interpreted
as a column number. Negative column numbers reverse the sort order.
","
......@@ -1215,7 +1215,7 @@ compare { {{ALL|ANY|SOME}(select)} | operand }
| [NOT] LIKE operand [ESCAPE string]
| [NOT] REGEXP operand
","
The right hand side of a condition.
The right hand side of a condition.
When comparing with LIKE, the wildcards characters are _ (any one character) and % (any characters).
When comparing with REGEXP, regular expression matching is used. See Java Matcher.find for details.
","
......@@ -2636,7 +2636,7 @@ LOCK_TIMEOUT()
"
"Functions (System)","LINK_SCHEMA","
LINK_SCHEMA(targetSchemaString, driverString, urlString,
LINK_SCHEMA(targetSchemaString, driverString, urlString,
userString, passwordString, sourceSchemaString): resultSet
","
Creates table links for all tables in a schema.
......@@ -2724,9 +2724,9 @@ CALL SESSION_ID()
"
"Functions (System)","TABLE","
TABLE( { name dataType = expression } [,..]): result set
TABLE|TABLE_DISTINCT( { name dataType = expression } [,..]): result set
","
Returns the result set.
Returns the result set. TABLE_DISTINCT removes duplicate rows.
","
SELECT * FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World'))
"
......
......@@ -55,7 +55,7 @@ public class LocalResult implements ResultInterface {
int scale = meta.getScale(i + 1);
int displaySize = meta.getColumnDisplaySize(i + 1);
Column col = new Column(name, type, precision, scale, displaySize);
Expression expr = new ExpressionColumn(db, null, col);
Expression expr = new ExpressionColumn(db, col);
cols.add(expr);
}
LocalResult result = new LocalResult(session, cols, columnCount);
......@@ -108,7 +108,17 @@ public class LocalResult implements ResultInterface {
return updateCount;
}
public LocalResult(Session session, ObjectArray cols, int visibleColumnCount) {
public LocalResult(Session session, ObjectArray expressionList, int visibleColumnCount) {
this(session, getList(expressionList), visibleColumnCount);
}
private static Expression[] getList(ObjectArray expressionList) {
Expression[] expressions = new Expression[expressionList.size()];
expressionList.toArray(expressions);
return expressions;
}
public LocalResult(Session session, Expression[] expressions, int visibleColumnCount) {
this.session = session;
if (session == null) {
this.maxMemoryRows = Integer.MAX_VALUE;
......@@ -118,9 +128,8 @@ public class LocalResult implements ResultInterface {
rows = new ObjectArray();
this.visibleColumnCount = visibleColumnCount;
rowId = -1;
this.expressions = new Expression[cols.size()];
cols.toArray(expressions);
this.displaySizes = new int[cols.size()];
this.expressions = expressions;
this.displaySizes = new int[expressions.length];
}
public void setSortOrder(SortOrder sort) {
......@@ -128,9 +137,8 @@ public class LocalResult implements ResultInterface {
}
public void setDistinct() {
// TODO big result sets: how to buffer distinct result sets? maybe do
// the
// distinct when sorting each block, and final merging
// TODO big result sets: how to buffer distinct result sets?
// maybe remove duplicates when sorting each block, and when merging
distinctRows = new ValueHashMap(session.getDatabase());
}
......@@ -340,7 +348,7 @@ public class LocalResult implements ResultInterface {
}
}
}
public String toString() {
return "columns: " + visibleColumnCount + " rows: " + rowCount + " pos: " + rowId;
}
......
......@@ -55,6 +55,7 @@ public class WebServer implements Service {
{ "pt_BR", "Portugu\u00eas (Brasil)"},
{ "pt_PT", "Portugu\u00eas (Europeu)"},
{ "ru", "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"},
{ "uk", "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
{ "zh_CN", "\u4E2D\u6587"},
};
......@@ -76,6 +77,8 @@ public class WebServer implements Service {
};
/*
String[] list = Locale.getISOLanguages();
for(int i=0; i<list.length; i++) System.out.print(list[i] + " ");
String lang = new java.util.Locale("hu").getDisplayLanguage(new java.util.Locale("hu"));
java.util.Locale.CHINESE.getDisplayLanguage(
java.util.Locale.CHINESE);
......
......@@ -392,7 +392,7 @@ public class TableFilter implements ColumnResolver {
}
}
buff.append(table.getSQL());
if (alias != null && !table.getName().equals(alias)) {
if (alias != null) {
buff.append(' ');
buff.append(Parser.quoteIdentifier(alias));
}
......@@ -422,7 +422,7 @@ public class TableFilter implements ColumnResolver {
String condition = StringUtils.unEnclose(filterCondition.getSQL());
condition = StringUtils.quoteRemarkSQL(condition);
buff.append(condition);
buff.append("*/");
buff.append(" */");
}
return buff.toString();
}
......
......@@ -307,4 +307,15 @@ public class TableView extends Table {
return owner;
}
public static TableView createTempView(Session s, User owner, Query query) throws SQLException {
String tempViewName = s.getNextTempViewName();
Schema mainSchema = s.getDatabase().getSchema(Constants.SCHEMA_MAIN);
String querySQL = query.getPlanSQL();
TableView v = new TableView(mainSchema, 0, tempViewName, querySQL, query.getParameters(), null, s,
false);
v.setOwner(owner);
v.setTemporary(true);
return v;
}
}
......@@ -56,13 +56,13 @@ public class DataType {
public int defaultDisplaySize;
public boolean hidden;
public int memory;
// for operations that include different types, convert both to the higher order
public int order;
// JDK 1.3 compatibility: Types.BOOLEAN
public static final int TYPE_BOOLEAN = 16;
// JDK 1.3 compatibility: Types.DATALINK
public static final int TYPE_DATALINK = 70;
......@@ -74,7 +74,7 @@ public class DataType {
if (TYPE_DATALINK != Types.DATALINK) {
new Exception("Types.DATALINK: " + Types.DATALINK).printStackTrace();
}
//#endif
add(Value.NULL, Types.NULL, "Null",
new DataType(),
......@@ -558,6 +558,8 @@ public class DataType {
return Value.CLOB;
case Types.NULL:
return Value.NULL;
case Types.ARRAY:
return Value.ARRAY;
default:
throw Message.getSQLException(ErrorCode.UNKNOWN_DATA_TYPE_1, ""+sqlType);
}
......
......@@ -10,21 +10,45 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils;
public class ValueResultSet extends Value {
private final ResultSet result;
private ValueResultSet(ResultSet rs) {
this.result = rs;
}
public static ValueResultSet get(ResultSet rs) throws SQLException {
ValueResultSet val = new ValueResultSet(rs);
return val;
}
public static ValueResultSet getCopy(LocalResult rs, int maxrows) throws SQLException {
int columnCount = rs.getVisibleColumnCount();
SimpleResultSet simple = new SimpleResultSet();
ValueResultSet val = new ValueResultSet(simple);
for (int i = 0; i < columnCount; i++) {
String name = rs.getColumnName(i);
int sqlType = DataType.convertTypeToSQLType(rs.getColumnType(i));
int precision = MathUtils.convertLongToInt(rs.getColumnPrecision(i));
int scale = rs.getColumnScale(i);
simple.addColumn(name, sqlType, precision, scale);
}
rs.reset();
for (int i = 0; i < maxrows && rs.next(); i++) {
Object[] list = new Object[columnCount];
for (int j = 0; j < columnCount; j++) {
list[j] = rs.currentRow()[j].getObject();
}
simple.addRow(list);
}
return val;
}
public static ValueResultSet getCopy(ResultSet rs, int maxrows) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int columnCount = meta.getColumnCount();
......@@ -97,7 +121,7 @@ public class ValueResultSet extends Value {
public Object getObject() throws SQLException {
return result;
}
public ResultSet getResultSet() {
return result;
}
......@@ -108,6 +132,6 @@ public class ValueResultSet extends Value {
public String getSQL() {
return "";
}
}
}
......@@ -104,7 +104,7 @@ import org.h2.tools.Server;
import org.h2.util.StringUtils;
/**
* The main test application. JUnit is not used because loops are easier to write in
* The main test application. JUnit is not used because loops are easier to write in
* regular java applications (most tests are ran multiple times using different settings).
*/
public class TestAll {
......@@ -117,7 +117,7 @@ public class TestAll {
/*
Random test:
cd bin
del *.db
start cmd /k "java -cp .;%H2DRIVERS% org.h2.test.TestAll join >testJoin.txt"
......@@ -142,18 +142,42 @@ java org.h2.test.TestAll timer
private Server server;
public boolean cache2Q;
public static void main(String[] args) throws Exception {
long time = System.currentTimeMillis();
TestAll test = new TestAll();
test.printSystem();
test.printSystem();
/*
create table test(id int, name varchar);
insert into test select x, '' from system_range(1, 10000);
-- fast
update test set name = 'y' where cast(id as varchar) like '1%';
-- slow
update test set name = 'x' where id in (select x from system_range(1, 10000) where cast(x as varchar) like '1%');
drop table test;
Optimize IN(...), IN(select), ID=? OR ID=?: create temp table and use join
Bug:
H2 1.0.62 (2007-11-25) has regressed on this query. Parser syntax error is returned (query is OK for derby, oracle, and earlier H2 versions).
SELECT COUNT(*) FROM (
SELECT TT.id,TT.table_name FROM (
SELECT DISTINCT id, table_name FROM information_schema.tables WHERE id=-8 UNION SELECT DISTINCT id, table_name FROM information_schema.tables WHERE id=-8) AS TT
) AS AWR WHERE AWR.id=-8
Remove the final predicate and the query parses & runs fine:
SELECT COUNT(*) FROM (
SELECT TT.id,TT.table_name FROM (
SELECT DISTINCT id, table_name FROM information_schema.tables WHERE id=-8 UNION SELECT DISTINCT id, table_name FROM information_schema.tables WHERE id=-8) AS TT
) AS AWR
write more tests for the command line tools
Changelog:
Certain setting in the Server didn't work (see bug...)
avoid creating thousands of trace.db files
......@@ -161,21 +185,10 @@ Known Problems:
link to history page, bug page
Add a link to the google code bug page
History:
implement & test: checkpoint commits running transactions
test DbStarter
create table test(id int, name varchar);
insert into test select x, '' from system_range(1, 10000);
-- fast
update test set name = 'y' where cast(id as varchar) like '1%';
-- slow
update test set name = 'x' where id in (select x from system_range(1, 10000) where cast(x as varchar) like '1%');
drop table test;
----
A file is sent although the Japanese translation has not been completed yet.
----
......@@ -183,17 +196,17 @@ A file is sent although the Japanese translation has not been completed yet.
At startup, when corrupted, say if LOG=0 was used before
slow:
select ta.attname, ia.attnum, ic.relname
from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n
where ic.relname = 'dummy_pkey'
AND n.nspname = ''
AND ic.oid = i.indexrelid
AND n.oid = ic.relnamespace
AND ia.attrelid = i.indexrelid
AND ta.attrelid = i.indrelid
AND ta.attnum = i.indkey[ia.attnum-1]
AND (NOT ta.attisdropped)
AND (NOT ia.attisdropped)
select ta.attname, ia.attnum, ic.relname
from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n
where ic.relname = 'dummy_pkey'
AND n.nspname = ''
AND ic.oid = i.indexrelid
AND n.oid = ic.relnamespace
AND ia.attrelid = i.indexrelid
AND ta.attrelid = i.indrelid
AND ta.attnum = i.indkey[ia.attnum-1]
AND (NOT ta.attisdropped)
AND (NOT ia.attisdropped)
order by ia.attnum;
DROP TABLE IF EXISTS TEST;
......@@ -229,7 +242,7 @@ move Products that Work with H2 > Comparison
move Performance Tuning > Advanced Topics
testHalt
java org.h2.test.TestAll halt
java org.h2.test.TestAll halt
timer test
......@@ -237,18 +250,18 @@ java.lang.Exception: query was too quick; result: 0 time:968
at org.h2.test.TestBase.logError(TestBase.java:220)
at org.h2.test.db.TestCases$1.run(TestCases.java:170)
at java.lang.Thread.run(Thread.java:595)
ftp server: problem with multithreading?
h2\src\docsrc\html\images\SQLInjection.txt
send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide,
send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide,
Send SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,...
Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
MySQL, PostgreSQL
READ_TEXT(fileName String) returning a CLOB.
I am not sure if this will read the CLOB in memory however.
READ_TEXT(fileName String) returning a CLOB.
I am not sure if this will read the CLOB in memory however.
Improve LOB in directories performance
......@@ -270,8 +283,8 @@ translated .pdf
write tests using the PostgreSQL JDBC driver
*/
*/
// run TestHalt
// GroovyServlet
......@@ -292,13 +305,13 @@ write tests using the PostgreSQL JDBC driver
// long running test with the same database
// repeatable test with a very big database (making backups of the database files)
/*
Features of H2
- Case insensitive string data type
- GROUP_CONCAT aggregate, User defined aggregates
*/
*/
if (args.length > 0) {
if ("crash".equals(args[0])) {
new TestCrashAPI().runTest(test);
......@@ -331,7 +344,7 @@ Features of H2
}
void runTests() throws Exception {
// TODO test set lock_mode=0, 1; max_trace_file_size; modes; collation; assert
// TODO test shutdown immediately
......@@ -353,7 +366,7 @@ Features of H2
// big = true;
// memory = false;
//
testQuick();
testCombination();
......@@ -405,7 +418,7 @@ Features of H2
logMode = 1;
cipher = null;
mvcc = false;
cache2Q = false;
cache2Q = false;
testAll();
diskUndo = false;
......@@ -420,9 +433,9 @@ Features of H2
logMode = 1;
cipher = null;
mvcc = false;
cache2Q = false;
cache2Q = false;
testAll();
big = false;
smallLog = false;
networked = false;
......@@ -437,8 +450,8 @@ Features of H2
throttle = 0;
cipher = null;
mvcc = false;
cache2Q = false;
testAll();
cache2Q = false;
testAll();
diskUndo = true;
smallLog = false;
......@@ -452,7 +465,7 @@ Features of H2
throttle = 1;
cipher = "XTEA";
mvcc = false;
cache2Q = false;
cache2Q = false;
testAll();
diskUndo = false;
......@@ -470,7 +483,7 @@ Features of H2
throttle = 0;
cipher = null;
mvcc = false;
cache2Q = false;
cache2Q = false;
testAll();
big = true;
......@@ -487,9 +500,9 @@ Features of H2
throttle = 0;
cipher = null;
mvcc = false;
cache2Q = true;
cache2Q = true;
testAll();
big = true;
smallLog = false;
networked = true;
......@@ -504,19 +517,19 @@ Features of H2
throttle = 0;
cipher = "AES";
mvcc = false;
cache2Q = false;
cache2Q = false;
testAll();
smallLog = big = networked = memory = ssl = textStorage = diskResult = deleteIndex = traceSystemOut = false;
traceLevelFile = throttle = 0;
logMode = 1;
cipher = null;
mvcc = true;
cache2Q = false;
cache2Q = false;
testAll();
}
void testAll() throws Exception {
DeleteDbFiles.execute(TestBase.baseDir, null, true);
testDatabase();
......@@ -553,7 +566,7 @@ Features of H2
void testDatabase() throws Exception {
System.out.println("test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc);
beforeTest();
// int testMvcc;
// mvcc = true;
......
......@@ -23,7 +23,7 @@ public class TestBigResult extends TestBase {
testOrderGroup();
testLimitBufferedResult();
}
private void testLargeUpdateDelete() throws Exception {
deleteDb("bigResult");
Connection conn = getConnection("bigResult");
......
......@@ -27,7 +27,9 @@ import org.h2.tools.Server;
import org.h2.util.Resources;
public class TestTools extends TestBase {
private Server server;
public void test() throws Exception {
deleteDb("utils");
testServerMain();
......@@ -41,20 +43,20 @@ public class TestTools extends TestBase {
testBackupRestore();
testRecover();
}
private void testServerMain() throws Exception {
String result;
Connection conn;
org.h2.Driver.load();
result = runServer(new String[]{"-?"}, 1);
check(result.indexOf("[options]") >= 0);
check(result.indexOf("Unknown option") < 0);
result = runServer(new String[]{"-xy"}, 1);
check(result.indexOf("[options]") >= 0);
check(result.indexOf("Unknown option") >= 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "false", "-tcpPort", "9001", "-tcpPassword", "abc"}, 0);
check(result.indexOf("tcp://") >= 0);
check(result.indexOf(":9001") >= 0);
......@@ -64,29 +66,50 @@ public class TestTools extends TestBase {
conn.close();
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9001", "-tcpPassword", "abc", "-tcpShutdownForce", "true"}, 0);
check(result.indexOf("Shutting down") >= 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "true", "-tcpPort", "9001", "-tcpPassword", "def", "-tcpSSL", "true"}, 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "true", "-tcpPort", "9001", "-tcpPassword", "abcdef", "-tcpSSL", "true"}, 0);
check(result.indexOf("ssl://") >= 0);
check(result.indexOf(":9001") >= 0);
check(result.indexOf("others can") >= 0);
check(result.indexOf("[options]") < 0);
conn = DriverManager.getConnection("jdbc:h2:ssl://localhost:9001/mem:", "sa", "sa");
conn.close();
result = runServer(new String[]{"-tcpShutdown", "ssl://localhost:9001", "-tcpPassword", "def", "-tcpShutdownForce", "false"}, 0);
result = runServer(new String[]{"-tcpShutdown", "ssl://localhost:9001", "-tcpPassword", "abcdef", "-tcpShutdownForce", "false"}, 0);
check(result.indexOf("Shutting down") >= 0);
result = runServer(new String[]{
"-web", "-webPort", "9002", "-webAllowOthers", "true", "-webSSL", "true",
"-pg", "-pgAllowOthers", "true", "-pgPort", "9003",
"-ftp", "-ftpPort", "9004", "-ftpDir", ".", "-ftpRead", "guest", "-ftpWrite", "sa", "-ftpWritePassword", "sa", "-ftpTask", "true",
"-tcp", "-tcpAllowOthers", "true", "-tcpPort", "9005", "-tcpPassword", "abc"}, 0);
Server stop = server;
check(result.indexOf("https://") >= 0);
check(result.indexOf(":9002") >= 0);
check(result.indexOf("pg://") >= 0);
check(result.indexOf(":9003") >= 0);
check(result.indexOf("others can") >= 0);
check(result.indexOf("only local") < 0);
check(result.indexOf("ftp://") >= 0);
check(result.indexOf(":9004") >= 0);
check(result.indexOf("tcp://") >= 0);
check(result.indexOf(":9005") >= 0);
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9005", "-tcpPassword", "abc", "-tcpShutdownForce", "true"}, 0);
check(result.indexOf("Shutting down") >= 0);
stop.shutdown();
}
private String runServer(String[] args, int exitCode) throws Exception {
ByteArrayOutputStream buff = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(buff);
int gotCode = new Server().run(args, ps);
server = new Server();
int gotCode = server.run(args, ps);
check(exitCode, gotCode);
ps.flush();
String s = new String(buff.toByteArray());
return s;
}
private void testConvertTraceFile() throws Exception {
deleteDb("toolsConvertTraceFile");
Class.forName("org.h2.Driver");
......@@ -96,7 +119,7 @@ public class TestTools extends TestBase {
stat.execute("create table test(id int primary key, name varchar)");
stat.execute("insert into test values(1, 'Hello')");
conn.close();
ConvertTraceFile.main(new String[]{"-traceFile", baseDir + "/toolsConvertTraceFile.trace.db", "-javaClass", baseDir + "/Test", "-script", baseDir + "/test.sql"});
new File(baseDir + "/Test.java").delete();
......@@ -108,13 +131,13 @@ public class TestTools extends TestBase {
deleteDb("toolsConvertTraceFile");
Player.main(new String[]{baseDir + "/test.trace.db"});
testTraceFile(url);
deleteDb("toolsConvertTraceFile");
RunScript.main(new String[]{"-url", url, "-user", "sa", "-script", baseDir + "/test.sql"});
testTraceFile(url);
}
private void testTraceFile(String url) throws Exception {
Connection conn;
Recover.main(new String[]{"-removePassword", "-log", "false", "-dir", baseDir, "-db", "toolsConvertTraceFile"});
......@@ -147,7 +170,7 @@ public class TestTools extends TestBase {
check("Hello", rs.getString(2));
conn.close();
}
private void testRecover() throws Exception {
Class.forName("org.h2.Driver");
String url = "jdbc:h2:" + baseDir + "/toolsRecover";
......@@ -160,7 +183,7 @@ public class TestTools extends TestBase {
rs.next();
byte[] b1 = rs.getBytes(3);
String s1 = rs.getString(4);
conn.close();
Recover.main(new String[]{"-dir", baseDir, "-db", "toolsRecover"});
deleteDb("toolsRecover");
......@@ -257,6 +280,7 @@ public class TestTools extends TestBase {
private void testServer() throws Exception {
Connection conn;
deleteDb("test");
Server server = Server.createTcpServer(new String[] { "-ifExists", "false", "-baseDir", baseDir }).start();
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", "");
conn.close();
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.tools.i18n;
public class AutoTranslate {
}
......@@ -13,10 +13,19 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.Map.Entry;
import org.h2.server.web.PageParser;
import org.h2.tools.doc.XMLParser;
import org.h2.util.FileUtils;
......@@ -24,13 +33,10 @@ import org.h2.util.IOUtils;
import org.h2.util.SortedProperties;
import org.h2.util.StringUtils;
//import com.google.api.translate.Language;
//import com.google.api.translate.Translate;
public class PrepareTranslation {
private static final String MAIN_LANGUAGE = "en";
private static final String DELETED_PREFIX = "~";
private static final boolean AUTO_TRANSLATE = false;
private static final boolean AUTO_TRANSLATE = true;
public static void main(String[] args) throws Exception {
new PrepareTranslation().run(args);
......@@ -55,7 +61,7 @@ public class PrepareTranslation {
// create the translated documentation
buildHtml("src/docsrc/text", "docs/html", "en");
// buildHtml("src/docsrc/text", "docs/html", "de");
buildHtml("src/docsrc/text", "docs/html", "de");
buildHtml("src/docsrc/text", "docs/html", "ja");
// convert the properties files back to utf8 text files, including the
......@@ -414,6 +420,7 @@ public class PrepareTranslation {
oldTranslations.setProperty(m, t);
}
}
HashSet toTranslate = new HashSet();
// add missing keys, using # and the value from the main file
Iterator it = main.keySet().iterator();
while (it.hasNext()) {
......@@ -422,11 +429,10 @@ public class PrepareTranslation {
if (!p.containsKey(key)) {
String t = oldTranslations.getProperty(now);
if (t == null) {
System.out.println(trans.getName() + ": key " + key
+ " not found in translation file; added dummy # 'translation'");
t = "#" + autoTranslate(now, language);
toTranslate.add(key);
} else {
p.put(key, t);
}
p.put(key, t);
} else {
String t = p.getProperty(key);
String last = base.getProperty(key);
......@@ -440,19 +446,42 @@ public class PrepareTranslation {
} else if (last != null && !last.equals(now)) {
t = oldTranslations.getProperty(now);
if (t == null) {
// main data changed since the last run: review
// translation
// main data changed since the last run: review translation
System.out.println(trans.getName() + ": key " + key + " changed, please review; last=" + last
+ " now=" + now);
String old = p.getProperty(key);
t = "#" + autoTranslate(now, language) + " #" + old;
// String old = p.getProperty(key);
toTranslate.add(key);
} else {
p.put(key, t);
}
p.put(key, t);
}
}
}
// remove keys that don't exist in the main file (deleted or typo in the
// key)
Map autoTranslated = new HashMap();
if (AUTO_TRANSLATE) {
HashSet set = new HashSet();
for (it = toTranslate.iterator(); it.hasNext();) {
String key = (String) it.next();
String now = main.getProperty(key);
set.add(now);
}
if ("de".equals(language)) {
autoTranslated = autoTranslate(set, "en", language);
}
}
for (it = toTranslate.iterator(); it.hasNext();) {
String key = (String) it.next();
String now = main.getProperty(key);
String t;
if (AUTO_TRANSLATE) {
t = "#" + autoTranslated.get(now);
} else {
System.out.println(trans.getName() + ": key " + key + " not found in translation file; added dummy # 'translation'");
t = "#" + now;
}
p.put(key, t);
}
// remove keys that don't exist in the main file (deleted or typo in the key)
it = new ArrayList(p.keySet()).iterator();
while (it.hasNext()) {
String key = (String) it.next();
......@@ -471,26 +500,87 @@ public class PrepareTranslation {
}
PropertiesToUTF8.storeProperties(p, trans.getAbsolutePath());
}
private Map autoTranslate(Set toTranslate, String sourceLanguage, String targetLanguage) {
HashMap results = new HashMap();
if (toTranslate.size() == 0) {
return results;
}
int maxLength = 1500;
int minSeparator = 100000;
HashMap keyMap = new HashMap(toTranslate.size());
StringBuffer buff = new StringBuffer(maxLength);
// TODO make sure these numbers don't occur in the original text
int separator = minSeparator;
for (Iterator it = toTranslate.iterator(); it.hasNext();) {
String original = (String) it.next();
if (original != null) {
original = original.trim();
if (buff.length() + original.length() > maxLength) {
System.out.println("remaining: " + (toTranslate.size() - separator + minSeparator));
translateChunk(buff, separator, sourceLanguage, targetLanguage, keyMap, results);
}
keyMap.put(new Integer(separator), original);
buff.append(separator);
buff.append(' ');
buff.append(original);
buff.append(' ');
separator++;
}
}
translateChunk(buff, separator, sourceLanguage, targetLanguage, keyMap, results);
return results;
}
private String autoTranslate(String original, String language) {
if (original == null || original.trim().length() == 0) {
return original;
private void translateChunk(StringBuffer buff, int separator, String source, String target, HashMap keyMap, HashMap results) {
buff.append(separator);
String original = buff.toString();
String translation = "";
try {
translation = translate(original, source, target);
System.out.println("original: " + original);
System.out.println("translation: " + translation);
} catch (Throwable e) {
System.out.println("Exception translating [" + original + "]: " + e);
e.printStackTrace();
}
String translation = original;
if (!AUTO_TRANSLATE) {
return "#" + translation;
for (Iterator it = keyMap.entrySet().iterator(); it.hasNext();) {
Entry entry = (Entry) it.next();
separator = ((Integer) entry.getKey()).intValue();
String o = (String) entry.getValue();
String startSeparator = String.valueOf(separator);
int start = translation.indexOf(startSeparator);
int end = translation.indexOf(String.valueOf(separator + 1));
if (start < 0 || end < 0) {
System.out.println("No translation for " + o);
results.put(o, "#" + o);
} else {
String t = translation.substring(start + startSeparator.length(), end);
t = t.trim();
results.put(o, t);
}
}
// if ("de".equals(language)) {
// try {
// Thread.sleep(5000);
// translation = Translate.translate(original, Language.ENGLISH, Language.GERMAN);
// System.out.println("original: " + original);
// System.out.println("translation: " + translation);
// } catch (Throwable e) {
// System.out.println("Exception translating [" + original + "]: " + e);
// // e.printStackTrace();
// }
// }
return "#" + translation;
keyMap.clear();
buff.setLength(0);
}
/**
* Translate the text using Google
*/
String translate(String text, String sourceLanguage, String targetLanguage) throws Exception {
Thread.sleep(4000);
String url = "http://translate.google.com/translate_t?langpair=" + sourceLanguage + "|" + targetLanguage + "&text="
+ URLEncoder.encode(text, "UTF-8");
HttpURLConnection conn = (HttpURLConnection) (new URL(url)).openConnection();
// conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
int todoTest;
// conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.10) Gecko/20071115 Firefox/2.0.0.10");
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; Java)");
String result = IOUtils.readStringAndClose(IOUtils.getReader(conn.getInputStream()), -1);
int start = result.indexOf("<div id=result_box");
start = result.indexOf('>', start) + 1;
int end = result.indexOf("</div>", start);
return result.substring(start, end);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论