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

--no commit message

--no commit message
上级 bcaeb7f4
...@@ -37,20 +37,25 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -37,20 +37,25 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / TODO (Build TODO)</h3><ul> <h3>Version 1.0 / TODO (Build TODO)</h3><ul>
<li>If SHUTDOWN IMMEDIATELY was called, then the connection was not closed and the database <li>PooledConnection.getConnection took a long time if only one connection was open at any time. Fixed.
opened from somebody else at the same time, in some cases this could result in errors with LOB files. Fixed. </li><li>Referential integrity violation: Two different SQL states are now used for missing parent / existing child.
</li><li>DatabaseEventListener.exceptionThrown has a new parameter: SQL
</li><li>For compatibility reasons, the catalog name can now be used in queries: SELECT * FROM TESTDB.PUBLIC.TEST
</li><li>If SHUTDOWN IMMEDIATELY was called, then the connection was not closed and the database
opened from somebody else at the same time, in some cases this could result in errors with LOB files. Fixed.
</li><li>The new view implementation is now enabled by default. </li><li>The new view implementation is now enabled by default.
To use the old implementation, set the system property 'h2.indexOld' to true To use the old implementation, set the system property 'h2.indexOld' to true
(java -Dh2.indexOld=true ..., or in source code Constants.INDEX_OLD = true). (java -Dh2.indexOld=true ..., or in source code Constants.INDEX_OLD = true).
If no problems are found, the old implementation will be removed in the next release. If no problems are found, the old implementation will be removed in the next release.
The old implementation does not work with multi-level nested temporary views The old implementation does not work with multi-level nested temporary views
(select * from (select * from (select * from test))). (select * from (select * from (select * from test))).
</li><li>The new view implementation did not work with &lt; and &lt;= comparison. Fixed. </li><li>The new view implementation did not work with &lt; and &lt;= comparison,
and did not allow conditions on aggregates or grouped columns (HAVING). Fixed.. Fixed.
</li><li>Both view implementations did not work with multiple levels of nested temporary views (FROM (SELECT...)). Fixed. </li><li>Both view implementations did not work with multiple levels of nested temporary views (FROM (SELECT...)). Fixed.
</li><li>The H2 Console can now be run as a standalone web application, </li><li>The H2 Console can now be run as a standalone web application,
or it can be embedded as a servlet into any existing web application. To build the or it can be embedded as a servlet into any existing web application. To build the
'H2 Console' web application, execute 'ant warConsole'. 'H2 Console' web application, execute 'ant warConsole'.
See src/tools/org/h2/server/web and src/tools/WEB-INF for details. See src/tools/org/h2/server/web and src/tools/WEB-INF for details.
</li><li>Deleting database files didn't work for Windows if the database was on the root directory of a drive. </li><li>Deleting database files didn't work for Windows if the database was on the root directory of a drive.
</li><li>The Polish translation is available. Thanks a lot to Tomek! </li><li>The Polish translation is available. Thanks a lot to Tomek!
</li><li>Windows service: the CLASSPATH was not included when starting the service. Fixed. </li><li>Windows service: the CLASSPATH was not included when starting the service. Fixed.
...@@ -878,6 +883,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -878,6 +883,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Performance / server mode: use UDP optionally? </li><li>Performance / server mode: use UDP optionally?
</li><li>Version check: docs / web console (using javascript), and maybe in the library (using TCP/IP) </li><li>Version check: docs / web console (using javascript), and maybe in the library (using TCP/IP)
</li><li>Aggregates: support MEDIAN </li><li>Aggregates: support MEDIAN
</li><li>Option to globally disable / enable referential integrity checks
</li><li>Web server classloader: override findResource / getResourceFrom </li><li>Web server classloader: override findResource / getResourceFrom
</li><li>Cost for embedded temporary view is calculated wrong, if result is constant </li><li>Cost for embedded temporary view is calculated wrong, if result is constant
</li><li>Comparison: pluggable sort order: natural sort </li><li>Comparison: pluggable sort order: natural sort
...@@ -1027,7 +1033,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -1027,7 +1033,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Support ARRAY data type </li><li>Support ARRAY data type
</li><li>Implement more JDBC 4.0 features </li><li>Implement more JDBC 4.0 features
</li><li>H2 Console: implement a servlet to allow simple web app integration </li><li>H2 Console: implement a servlet to allow simple web app integration
</li><li>Option to globally disable / enable referential integrity checks
</li><li>Support ISO 8601 timestamp / date / time with timezone </li><li>Support ISO 8601 timestamp / date / time with timezone
</li><li>Support TRANSFORM / PIVOT as in MS Access </li><li>Support TRANSFORM / PIVOT as in MS Access
</li><li>Sequence: PostgreSQL compatibility (rename, create) (http://www.postgresql.org/docs/8.2/static/sql-altersequence.html) </li><li>Sequence: PostgreSQL compatibility (rename, create) (http://www.postgresql.org/docs/8.2/static/sql-altersequence.html)
......
...@@ -39,11 +39,12 @@ public interface DatabaseEventListener extends EventListener { ...@@ -39,11 +39,12 @@ public interface DatabaseEventListener extends EventListener {
void diskSpaceIsLow(long stillAvailable) throws SQLException; void diskSpaceIsLow(long stillAvailable) throws SQLException;
/** /**
* This method is called if an exception occurred. * This method is called if an exception occurred during database recovery
* *
* @param e the exception * @param e the exception
* @param sql the SQL statement
*/ */
void exceptionThrown(SQLException e); void exceptionThrown(SQLException e, String sql);
/** /**
* This method is called for long running events, such as recovering, scanning a file or building an index. * This method is called for long running events, such as recovering, scanning a file or building an index.
......
...@@ -23,14 +23,16 @@ public abstract class Command implements CommandInterface { ...@@ -23,14 +23,16 @@ public abstract class Command implements CommandInterface {
protected long startTime; protected long startTime;
protected Trace trace; protected Trace trace;
private volatile boolean cancel; private volatile boolean cancel;
private final String sql;
public abstract boolean isTransactional(); public abstract boolean isTransactional();
public abstract boolean isQuery(); public abstract boolean isQuery();
public abstract ObjectArray getParameters(); public abstract ObjectArray getParameters();
public abstract boolean isReadOnly(); public abstract boolean isReadOnly();
public Command(Parser parser) { public Command(Parser parser, String sql) {
this.session = parser.getSession(); this.session = parser.getSession();
this.sql = sql;
trace = session.getDatabase().getTrace(Trace.COMMAND); trace = session.getDatabase().getTrace(Trace.COMMAND);
} }
...@@ -42,21 +44,6 @@ public abstract class Command implements CommandInterface { ...@@ -42,21 +44,6 @@ public abstract class Command implements CommandInterface {
throw Message.getSQLException(Message.METHOD_ONLY_ALLOWED_FOR_QUERY); throw Message.getSQLException(Message.METHOD_ONLY_ALLOWED_FOR_QUERY);
} }
// TODO insert parameters into the original query, or allow this syntax
// if(parameters != null && parameters.size() > 0) {
// buff.append(" /* ");
// for(int i=0; i<parameters.size(); i++) {
// if(i>0) {
// buff.append(", ");
// }
// Parameter param = (Parameter) parameters.get(i);
// buff.append(i+1);
// buff.append(" = ");
// buff.append(param.getSQL());
// }
// buff.append(" */");
// }
public ResultInterface executeQuery(int maxrows, boolean scrollable) throws SQLException { public ResultInterface executeQuery(int maxrows, boolean scrollable) throws SQLException {
return executeQueryLocal(maxrows); return executeQueryLocal(maxrows);
} }
...@@ -73,7 +60,7 @@ public abstract class Command implements CommandInterface { ...@@ -73,7 +60,7 @@ public abstract class Command implements CommandInterface {
return result; return result;
} catch(Throwable e) { } catch(Throwable e) {
SQLException s = Message.convert(e); SQLException s = Message.convert(e);
database.exceptionThrown(s); database.exceptionThrown(s, sql);
throw s; throw s;
} finally { } finally {
stop(); stop();
...@@ -119,7 +106,7 @@ public abstract class Command implements CommandInterface { ...@@ -119,7 +106,7 @@ public abstract class Command implements CommandInterface {
int result = update(); int result = update();
return result; return result;
} catch (SQLException e) { } catch (SQLException e) {
database.exceptionThrown(e); database.exceptionThrown(e, sql);
database.checkPowerOff(); database.checkPowerOff();
session.rollbackTo(rollback); session.rollbackTo(rollback);
throw e; throw e;
...@@ -136,5 +123,8 @@ public abstract class Command implements CommandInterface { ...@@ -136,5 +123,8 @@ public abstract class Command implements CommandInterface {
public void cancel() { public void cancel() {
this.cancel = true; this.cancel = true;
} }
public String getSQL() {
return null;
}
} }
...@@ -16,8 +16,8 @@ public class CommandContainer extends Command { ...@@ -16,8 +16,8 @@ public class CommandContainer extends Command {
private Prepared prepared; private Prepared prepared;
CommandContainer(Parser parser, Prepared prepared) { CommandContainer(Parser parser, String sql, Prepared prepared) {
super(parser); super(parser, sql);
prepared.setCommand(this); prepared.setCommand(this);
this.prepared = prepared; this.prepared = prepared;
} }
......
...@@ -16,8 +16,8 @@ public class CommandList extends Command { ...@@ -16,8 +16,8 @@ public class CommandList extends Command {
// TODO lock if possible! // TODO lock if possible!
public CommandList(Parser parser, Command c, String remaining) { public CommandList(Parser parser, String sql, Command c, String remaining) {
super(parser); super(parser, sql);
this.command = c; this.command = c;
this.remaining = remaining; this.remaining = remaining;
} }
......
...@@ -152,6 +152,7 @@ public class Parser { ...@@ -152,6 +152,7 @@ public class Parser {
private char[] sqlCommandChars; private char[] sqlCommandChars;
private int lastParseIndex; private int lastParseIndex;
private int parseIndex; private int parseIndex;
private Prepared prepared;
private Prepared currentPrepared; private Prepared currentPrepared;
private Select currentSelect; private Select currentSelect;
private Session session; private Session session;
...@@ -191,12 +192,12 @@ public class Parser { ...@@ -191,12 +192,12 @@ public class Parser {
try { try {
Prepared p = parse(sql); Prepared p = parse(sql);
p.prepare(); p.prepare();
Command c = new CommandContainer(this, p); Command c = new CommandContainer(this, sql, p);
p.setCommand(c); p.setCommand(c);
if (isToken(";")) { if (isToken(";")) {
String remaining = originalSQL.substring(parseIndex); String remaining = originalSQL.substring(parseIndex);
if(remaining.trim().length()!=0) { if(remaining.trim().length()!=0) {
CommandList list = new CommandList(this, c, remaining); CommandList list = new CommandList(this, sql, c, remaining);
// list.addCommand(c); // list.addCommand(c);
// do { // do {
// c = parseCommand(); // c = parseCommand();
...@@ -243,6 +244,7 @@ public class Parser { ...@@ -243,6 +244,7 @@ public class Parser {
int start = lastParseIndex; int start = lastParseIndex;
currentSelect = null; currentSelect = null;
currentPrepared = null; currentPrepared = null;
prepared = null;
Prepared c = null; Prepared c = null;
recompileAlways = false; recompileAlways = false;
indexedParameterList = null; indexedParameterList = null;
...@@ -740,10 +742,18 @@ public class Parser { ...@@ -740,10 +742,18 @@ public class Parser {
if(isToken("SELECT") || isToken("FROM")) { if(isToken("SELECT") || isToken("FROM")) {
Query query = parseQueryWithParams(); Query query = parseQueryWithParams();
String querySQL = query.getSQL(); String querySQL = query.getSQL();
String tempViewName = session.getNextTempViewName(); Session s;
table = new TableView(mainSchema, 0, tempViewName, querySQL, query.getParameters(), null, session, false); if(prepared != null && prepared instanceof CreateView) {
table.setOnCommitDrop(true); s = database.getSystemSession();
session.addLocalTempTable(table); } else {
s = session;
}
String tempViewName = s.getNextTempViewName();
table = new TableView(mainSchema, 0, tempViewName, querySQL, query.getParameters(), null, s, false);
if(s != database.getSystemSession()) {
table.setOnCommitDrop(true);
}
s.addLocalTempTable(table);
read(")"); read(")");
} else { } else {
TableFilter top = readTableFilter(fromOuter); TableFilter top = readTableFilter(fromOuter);
...@@ -2051,6 +2061,15 @@ public class Parser { ...@@ -2051,6 +2061,15 @@ public class Parser {
s = currentToken; s = currentToken;
read(); read();
} }
if (".".equals(currentToken) && schemaName.equals(database.getShortName())) {
read(".");
schemaName = s;
if (currentTokenType != IDENTIFIER) {
throw Message.getSyntaxError(sqlCommand, parseIndex, "identifier");
}
s = currentToken;
read();
}
return s; return s;
} }
...@@ -3197,7 +3216,7 @@ public class Parser { ...@@ -3197,7 +3216,7 @@ public class Parser {
columns.add(new Column(cols[i], Value.STRING, 0, 0)); columns.add(new Column(cols[i], Value.STRING, 0, 0));
} }
int id = database.allocateObjectId(true, true); int id = database.allocateObjectId(true, true);
recursiveTable = new TableData(schema, tempViewName, id, columns, false); recursiveTable = schema.createTable(tempViewName, id, columns, false);
recursiveTable.setTemporary(true); recursiveTable.setTemporary(true);
session.addLocalTempTable(recursiveTable); session.addLocalTempTable(recursiveTable);
String querySQL = StringCache.getNew(sqlCommand.substring(parseIndex)); String querySQL = StringCache.getNew(sqlCommand.substring(parseIndex));
...@@ -3221,6 +3240,7 @@ public class Parser { ...@@ -3221,6 +3240,7 @@ public class Parser {
boolean ifNotExists = readIfNoExists(); boolean ifNotExists = readIfNoExists();
String viewName = readIdentifierWithSchema(); String viewName = readIdentifierWithSchema();
CreateView command = new CreateView(session, getSchema()); CreateView command = new CreateView(session, getSchema());
this.prepared = command;
command.setViewName(viewName); command.setViewName(viewName);
command.setIfNotExists(ifNotExists); command.setIfNotExists(ifNotExists);
command.setComment(readCommentIf()); command.setComment(readCommentIf());
......
...@@ -197,7 +197,7 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -197,7 +197,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
// can't just use this table, because most column objects are 'shared' with the old table // can't just use this table, because most column objects are 'shared' with the old table
// still need a new id because using 0 would mean: the new table tries to use the rows of the table 0 (the script table) // still need a new id because using 0 would mean: the new table tries to use the rows of the table 0 (the script table)
int id = -1; int id = -1;
TableData newTable = new TableData(getSchema(), tempName, id, newColumns, persistent); TableData newTable = getSchema().createTable(tempName, id, newColumns, persistent);
newTable.setComment(table.getComment()); newTable.setComment(table.getComment());
execute(newTable.getCreateSQL()); execute(newTable.getCreateSQL());
newTable = (TableData) newTable.getSchema().getTableOrView(session, newTable.getName()); newTable = (TableData) newTable.getSchema().getTableOrView(session, newTable.getName());
......
...@@ -70,7 +70,7 @@ public class CreateLinkedTable extends SchemaCommand { ...@@ -70,7 +70,7 @@ public class CreateLinkedTable extends SchemaCommand {
tableName); tableName);
} }
int id = getObjectId(false, true); int id = getObjectId(false, true);
TableLink table = new TableLink(getSchema(), id, tableName, driver, url, user, password, originalTable, emitUpdates, force); TableLink table = getSchema().createTableLink(id, tableName, driver, url, user, password, originalTable, emitUpdates, force);
table.setComment(comment); table.setComment(comment);
db.addSchemaObject(session, table); db.addSchemaObject(session, table);
return 0; return 0;
......
...@@ -119,7 +119,7 @@ public class CreateTable extends SchemaCommand { ...@@ -119,7 +119,7 @@ public class CreateTable extends SchemaCommand {
} }
} }
int id = getObjectId(true, true); int id = getObjectId(true, true);
TableData table = new TableData(getSchema(), tableName, id, columns, persistent); TableData table = getSchema().createTable(tableName, id, columns, persistent);
table.setComment(comment); table.setComment(comment);
table.setTemporary(temporary); table.setTemporary(temporary);
table.setGlobalTemporary(globalTemporary); table.setGlobalTemporary(globalTemporary);
......
...@@ -57,7 +57,8 @@ ...@@ -57,7 +57,8 @@
} else { } else {
querySQL = select.getSQL(); querySQL = select.getSQL();
} }
TableView view = new TableView(getSchema(), id, viewName, querySQL, null, columnNames, session, recursive); Session s = db.getSystemSession();
TableView view = new TableView(getSchema(), id, viewName, querySQL, null, columnNames, s, recursive);
view.setComment(comment); view.setComment(comment);
db.addSchemaObject(session, view); db.addSchemaObject(session, view);
return 0; return 0;
......
...@@ -277,6 +277,10 @@ public class Select extends Query { ...@@ -277,6 +277,10 @@ public class Select extends Query {
Value[] row = new Value[columnCount]; Value[] row = new Value[columnCount];
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression expr = (Expression) expressions.get(i); Expression expr = (Expression) expressions.get(i);
int testing;
if(expr == null) {
System.out.println("stop");
}
row[i] = expr.getValue(session); row[i] = expr.getValue(session);
} }
result.addRow(row); result.addRow(row);
...@@ -586,7 +590,12 @@ public class Select extends Query { ...@@ -586,7 +590,12 @@ public class Select extends Query {
buff.append(StringUtils.unEnclose(g.getSQL())); buff.append(StringUtils.unEnclose(g.getSQL()));
} }
} }
if(havingIndex >= 0) { if(having != null) {
// could be set after addGlobalCondition
// in this case the query is not run directly, just getPlanSQL is called
Expression h = having;
buff.append("\nHAVING " + StringUtils.unEnclose(h.getSQL()));
} else if(havingIndex >= 0) {
Expression h = exprList[havingIndex]; Expression h = exprList[havingIndex];
buff.append("\nHAVING " + StringUtils.unEnclose(h.getSQL())); buff.append("\nHAVING " + StringUtils.unEnclose(h.getSQL()));
} }
...@@ -674,7 +683,10 @@ public class Select extends Query { ...@@ -674,7 +683,10 @@ public class Select extends Query {
Expression comp = new Comparison(session, comparisonType, col, expr); Expression comp = new Comparison(session, comparisonType, col, expr);
comp = comp.optimize(session); comp = comp.optimize(session);
if(isGroupQuery) { if(isGroupQuery) {
if(having == null) { if(havingIndex >= 0) {
having = (Expression) expressions.get(havingIndex);
}
if(having == null) {
having = comp; having = comp;
} else { } else {
having = new ConditionAndOr(ConditionAndOr.AND, having, comp); having = new ConditionAndOr(ConditionAndOr.AND, having, comp);
......
...@@ -275,7 +275,7 @@ public class ConstraintReferential extends Constraint { ...@@ -275,7 +275,7 @@ public class ConstraintReferential extends Constraint {
check.setValue(refIdx, v.convertTo(refCol.getType())); check.setValue(refIdx, v.convertTo(refCol.getType()));
} }
if(!found(session, refIndex, check)) { if(!found(session, refIndex, check)) {
throw Message.getSQLException(Message.CHECK_CONSTRAINT_VIOLATED_1, getShortDescription()); throw Message.getSQLException(Message.REFERENTIAL_INTEGRITY_VIOLATED_PARENT_MISSING_1, getShortDescription());
} }
} }
...@@ -339,7 +339,7 @@ public class ConstraintReferential extends Constraint { ...@@ -339,7 +339,7 @@ public class ConstraintReferential extends Constraint {
check.setValue(idx, v); check.setValue(idx, v);
} }
if(found(session, index, check)) { if(found(session, index, check)) {
throw Message.getSQLException(Message.CHECK_CONSTRAINT_VIOLATED_1, getShortDescription()); throw Message.getSQLException(Message.REFERENTIAL_INTEGRITY_VIOLATED_CHILD_EXISTS_1, getShortDescription());
} }
} }
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
*/ */
package org.h2.engine; package org.h2.engine;
import org.h2.message.TraceSystem;
/* /*
* Coding rules: * Coding rules:
* - boolean CHECK = x > boolean CHECK = Database.CHECK * - boolean CHECK = x > boolean CHECK = Database.CHECK
...@@ -246,8 +248,9 @@ public class Constants { ...@@ -246,8 +248,9 @@ public class Constants {
public static int MAX_FILE_RETRY = Math.max(1, getIntSetting("h2.maxFileRetry", 16)); public static int MAX_FILE_RETRY = Math.max(1, getIntSetting("h2.maxFileRetry", 16));
public static boolean LOB_CLOSE_BETWEEN_READS = getBooleanSetting("h2.lobCloseBetweenReads", false); public static boolean LOB_CLOSE_BETWEEN_READS = getBooleanSetting("h2.lobCloseBetweenReads", false);
public static boolean INDEX_OLD = getBooleanSetting("h2.indexOld", false); public static boolean INDEX_OLD = getBooleanSetting("h2.indexOld", false);
public static final boolean INDEX_LOOKUP_NEW = getBooleanSetting("h2.indexLookupNew", true); public static final boolean INDEX_LOOKUP_NEW = getBooleanSetting("h2.indexLookupNew", true);
public static final boolean TRACE_IO = getBooleanSetting("h2.traceIO", false); public static final boolean TRACE_IO = getBooleanSetting("h2.traceIO", false);
public static final int DATASOURCE_TRACE_LEVEL = getIntSetting("h2.dataSourceTraceLevel", TraceSystem.ERROR);
public static boolean getBooleanSetting(String name, boolean defaultValue) { public static boolean getBooleanSetting(String name, boolean defaultValue) {
String s = System.getProperty(name); String s = System.getProperty(name);
......
...@@ -467,7 +467,7 @@ public class Database implements DataHandler { ...@@ -467,7 +467,7 @@ public class Database implements DataHandler {
cols.add(new Column("HEAD", Value.INT, 0, 0)); cols.add(new Column("HEAD", Value.INT, 0, 0));
cols.add(new Column("TYPE", Value.INT, 0, 0)); cols.add(new Column("TYPE", Value.INT, 0, 0));
cols.add(new Column("SQL", Value.STRING, 0, 0)); cols.add(new Column("SQL", Value.STRING, 0, 0));
meta = new TableData(mainSchema, "SYS", 0, cols, persistent); meta = mainSchema.createTable("SYS", 0, cols, persistent);
metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, new Column[]{columnId}, IndexType.createPrimaryKey(false, false), Index.EMPTY_HEAD, null); metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, new Column[]{columnId}, IndexType.createPrimaryKey(false, false), Index.EMPTY_HEAD, null);
objectIds.set(0); objectIds.set(0);
// there could be views on system tables, so they must be added first // there could be views on system tables, so they must be added first
...@@ -1269,10 +1269,10 @@ public class Database implements DataHandler { ...@@ -1269,10 +1269,10 @@ public class Database implements DataHandler {
} }
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
if(eventListener != null) { if(eventListener != null) {
try { try {
eventListener.exceptionThrown(e); eventListener.exceptionThrown(e, sql);
} catch(Exception e2) { } catch(Exception e2) {
// ignore this second (user made) exception // ignore this second (user made) exception
} }
......
...@@ -65,10 +65,10 @@ public class MetaRecord { ...@@ -65,10 +65,10 @@ public class MetaRecord {
command.setHeadPos(headPos); command.setHeadPos(headPos);
command.update(); command.update();
} catch(Throwable e) { } catch(Throwable e) {
SQLException s = Message.convert(e); SQLException s = Message.addSQL(Message.convert(e), sql);
db.getTrace(Trace.DATABASE).error(sql, s); db.getTrace(Trace.DATABASE).error(sql, s);
if(listener != null) { if(listener != null) {
listener.exceptionThrown(s); listener.exceptionThrown(s, sql);
// continue startup in this case // continue startup in this case
} else { } else {
throw s; throw s;
......
...@@ -284,9 +284,10 @@ public class SessionRemote implements SessionInterface, DataHandler { ...@@ -284,9 +284,10 @@ public class SessionRemote implements SessionInterface, DataHandler {
if (status == STATUS_ERROR) { if (status == STATUS_ERROR) {
String sqlstate = transfer.readString(); String sqlstate = transfer.readString();
String message = transfer.readString(); String message = transfer.readString();
String sql = transfer.readString();
int errorCode = transfer.readInt(); int errorCode = transfer.readInt();
String trace = transfer.readString(); String trace = transfer.readString();
throw new JdbcSQLException(message, sqlstate, errorCode, null, trace); throw new JdbcSQLException(message, sql, sqlstate, errorCode, null, trace);
} else if(status == STATUS_CLOSED) { } else if(status == STATUS_CLOSED) {
transferList = null; transferList = null;
} }
......
...@@ -339,7 +339,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -339,7 +339,7 @@ public class Function extends Expression implements FunctionCall {
varArgs.add(param); varArgs.add(param);
} else { } else {
if(index >= args.length) { if(index >= args.length) {
throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, ""+args.length); throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_2, new String[] {info.name, "" + args.length}, null);
} }
args[index] = param; args[index] = param;
} }
...@@ -947,7 +947,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -947,7 +947,7 @@ public class Function extends Expression implements FunctionCall {
private static int getDatePart(String part) throws SQLException { private static int getDatePart(String part) throws SQLException {
Integer p = (Integer) datePart.get(StringUtils.toUpperEnglish(part)); Integer p = (Integer) datePart.get(StringUtils.toUpperEnglish(part));
if(p==null) { if(p==null) {
throw Message.getSQLException(Message.INVALID_VALUE_2, new String[] { "part", part }, null); throw Message.getSQLException(Message.INVALID_VALUE_2, new String[] { "date part", part }, null);
} }
return p.intValue(); return p.intValue();
} }
...@@ -1057,7 +1057,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1057,7 +1057,7 @@ public class Function extends Expression implements FunctionCall {
// avoid out of memory // avoid out of memory
return s; return s;
} }
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer(s.length());
int start = 0; int start = 0;
int len = replace.length(); int len = replace.length();
while (true) { while (true) {
...@@ -1290,7 +1290,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1290,7 +1290,7 @@ public class Function extends Expression implements FunctionCall {
} }
boolean ok = (len >= min) && (len <= max); boolean ok = (len >= min) && (len <= max);
if(!ok) { if(!ok) {
throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, min + ".." + max); throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_2, new String[]{info.name, min + ".." + max}, null);
} }
args = new Expression[len]; args = new Expression[len];
varArgs.toArray(args); varArgs.toArray(args);
...@@ -1298,7 +1298,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1298,7 +1298,7 @@ public class Function extends Expression implements FunctionCall {
} else { } else {
int len = args.length; int len = args.length;
if(len>0 && args[len-1] == null) { if(len>0 && args[len-1] == null) {
throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_1, info.name + ": " + len); throw Message.getSQLException(Message.INVALID_PARAMETER_COUNT_2, new String[]{info.name, "" + len}, null);
} }
} }
} }
......
...@@ -1713,11 +1713,11 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat ...@@ -1713,11 +1713,11 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
/** /**
* Returns whether the catalog name in INSERT, UPDATE, DELETE is supported. * Returns whether the catalog name in INSERT, UPDATE, DELETE is supported.
* *
* @return false * @return true
*/ */
public boolean supportsCatalogsInDataManipulation() { public boolean supportsCatalogsInDataManipulation() {
debugCodeCall("supportsCatalogsInDataManipulation"); debugCodeCall("supportsCatalogsInDataManipulation");
return false; return true;
} }
/** /**
...@@ -1733,31 +1733,31 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat ...@@ -1733,31 +1733,31 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
/** /**
* Returns whether the catalog name in CREATE TABLE is supported. * Returns whether the catalog name in CREATE TABLE is supported.
* *
* @return false * @return true
*/ */
public boolean supportsCatalogsInTableDefinitions() { public boolean supportsCatalogsInTableDefinitions() {
debugCodeCall("supportsCatalogsInTableDefinitions"); debugCodeCall("supportsCatalogsInTableDefinitions");
return false; return true;
} }
/** /**
* Returns whether the catalog name in CREATE INDEX is supported. * Returns whether the catalog name in CREATE INDEX is supported.
* *
* @return false * @return true
*/ */
public boolean supportsCatalogsInIndexDefinitions() { public boolean supportsCatalogsInIndexDefinitions() {
debugCodeCall("supportsCatalogsInIndexDefinitions"); debugCodeCall("supportsCatalogsInIndexDefinitions");
return false; return true;
} }
/** /**
* Returns whether the catalog name in GRANT is supported. * Returns whether the catalog name in GRANT is supported.
* *
* @return false * @return true
*/ */
public boolean supportsCatalogsInPrivilegeDefinitions() { public boolean supportsCatalogsInPrivilegeDefinitions() {
debugCodeCall("supportsCatalogsInPrivilegeDefinitions"); debugCodeCall("supportsCatalogsInPrivilegeDefinitions");
return false; return true;
} }
/** /**
......
...@@ -16,9 +16,10 @@ import org.h2.engine.Constants; ...@@ -16,9 +16,10 @@ import org.h2.engine.Constants;
public class JdbcSQLException extends SQLException { public class JdbcSQLException extends SQLException {
private static final long serialVersionUID = -8200821788226954151L; private static final long serialVersionUID = -8200821788226954151L;
private Throwable cause; private final String originalMessage;
private String originalMessage; private final String sql;
private String trace; private final Throwable cause;
private final String trace;
/** /**
* Creates a SQLException a message, sqlstate and cause. * Creates a SQLException a message, sqlstate and cause.
...@@ -27,15 +28,25 @@ public class JdbcSQLException extends SQLException { ...@@ -27,15 +28,25 @@ public class JdbcSQLException extends SQLException {
* @param state the SQL state * @param state the SQL state
* @param cause the exception that was the reason for this exception * @param cause the exception that was the reason for this exception
*/ */
public JdbcSQLException(String message, String state, int errorCode, Throwable cause, String trace) { public JdbcSQLException(String message, String sql, String state, int errorCode, Throwable cause, String trace) {
super(message + " [" + state + "-" + Constants.BUILD_ID + "]", state, errorCode); super(buildMessage(message, sql, state), state, errorCode);
this.originalMessage = message; this.originalMessage = message;
this.sql = sql;
this.cause = cause; this.cause = cause;
this.trace = trace; this.trace = trace;
//#ifdef JDK14 //#ifdef JDK14
initCause(cause); initCause(cause);
//#endif //#endif
} }
private static String buildMessage(String message, String sql, String state) {
StringBuffer buff = new StringBuffer(message);
if(sql != null) {
buff.append("; SQL statement: ");
buff.append(sql);
}
return message + " [" + state + "-" + Constants.BUILD_ID + "]";
}
/** /**
* INTERNAL * INTERNAL
...@@ -110,6 +121,15 @@ public class JdbcSQLException extends SQLException { ...@@ -110,6 +121,15 @@ public class JdbcSQLException extends SQLException {
return cause; return cause;
} }
/**
* Returns the SQL statement.
*
* @return the SQL statement
*/
public String getSQL() {
return sql;
}
/** /**
* Returns the class name, the message, and in the server mode, the stack trace of the server * Returns the class name, the message, and in the server mode, the stack trace of the server
* *
......
...@@ -23,7 +23,7 @@ public class JdbcDataSourceFactory implements ObjectFactory { ...@@ -23,7 +23,7 @@ public class JdbcDataSourceFactory implements ObjectFactory {
static { static {
org.h2.Driver.load(); org.h2.Driver.load();
traceSystem = new TraceSystem(Constants.CLIENT_TRACE_DIRECTORY + "h2datasource" + Constants.SUFFIX_TRACE_FILE); traceSystem = new TraceSystem(Constants.CLIENT_TRACE_DIRECTORY + "h2datasource" + Constants.SUFFIX_TRACE_FILE);
traceSystem.setLevelFile(TraceSystem.DEBUG); traceSystem.setLevelFile(Constants.DATASOURCE_TRACE_LEVEL);
} }
public JdbcDataSourceFactory() { public JdbcDataSourceFactory() {
......
...@@ -39,6 +39,7 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -39,6 +39,7 @@ implements XAConnection, XAResource, JdbcConnectionListener
//#ifdef JDK14 //#ifdef JDK14
private JdbcDataSourceFactory factory; private JdbcDataSourceFactory factory;
private String url, user, password; private String url, user, password;
private JdbcConnection connSentinel;
private JdbcConnection conn; private JdbcConnection conn;
private ArrayList listeners = new ArrayList(); private ArrayList listeners = new ArrayList();
private Xid currentTransaction; private Xid currentTransaction;
...@@ -55,7 +56,8 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -55,7 +56,8 @@ implements XAConnection, XAResource, JdbcConnectionListener
this.url = url; this.url = url;
this.user = user; this.user = user;
this.password = password; this.password = password;
getConnection(); connSentinel = openConnection();
getConnection();
} }
public XAResource getXAResource() throws SQLException { public XAResource getXAResource() throws SQLException {
...@@ -65,19 +67,37 @@ implements XAConnection, XAResource, JdbcConnectionListener ...@@ -65,19 +67,37 @@ implements XAConnection, XAResource, JdbcConnectionListener
public void close() throws SQLException { public void close() throws SQLException {
debugCodeCall("close"); debugCodeCall("close");
try {
closeConnection(conn);
closeConnection(connSentinel);
} finally {
conn = null;
connSentinel = null;
}
}
private void closeConnection(JdbcConnection conn) throws SQLException {
if(conn != null) { if(conn != null) {
conn.closeConnection(); conn.closeConnection();
conn = null;
} }
} }
public Connection getConnection() throws SQLException { private JdbcConnection openConnection() throws SQLException {
debugCodeCall("getConnection");
close();
Properties info = new Properties(); Properties info = new Properties();
info.setProperty("user", user); info.setProperty("user", user);
info.setProperty("password", password); info.setProperty("password", password);
conn = new JdbcConnection(url, info); JdbcConnection conn = new JdbcConnection(url, info);
conn.setJdbcConnectionListener(this);
return conn;
}
public Connection getConnection() throws SQLException {
debugCodeCall("getConnection");
if(conn != null) {
closeConnection(conn);
conn = null;
}
conn = openConnection();
conn.setJdbcConnectionListener(this); conn.setJdbcConnectionListener(this);
return conn; return conn;
} }
......
...@@ -62,7 +62,7 @@ public class Message { ...@@ -62,7 +62,7 @@ public class Message {
public static JdbcSQLException getSQLException(int errorCode, String[] param, Throwable cause) { public static JdbcSQLException getSQLException(int errorCode, String[] param, Throwable cause) {
String sqlstate = getState(errorCode); String sqlstate = getState(errorCode);
String message = translate(sqlstate, param); String message = translate(sqlstate, param);
return new JdbcSQLException(message, sqlstate, errorCode, cause, null); return new JdbcSQLException(message, null, sqlstate, errorCode, cause, null);
} }
public static SQLException getSyntaxError(String sql, int index) { public static SQLException getSyntaxError(String sql, int index) {
...@@ -119,7 +119,7 @@ public class Message { ...@@ -119,7 +119,7 @@ public class Message {
case NO_DATA_AVAILABLE: return "02000"; case NO_DATA_AVAILABLE: return "02000";
// 07: dynamic SQL error // 07: dynamic SQL error
case INVALID_PARAMETER_COUNT_1: return "07001"; case INVALID_PARAMETER_COUNT_2: return "07001";
// 08: connection exception // 08: connection exception
case ERROR_OPENING_DATABASE: return "08000"; case ERROR_OPENING_DATABASE: return "08000";
...@@ -128,17 +128,6 @@ public class Message { ...@@ -128,17 +128,6 @@ public class Message {
// 21: cardinality violation // 21: cardinality violation
case COLUMN_COUNT_DOES_NOT_MATCH: return "21S02"; case COLUMN_COUNT_DOES_NOT_MATCH: return "21S02";
// 22: data exception
case NUMERIC_VALUE_OUT_OF_RANGE: return "22003";
case DIVISION_BY_ZERO_1: return "22012";
case LIKE_ESCAPE_ERROR_1: return "22025";
// 23: integrity constraint violation
case CHECK_CONSTRAINT_VIOLATED_1: return "23000";
case DUPLICATE_KEY_1: return "23001"; // integrity constraint violation
// 3B: savepoint exception
// 42: syntax error or access rule violation // 42: syntax error or access rule violation
case SYNTAX_ERROR_1: return "42000"; case SYNTAX_ERROR_1: return "42000";
case SYNTAX_ERROR_2: return "42001"; case SYNTAX_ERROR_2: return "42001";
...@@ -154,7 +143,7 @@ public class Message { ...@@ -154,7 +143,7 @@ public class Message {
// HZ: remote database access // HZ: remote database access
// // HY
case GENERAL_ERROR_1: return "HY000"; case GENERAL_ERROR_1: return "HY000";
case UNKNOWN_DATA_TYPE_1: return "HY004"; case UNKNOWN_DATA_TYPE_1: return "HY004";
...@@ -169,7 +158,7 @@ public class Message { ...@@ -169,7 +158,7 @@ public class Message {
public static final int NO_DATA_AVAILABLE = 2000; public static final int NO_DATA_AVAILABLE = 2000;
// 07: dynamic SQL error // 07: dynamic SQL error
public static final int INVALID_PARAMETER_COUNT_1 = 7001; public static final int INVALID_PARAMETER_COUNT_2 = 7001;
// 08: connection exception // 08: connection exception
public static final int ERROR_OPENING_DATABASE = 8000; public static final int ERROR_OPENING_DATABASE = 8000;
...@@ -185,8 +174,10 @@ public class Message { ...@@ -185,8 +174,10 @@ public class Message {
// 23: integrity constraint violation // 23: integrity constraint violation
public static final int CHECK_CONSTRAINT_VIOLATED_1 = 23000; public static final int CHECK_CONSTRAINT_VIOLATED_1 = 23000;
public static final int DUPLICATE_KEY_1 = 23001; // integrity constraint violation public static final int DUPLICATE_KEY_1 = 23001;
public static final int REFERENTIAL_INTEGRITY_VIOLATED_PARENT_MISSING_1 = 23002;
public static final int REFERENTIAL_INTEGRITY_VIOLATED_CHILD_EXISTS_1 = 23003;
// 3B: savepoint exception // 3B: savepoint exception
// 42: syntax error or access rule violation // 42: syntax error or access rule violation
...@@ -341,16 +332,16 @@ public class Message { ...@@ -341,16 +332,16 @@ public class Message {
public static final int RESULT_SET_NOT_UPDATABLE = 90127; public static final int RESULT_SET_NOT_UPDATABLE = 90127;
public static SQLException addSQL(SQLException e, String sql) { public static SQLException addSQL(SQLException e, String sql) {
if(e.getMessage().indexOf("SQL")>=0) {
return e;
}
if(e instanceof JdbcSQLException) { if(e instanceof JdbcSQLException) {
JdbcSQLException j = (JdbcSQLException) e; JdbcSQLException j = (JdbcSQLException) e;
return new JdbcSQLException(j.getOriginalMessage()+"; SQL statement: "+sql, if(j.getSQL() != null) {
return j;
}
return new JdbcSQLException(j.getOriginalMessage(), j.getSQL(),
j.getSQLState(), j.getSQLState(),
j.getErrorCode(), j, null); j.getErrorCode(), j, null);
} else { } else {
return new JdbcSQLException(e.getMessage()+"; SQL statement: "+sql, return new JdbcSQLException(e.getMessage(), sql,
e.getSQLState(), e.getSQLState(),
e.getErrorCode(), e, null); e.getErrorCode(), e, null);
} }
......
...@@ -709,7 +709,7 @@ SET AUTOCOMMIT OFF ...@@ -709,7 +709,7 @@ SET AUTOCOMMIT OFF
SET CACHE_SIZE int SET CACHE_SIZE int
"," ","
Sets the size of the cache. Sets the size of the cache.
A cache entry contains about 128 bytes. The default value is 32768. A cache entry contains about 128 bytes. The default value is 65536.
This setting is persistent and affects all connections as there is only one cache per database. This setting is persistent and affects all connections as there is only one cache per database.
Admin rights are required to execute this command. Admin rights are required to execute this command.
This setting can be appended to the database URL: jdbc:h2:test;CACHE_SIZE=8192 This setting can be appended to the database URL: jdbc:h2:test;CACHE_SIZE=8192
......
# If the word 'SQL' appears then the whole SQL statement must be a parameter. Otherwise this may be added: '; SQL statement: ' + sql # If the word 'SQL' appears then the whole SQL statement must be a parameter. Otherwise this may be added: '; SQL statement: ' + sql
02000=No data is available 02000=No data is available
07001=Invalid parameter count, expected count: {0} 07001=Invalid parameter count for {0}, expected count: {1}
08000=Error opening database 08000=Error opening database
08004=Wrong user name or password 08004=Wrong user name or password
21S02=Column count does not match 21S02=Column count does not match
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
22025=Error in LIKE ESCAPE: {0} 22025=Error in LIKE ESCAPE: {0}
23000=Check constraint violation: {0} 23000=Check constraint violation: {0}
23001=Unique index or primary key violation: {0} 23001=Unique index or primary key violation: {0}
23002=Referential integrity constraint violation: {0}
23003=Referential integrity constraint violation: {0}
42000=Syntax error in SQL statement {0} 42000=Syntax error in SQL statement {0}
42001=Syntax error in SQL statement {0}; expected {1} 42001=Syntax error in SQL statement {0}; expected {1}
42S01=Table {0} already exists 42S01=Table {0} already exists
......
...@@ -18,6 +18,8 @@ import org.h2.jdbc.JdbcSQLException; ...@@ -18,6 +18,8 @@ import org.h2.jdbc.JdbcSQLException;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableData;
import org.h2.table.TableLink;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
public class Schema extends DbObject { public class Schema extends DbObject {
...@@ -250,5 +252,13 @@ public class Schema extends DbObject { ...@@ -250,5 +252,13 @@ public class Schema extends DbObject {
} }
map.remove(objName); map.remove(objName);
} }
public TableData createTable(String tempName, int id, ObjectArray newColumns, boolean persistent) throws SQLException {
return new TableData(this, tempName, id, newColumns, persistent);
}
public TableLink createTableLink(int id, String tableName, String driver, String url, String user, String password, String originalTable, boolean emitUpdates, boolean force) throws SQLException {
return new TableLink(this, id, tableName, driver, url, user, password, originalTable, emitUpdates, force);
}
} }
...@@ -130,14 +130,19 @@ public class TcpServerThread implements Runnable { ...@@ -130,14 +130,19 @@ public class TcpServerThread implements Runnable {
e.printStackTrace(new PrintWriter(writer)); e.printStackTrace(new PrintWriter(writer));
String trace = writer.toString(); String trace = writer.toString();
String message; String message;
String sql;
if(e instanceof JdbcSQLException) { if(e instanceof JdbcSQLException) {
message = ((JdbcSQLException) e).getOriginalMessage(); JdbcSQLException j = (JdbcSQLException) e;
message = j.getOriginalMessage();
sql = j.getSQL();
} else { } else {
message = e.getMessage(); message = e.getMessage();
sql = null;
} }
transfer.writeInt(SessionRemote.STATUS_ERROR). transfer.writeInt(SessionRemote.STATUS_ERROR).
writeString(s.getSQLState()). writeString(s.getSQLState()).
writeString(message). writeString(message).
writeString(sql).
writeInt(s.getErrorCode()). writeInt(s.getErrorCode()).
writeString(trace). writeString(trace).
flush(); flush();
......
...@@ -83,7 +83,7 @@ public class LogFile { ...@@ -83,7 +83,7 @@ public class LogFile {
} }
String s = fileName.substring(fileNamePrefix.length()+1, fileName.length()-Constants.SUFFIX_LOG_FILE.length()); String s = fileName.substring(fileNamePrefix.length()+1, fileName.length()-Constants.SUFFIX_LOG_FILE.length());
int id = Integer.parseInt(s); int id = Integer.parseInt(s);
return new LogFile(log, id, fileNamePrefix); return new LogFile(log, id, fileNamePrefix);
} }
public String getFileName() { public String getFileName() {
......
...@@ -12,6 +12,7 @@ import org.h2.api.DatabaseEventListener; ...@@ -12,6 +12,7 @@ import org.h2.api.DatabaseEventListener;
import org.h2.engine.Constants; 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.message.Trace;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
...@@ -217,7 +218,15 @@ public class LogSystem { ...@@ -217,7 +218,15 @@ public class LogSystem {
activeLogs = new ObjectArray(); activeLogs = new ObjectArray();
for (int i = 0; i < list.length; i++) { for (int i = 0; i < list.length; i++) {
String s = list[i]; String s = list[i];
LogFile l = LogFile.openIfLogFile(this, fileNamePrefix, s); LogFile l = null;
try {
l = LogFile.openIfLogFile(this, fileNamePrefix, s);
} catch(SQLException e) {
database.getTrace(Trace.LOG).debug("Error opening log file, header corrupt: "+s, e);
// this can happen if the system crashes just after creating a new file (before writing the header)
// rename it, so that it doesn't get in the way the next time
FileUtils.rename(s, s + ".corrupt");
}
if (l != null) { if (l != null) {
if (l.getPos() == LOG_WRITTEN) { if (l.getPos() == LOG_WRITTEN) {
closeOldFile(l); closeOldFile(l);
......
...@@ -241,7 +241,7 @@ public class Csv implements SimpleRowSource { ...@@ -241,7 +241,7 @@ public class Csv implements SimpleRowSource {
return data; return data;
} }
} }
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer(data.length());
for(int i=0; i<data.length(); i++) { for(int i=0; i<data.length(); i++) {
char ch = data.charAt(i); char ch = data.charAt(i);
if(ch == fieldDelimiter || ch == escapeCharacter) { if(ch == fieldDelimiter || ch == escapeCharacter) {
...@@ -405,7 +405,7 @@ public class Csv implements SimpleRowSource { ...@@ -405,7 +405,7 @@ public class Csv implements SimpleRowSource {
} }
private String unEscape(String s) { private String unEscape(String s) {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer(s.length());
int start = 0; int start = 0;
while(true) { while(true) {
int idx = s.indexOf(escapeCharacter, start); int idx = s.indexOf(escapeCharacter, start);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.h2.util; package org.h2.util;
public class ClassUtils { public class ClassUtils {
public static Class loadClass(String className) throws ClassNotFoundException { public static Class loadClass(String className) throws ClassNotFoundException {
// TODO support special syntax to load classes using another classloader // TODO support special syntax to load classes using another classloader
return Class.forName(className); return Class.forName(className);
......
...@@ -223,7 +223,7 @@ public class StringUtils { ...@@ -223,7 +223,7 @@ public class StringUtils {
if(array == null) { if(array == null) {
return "null"; return "null";
} }
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer(5 * array.length);
buff.append("new String[]{"); buff.append("new String[]{");
for(int i=0; i<array.length; i++) { for(int i=0; i<array.length; i++) {
if(i>0) { if(i>0) {
...@@ -339,7 +339,7 @@ public class StringUtils { ...@@ -339,7 +339,7 @@ public class StringUtils {
} }
public static String arrayCombine(String[] list, char separatorChar) { public static String arrayCombine(String[] list, char separatorChar) {
StringBuffer buff=new StringBuffer(); StringBuffer buff=new StringBuffer(5 * list.length);
for(int i=0;i<list.length;i++) { for(int i=0;i<list.length;i++) {
if(i>0) { if(i>0) {
buff.append(separatorChar); buff.append(separatorChar);
...@@ -581,7 +581,8 @@ public class StringUtils { ...@@ -581,7 +581,8 @@ public class StringUtils {
} }
public static String quoteIdentifier(String s) { public static String quoteIdentifier(String s) {
StringBuffer buff = new StringBuffer("\""); StringBuffer buff = new StringBuffer(s.length() + 2);
buff.append('\"');
for(int i=0; i<s.length(); i++) { for(int i=0; i<s.length(); i++) {
char c = s.charAt(i); char c = s.charAt(i);
if(c == '"') { if(c == '"') {
......
...@@ -68,7 +68,8 @@ public class ShowProgress implements DatabaseEventListener { ...@@ -68,7 +68,8 @@ public class ShowProgress implements DatabaseEventListener {
System.out.println("diskSpaceIsLow stillAvailable="+stillAvailable); System.out.println("diskSpaceIsLow stillAvailable="+stillAvailable);
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
System.out.println("Error executing " + sql);
e.printStackTrace(); e.printStackTrace();
} }
......
...@@ -7,6 +7,7 @@ package org.h2.test; ...@@ -7,6 +7,7 @@ package org.h2.test;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Properties; import java.util.Properties;
import org.h2.message.TraceSystem;
import org.h2.server.TcpServer; import org.h2.server.TcpServer;
import org.h2.test.jdbc.*; import org.h2.test.jdbc.*;
import org.h2.test.jdbc.xa.TestXA; import org.h2.test.jdbc.xa.TestXA;
...@@ -93,46 +94,37 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -93,46 +94,37 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
test.printSystem(); test.printSystem();
/* /*
The database name must be at least 3 characters
jdbc:h2:te
runscript from 'C:\download\backup.sql'; traceSystem.setLevelFile(TraceSystem.ERROR);
alter table download_link add html_ltarget_ord INTEGER(10) default 0; because of temp file limitations, database names with less than 3 characters are not supported
alter table navigation_link add html_ltarget_ord INTEGER(10) default 0;
alter table web_link add html_ltarget_ord INTEGER(10) default 0;
ALTER TABLE navigation_page_content DROP COLUMN parent_type_id;
ALTER TABLE entity_info DROP COLUMN parent_type_id;
ALTER TABLE navigation_point_content DROP COLUMN parent_type_id;
ALTER TABLE paragraph_proxy DROP COLUMN parent_type_id;
ALTER TABLE patch DROP COLUMN parent_type_id;
ALTER TABLE page_content DROP COLUMN parent_type_id;
ALTER TABLE image_gallery_image_usage_ref DROP COLUMN ref_image_gallery;
ALTER TABLE navigation_page_content_reference DROP COLUMN ref_element_provider;
ALTER TABLE paragraph_proxy DROP COLUMN ref_page_content;
alter table navigation_page_content_reference add contained BOOLEAN(1) default false;
update navigation_page_content_reference set contained=true where state=7;
alter table navigation_page_content add contained BOOLEAN(1) default false;
update navigation_page_content set contained=true where state=7;
alter table navigation_point_content add contained BOOLEAN(1) default false;
update navigation_point_content set contained=true where state=7;
alter table weblica_link add contained BOOLEAN(1) default false;
update weblica_link set contained=true where state=7;
alter table image_usage add contained BOOLEAN(1) default false;
update image_usage set contained=true where state=7;
alter table paragraph_proxy add contained BOOLEAN(1) default false;
add test case:
prepare: select * from (select * from (select * from dual) a) b;
select * from dual;
execute prepared
add test case:
try to create a view without access rights
try to create a view with a subquery without access right
make sure INDEX_LOOKUP_NEW = is true by default.
Test Console (batch, javaw, different platforms)
test with openoffice (metadata changes)
testHalt
java org.h2.test.TestAll halt
>testHalt.txt
timer test
make sure INDEX_LOOKUP_NEW = is true by default. backup.sql / lob file problem
Test Console (batch, javaw, different platforms)
Change documentation and default database for H2 Console: jdbc:h2:~/test Change documentation and default database for H2 Console: jdbc:h2:~/test
testHalt
Mail http://sf.net/projects/samooha Mail http://sf.net/projects/samooha
java.lang.Exception: query was too quick; result: 0 time:968 java.lang.Exception: query was too quick; result: 0 time:968
...@@ -152,9 +144,8 @@ MySQL, PostgreSQL ...@@ -152,9 +144,8 @@ MySQL, PostgreSQL
http://semmle.com/ http://semmle.com/
try out, find bugs try out, find bugs
Currently there is no such feature, however it is quite simple to add a user defined function READ_TEXT(fileName String) returning a CLOB.
READ_TEXT(fileName String) returning a CLOB. The performance would probably not be optimal, I am not sure if this will read the CLOB in memory however.
but it should work. I am not sure if this will read the CLOB in memory however.
I will add this to the todo list. I will add this to the todo list.
Docs: Fix Quickstart Docs: Fix Quickstart
...@@ -176,21 +167,25 @@ Test Eclipse DTP 1.5 (HSQLDB / H2 connection bug fixed) ...@@ -176,21 +167,25 @@ Test Eclipse DTP 1.5 (HSQLDB / H2 connection bug fixed)
Automate real power off tests Automate real power off tests
how to make -baseDir work for H2 Console? how to make -baseDir work for H2 Console (embedded mode)?
-Dh2.baseDir=x {$baseDir}/...
http://db.apache.org/ddlutils/ (write a H2 driver) http://db.apache.org/ddlutils/ (write a H2 driver)
Negative dictionary: Negative dictionary:
Please note that Please note that
timer test support translated exceptions (translated, then english at the end, for Hibernate compatibility)
support translated exceptions (english + translated) keep db open as long as there are PooledConnections
select * from H2.PUBLIC.ORDERS make static member variables final (this helps find forgotten initializers)
Merge more from diff.zip (Pavel Ganelin)
keep db open (independent of DB_CLOSE_DELAY) while a PooledConnections exists. keep db open (independent of DB_CLOSE_DELAY) while a PooledConnections exists.
*/ */
/* /*
...@@ -260,7 +255,6 @@ SELECT COUNT(*) AS A FROM TEST GROUP BY ID HAVING A>0; ...@@ -260,7 +255,6 @@ SELECT COUNT(*) AS A FROM TEST GROUP BY ID HAVING A>0;
-- Yes: MySQL, HSQLDB -- Yes: MySQL, HSQLDB
-- Fail: Oracle, MS SQL Server, PostgreSQL, H2, Derby -- Fail: Oracle, MS SQL Server, PostgreSQL, H2, Derby
*/ */
// TODO: fix Hibernate dialect bug / Bordea Felix (lost email) // TODO: fix Hibernate dialect bug / Bordea Felix (lost email)
// run TestHalt // run TestHalt
......
...@@ -46,8 +46,8 @@ public class TestListener extends TestBase implements DatabaseEventListener { ...@@ -46,8 +46,8 @@ public class TestListener extends TestBase implements DatabaseEventListener {
System.out.println("diskSpaceIsLow stillAvailable="+stillAvailable); System.out.println("diskSpaceIsLow stillAvailable="+stillAvailable);
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
TestBase.logError("exceptionThrown", e); TestBase.logError("exceptionThrown sql=" + sql, e);
} }
public void setProgress(int state, String name, int current, int max) { public void setProgress(int state, String name, int current, int max) {
......
...@@ -117,7 +117,7 @@ public class TestMultiConn extends TestBase implements DatabaseEventListener { ...@@ -117,7 +117,7 @@ public class TestMultiConn extends TestBase implements DatabaseEventListener {
public void diskSpaceIsLow(long stillAvailable) throws SQLException { public void diskSpaceIsLow(long stillAvailable) throws SQLException {
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
} }
public void setProgress(int state, String name, int x, int max) { public void setProgress(int state, String name, int x, int max) {
......
...@@ -137,8 +137,8 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener { ...@@ -137,8 +137,8 @@ public class TestOpenClose extends TestBase implements DatabaseEventListener {
throw new SQLException("unexpected"); throw new SQLException("unexpected");
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
throw new Error("unexpected: " + e); throw new Error("unexpected: " + e + " sql: " + sql);
} }
public void setProgress(int state, String name, int current, int max) { public void setProgress(int state, String name, int current, int max) {
......
...@@ -33,11 +33,11 @@ public class TestScriptSimple extends TestBase { ...@@ -33,11 +33,11 @@ public class TestScriptSimple extends TestBase {
} }
sql = sql.trim(); sql = sql.trim();
// System.out.println(sql); // System.out.println(sql);
if("@reconnect".equals(sql)) { if("@reconnect".equals(sql.toLowerCase())) {
reconnect(); reconnect();
} else if(sql.length() == 0) { } else if(sql.length() == 0) {
// ignore // ignore
} else if(sql.startsWith("select")) { } else if(sql.toLowerCase().startsWith("select")) {
ResultSet rs = conn.createStatement().executeQuery(sql); ResultSet rs = conn.createStatement().executeQuery(sql);
while(rs.next()) { while(rs.next()) {
String expected = reader.readStatement().trim(); String expected = reader.readStatement().trim();
......
...@@ -388,11 +388,11 @@ public class TestMetaData extends TestBase { ...@@ -388,11 +388,11 @@ public class TestMetaData extends TestBase {
checkFalse(meta.supportsANSI92IntermediateSQL()); checkFalse(meta.supportsANSI92IntermediateSQL());
checkFalse(meta.supportsANSI92FullSQL()); checkFalse(meta.supportsANSI92FullSQL());
check(meta.supportsBatchUpdates()); check(meta.supportsBatchUpdates());
checkFalse(meta.supportsCatalogsInDataManipulation()); check(meta.supportsCatalogsInDataManipulation());
checkFalse(meta.supportsCatalogsInIndexDefinitions()); check(meta.supportsCatalogsInIndexDefinitions());
checkFalse(meta.supportsCatalogsInPrivilegeDefinitions()); check(meta.supportsCatalogsInPrivilegeDefinitions());
checkFalse(meta.supportsCatalogsInProcedureCalls()); checkFalse(meta.supportsCatalogsInProcedureCalls());
checkFalse(meta.supportsCatalogsInTableDefinitions()); check(meta.supportsCatalogsInTableDefinitions());
check(meta.supportsColumnAliasing()); check(meta.supportsColumnAliasing());
check(meta.supportsConvert()); check(meta.supportsConvert());
check(meta.supportsConvert(Types.INTEGER, Types.VARCHAR)); check(meta.supportsConvert(Types.INTEGER, Types.VARCHAR));
......
...@@ -47,7 +47,7 @@ public abstract class TestHalt extends TestBase { ...@@ -47,7 +47,7 @@ public abstract class TestHalt extends TestBase {
for(int i=0;; i++) { for(int i=0;; i++) {
operations = OP_INSERT | i; operations = OP_INSERT | i;
flags = i >> 4; flags = i >> 4;
// flags = FLAG_NODELAY | FLAG_LOBS; // flags |= FLAG_NO_DELAY; // | FLAG_LOBS;
try { try {
runTest(); runTest();
} catch(Throwable t) { } catch(Throwable t) {
......
...@@ -25,11 +25,6 @@ public class TestHaltApp extends TestHalt { ...@@ -25,11 +25,6 @@ public class TestHaltApp extends TestHalt {
protected void testInit() throws SQLException { protected void testInit() throws SQLException {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
try {
execute(stat, "DROP TABLE TEST");
} catch(SQLException e) {
// ignore
}
// stat.execute("CREATE TABLE TEST(ID IDENTITY, NAME VARCHAR(255))"); // stat.execute("CREATE TABLE TEST(ID IDENTITY, NAME VARCHAR(255))");
for(int i=0; i< 20; i++) { for(int i=0; i< 20; i++) {
execute(stat, "DROP TABLE IF EXISTS TEST" + i); execute(stat, "DROP TABLE IF EXISTS TEST" + i);
...@@ -38,11 +33,15 @@ public class TestHaltApp extends TestHalt { ...@@ -38,11 +33,15 @@ public class TestHaltApp extends TestHalt {
for(int i=0; i< 20; i+=2) { for(int i=0; i< 20; i+=2) {
execute(stat, "DROP TABLE TEST" + i); execute(stat, "DROP TABLE TEST" + i);
} }
execute(stat, "DROP TABLE IF EXISTS TEST");
execute(stat, "CREATE TABLE TEST(ID BIGINT GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), DATA CLOB)"); execute(stat, "CREATE TABLE TEST(ID BIGINT GENERATED BY DEFAULT AS IDENTITY, NAME VARCHAR(255), DATA CLOB)");
} }
protected void testWaitAfterAppStart() throws Exception { protected void testWaitAfterAppStart() throws Exception {
int sleep = 10 + random.nextInt(300); int sleep = 10 + random.nextInt(300);
if((flags & FLAG_NO_DELAY) == 0) {
sleep += 1000;
}
Thread.sleep(sleep); Thread.sleep(sleep);
} }
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
create table script.public.x(a int);
> ok
select * from script.PUBLIC.x;
> A
> -
> rows: 0
create index script.public.idx on script.public.x(a);
> ok
drop table script.public.x;
> ok
create table t1 (i int); create table t1 (i int);
> ok > ok
......
create table test_table(column_a integer);
insert into test_table values(1);
create view test_view AS SELECT * FROM (SELECT DISTINCT * FROM test_table) AS subquery;
select * FROM test_view;
> 1;
drop view test_view;
drop table test_table;
CREATE TABLE TEST(ID INT);
INSERT INTO TEST VALUES(1);
CREATE VIEW TEST_VIEW AS SELECT COUNT(ID) X FROM TEST;
explain SELECT * FROM TEST_VIEW WHERE X>1;
DROP VIEW TEST_VIEW;
DROP TABLE TEST;
create table test1(id int); create table test1(id int);
insert into test1 values(1), (1), (2), (3); insert into test1 values(1), (1), (2), (3);
select sum(C0) from (select count(*) AS C0 from (select distinct * from test1) as temp); select sum(C0) from (select count(*) AS C0 from (select distinct * from test1) as temp);
......
...@@ -96,7 +96,7 @@ public class TestExit extends TestBase implements DatabaseEventListener { ...@@ -96,7 +96,7 @@ public class TestExit extends TestBase implements DatabaseEventListener {
public void diskSpaceIsLow(long stillAvailable) throws SQLException { public void diskSpaceIsLow(long stillAvailable) throws SQLException {
} }
public void exceptionThrown(SQLException e) { public void exceptionThrown(SQLException e, String sql) {
} }
public void closingDatabase() { public void closingDatabase() {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论