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

--no commit message

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