提交 476b0169 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 2ceb8a1f
......@@ -1365,14 +1365,14 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Change Constants.DEFAULT_MAX_MEMORY_UNDO to 10000 (and change the docs). Test.
<li>Enable and document optimizations, LOB files in directories
<li>Special methods for DataPage.writeByte / writeShort and so on
<li>Index organized tables CREATE TABLE...(...) ORGANIZATION INDEX (store in data file) (probably file format changes are required for rowId)
</ul>
<h3>Priority 1</h3>
<ul>
<li>More tests with MULTI_THREADED=1
<li>Test read committed transaction isolation
<li>Test read committed transaction isolation (Hibernate)
<li>Hot backup (incremental backup, online backup)
<li>Documentation (FAQ) for how to connect to H2
<li>More tests with MULTI_THREADED=1
<li>Improve performance for create table (if this is possible)
<li>Test with Spatial DB in a box / JTS (http://docs.codehaus.org/display/GEOS/SpatialDBBox)
<li>Document how to use H2 with PHP (generic database API)
......@@ -1381,11 +1381,10 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Server side cursors
<li>Row level locking
<li>System table: open sessions and locks of a database
<li>System table: open connections and databases of a (TCP) server
<li>System table / function: cache usage
<li>Function in management db: open connections and databases of a (TCP) server
<li>Fix right outer joins
<li>Full outer joins
<li>Index organized tables: CREATE TABLE...(...) ORGANIZATION INDEX
<li>Long running queries / errors / trace system table
<li>Migrate database tool (also from other database engines)
<li>Shutdown compact
......@@ -1399,7 +1398,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>SET variable { TO | = } { value | 'value' | DEFAULT }
<li>Running totals: select @running:=if(@previous=t.ID,@running,0)+t.NUM as TOTAL, @previous:=t.ID
<li>Support SET REFERENTIAL_INTEGRITY {TRUE|FALSE}
<li>Backup of BLOB / CLOB: use a stream for backup, use a block append function to restore.
<li>Support CHAR data type (internally use VARCHAR, but report CHAR for JPox)
<li>Recovery for BLOB / CLOB: support functions
</ul>
<h3>Priority 2</h3>
......@@ -1412,7 +1412,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Compression performance: don't allocate buffers, compress / expand in to out buffer
<li>Start / stop server with database URL
<li># is the start of a single line comment (MySQL) but date quote (Access). Mode specific
<li>Run benchmarks with JDK 1.5, Server
<li>Run benchmarks with JDK 1.5, JDK 1.6, Server
<li>Rebuild index functionality (other than delete the index file)
<li>Don't use deleteOnExit (bug 4513817: File.deleteOnExit consumes memory)
<li>Console: add accesskey to most important commands (A, AREA, BUTTON, INPUT, LABEL, LEGEND, TEXTAREA)
......@@ -1512,6 +1512,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Clustering: recovery needs to becomes fully automatic.
<li>Date: default date is '1970-01-01' (is it 1900-01-01 in the standard / other databases?)
<li>Test and document UPDATE TEST SET (ID, NAME) = (SELECT ID*10, NAME || '!' FROM TEST T WHERE T.ID=TEST.ID);
<li>Support home directory as ~ in database URL (jdbc:h2:file:~/.mydir/myDB)
<li>Document EXISTS and so on, provide more samples.
<li>Modular build (multiple independent jars).
<li>Better space re-use in the files after deleting data (shrink the files)
......@@ -1554,19 +1555,16 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Console: Allow setting Null value; Alternative display format two column (for copy and paste as well)
<li>Console: Improve editing data (Tab, Shift-Tab, Enter, Up, Down, Shift+Del?)
<li>Console: Autocomplete Ctrl+Space inserts template
<li>Console: SQL statement formatter (newline before FROM, join, WHERE, AND, GROUP, ORDER, SELECT)
<li>Google Code http://code.google.com/p/h2database/issues/list#
<li>Simplify translation ('Donate a translation')
<li>Option to encrypt .trace.db file
<li>Write Behind Cache on SATA leads to data corruption
See also http://sr5tech.com/write_back_cache_experiments.htm
and http://www.jasonbrome.com/blog/archives/2004/04/03/writecache_enabled.html
<li>Support home directory as ~ in database URL (jdbc:h2:file:~/.mydir/myDB)
<li>Functions with unknown return or parameter data types: serialize / deserialize
<li>Test if idle TCP connections are closed, and how to disable that
<li>Compare with Daffodil One$DB
<li>Try using a factory for Row, Value[] (faster?), http://javolution.org/, alternative ObjectArray / IntArray
<li>Auto-Update feature
<li>Auto-Update feature for database, .jar file
<li>ResultSet SimpleResultSet.readFromURL(String url): id varchar, state varchar, released timestamp
<li>RANK() and DENSE_RANK(), Partition using OVER()
<li>ROW_NUMBER (not the same as ROWNUM)
......@@ -1583,7 +1581,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Console: -ifExists doesn't work for the console. Add a flag to disable other dbs
<li>Maybe use Fowler Noll Vo hash function
<li>Improved full text search (supports LOBs, readers / tokenizers / filters).
<li>Update in-place
<li>Performance: Update in-place
<li>Check if 'FSUTIL behavior set disablelastaccess 1' improves the performance (fsutil behavior query disablelastaccess)
<li>Remove finally() (almost) everywhere
<li>Java static code analysis: http://pmd.sourceforge.net/
......@@ -1613,7 +1611,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<li>Support ARRAY data type
<li>Implement more JDBC 4.0 features
<li>H2 Console: implement a servlet to allow simple web app integration
<li>Support CHAR data type (internally use VARCHAR, but report CHAR for JPox)
<li>Option to globally disable / enable referential integrity checks
<li>Support ISO 8601 timestamp / date / time with timezone
<li>Support TRANSFORM / PIVOT as in MS Access
......
......@@ -284,9 +284,8 @@ public class Bnf {
public void linkStatements() {
HashMap ruleMap = getRuleMap();
for(Iterator it = ruleMap.keySet().iterator(); it.hasNext(); ) {
String key = (String)it.next();
RuleHead r = (RuleHead) ruleMap.get(key);
for(Iterator it = ruleMap.values().iterator(); it.hasNext(); ) {
RuleHead r = (RuleHead) it.next();
r.getRule().setLinks(ruleMap);
}
}
......
......@@ -35,7 +35,7 @@ public class CommandContainer extends Command {
}
private void recompileIfRequired() throws SQLException {
if(prepared == null || prepared.needRecompile()) {
if(prepared.needRecompile()) {
// TODO test with 'always recompile'
prepared.setModificationId(0);
String sql = prepared.getSQL();
......
......@@ -3134,7 +3134,6 @@ public class Parser {
boolean ifNotExists = readIfNoExists();
String viewName = readIdentifierWithSchema();
CreateView command = new CreateView(session, getSchema());
command.setForce(force);
command.setViewName(viewName);
command.setIfNotExists(ifNotExists);
String select = StringCache.getNew(sqlCommand.substring(parseIndex));
......
......@@ -280,7 +280,6 @@ public class AlterTableAddConstraint extends SchemaCommand {
public void setColumnNames(String[] columnNames) {
this.columnNames = columnNames;
}
public void setRefTableName(Schema refSchema, String ref) {
......
......@@ -18,7 +18,6 @@ public class CreateView extends SchemaCommand {
private Query select;
private String viewName;
private boolean ifNotExists;
private boolean force;
private String selectSQL;
private String[] columnNames;
private String comment;
......@@ -48,7 +47,7 @@ public class CreateView extends SchemaCommand {
}
int id = getObjectId(true, true);
String querySQL;
if(select == null && force) {
if(select == null) {
querySQL = selectSQL;
} else {
querySQL = select.getSQL();
......@@ -63,10 +62,6 @@ public class CreateView extends SchemaCommand {
this.ifNotExists = ifNotExists;
}
public void setForce(boolean force) {
this.force = force;
}
public void setSelectSQL(String selectSQL) {
this.selectSQL = selectSQL;
}
......
......@@ -6,7 +6,6 @@ package org.h2.command.dml;
import java.sql.SQLException;
import java.util.BitSet;
import java.util.Enumeration;
import java.util.Random;
import org.h2.engine.Session;
......@@ -92,14 +91,9 @@ public class Optimizer {
}
private void calculateBruteForceAll() throws SQLException {
Enumeration en = new Permutations(filters);
for(int x=0; en.hasMoreElements(); x++) {
if(canStop(x)) {
break;
}
Object[] f = (Object[]) en.nextElement();
TableFilter[] ftry = new TableFilter[filters.length];
System.arraycopy(f, 0, ftry, 0, filters.length);
TableFilter[] ftry = new TableFilter[filters.length];
Permutations perm = new Permutations(filters, ftry);
for(int x=0; !canStop(x) && perm.next(); x++) {
testPlan(ftry);
}
}
......@@ -107,18 +101,13 @@ public class Optimizer {
private void calculateBruteForceSome() throws SQLException {
int bruteForce = getMaxBruteForceFilters(filters.length);
TableFilter[] ftry = new TableFilter[filters.length];
Enumeration en = new Permutations(filters, bruteForce);
for(int x=0; en.hasMoreElements(); x++) {
if(canStop(x)) {
break;
}
Object[] f = (Object[]) en.nextElement();
System.arraycopy(f, 0, ftry, 0, bruteForce);
Permutations perm = new Permutations(filters, ftry, bruteForce);
for(int x=0; !canStop(x) && perm.next(); x++) {
// find out what filters are not used yet
for(int i=0; i<filters.length; i++) {
filters[i].setUsed(false);
}
for(int i=0; i<f.length; i++) {
for(int i=0; i<bruteForce; i++) {
ftry[i].setUsed(true);
}
// fill the remaining elements with the unused elements (greedy)
......
......@@ -5,11 +5,14 @@
package org.h2.command.dml;
import java.sql.SQLException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.h2.command.Prepared;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.store.DiskFile;
/**
......@@ -29,6 +32,7 @@ public class TransactionCommand extends Prepared {
public static final int ROLLBACK_TRANSACTION = 11;
public static final int SHUTDOWN = 12;
public static final int SHUTDOWN_IMMEDIATELY = 13;
public static final int BACKUP = 14;
private int type;
private String savepointName;
......@@ -111,12 +115,28 @@ public class TransactionCommand extends Prepared {
session.close();
break;
}
case BACKUP: {
session.getUser().checkAdmin();
session.commit();
backupTo("backup.zip");
break;
}
default:
throw Message.getInternalError("type=" + type);
}
return 0;
}
private void backupTo(String fileName) {
// ZipOutputStream out = new ZipOutputStream("test.zip");
// out.putNextEntry(arg0)
// DiskFile file = session.getDatabase().getDataFile();
//// session.getDatabase().getLog().incStopDeleteFiles(true);
// // TODO Auto-generated method stub
//// session.getDatabase().getLog().setStopDeleteFiles(false);
//
}
public boolean isTransactional() {
return true;
}
......
......@@ -809,9 +809,7 @@ public class Database implements DataHandler {
traceSystem.getTrace(Trace.DATABASE).error("close", e);
}
traceSystem.getTrace(Trace.DATABASE).info("closed");
if(traceSystem != null) {
traceSystem.close();
}
traceSystem.close();
Engine.getInstance().close(databaseName);
if(deleteFilesOnDisconnect && persistent) {
deleteFilesOnDisconnect = false;
......
......@@ -71,7 +71,7 @@ public abstract class DbObject {
this.trace = database.getTrace(traceModule);
this.id = id;
this.objectName = name;
this.modificationId = database == null ? -1 : database.getModificationMetaId();
this.modificationId = database.getModificationMetaId();
}
public void setModified() {
......
......@@ -11,7 +11,7 @@ import org.h2.util.StringUtils;
public class Mode {
// TODO isolation: this setting should not be global
public static Mode currentMode;
private static Mode currentMode;
public static final String REGULAR_NAME = "REGULAR";
public boolean nullConcatIsNull;
......
......@@ -103,7 +103,7 @@ public class Session implements SessionInterface {
table.removeChildrenAndResources(this);
}
public void finalize() {
protected void finalize() {
if(!Constants.RUN_FINALIZERS) {
return;
}
......@@ -450,7 +450,7 @@ public class Session implements SessionInterface {
public JdbcConnection createConnection(boolean columnList) throws SQLException {
String url;
if(columnList) {
url = Constants.CONN_URL_INTERNAL;
url = Constants.CONN_URL_COLUMNLIST;
} else {
url = Constants.CONN_URL_INTERNAL;
}
......
......@@ -18,7 +18,7 @@ import org.h2.value.ValueNull;
public class ValueExpression extends Expression {
private Value value;
public static ValueExpression NULL = new ValueExpression(ValueNull.INSTANCE);
public static final ValueExpression NULL = new ValueExpression(ValueNull.INSTANCE);
public static ValueExpression get(Value v) {
if(v == ValueNull.INSTANCE) {
......
......@@ -582,8 +582,13 @@ public class FullText implements Trigger {
String key = rs.getString(1);
long indexId = rs.getLong(2);
IndexInfo index = setting.getIndexInfo(indexId);
String query = StringUtils.quoteIdentifier(index.schemaName)+"."+StringUtils.quoteIdentifier(index.tableName);
query +=" WHERE " + key;
StringBuffer buff = new StringBuffer();
buff.append(StringUtils.quoteIdentifier(index.schemaName));
buff.append('.');
buff.append(StringUtils.quoteIdentifier(index.tableName));
buff.append(" WHERE ");
buff.append(key);
String query = buff.toString();
result.addRow(new String[]{query});
rowCount++;
if(limit > 0 && rowCount >= limit) {
......
......@@ -102,8 +102,6 @@ public class BtreeIndex extends Index implements RecordReader {
}
}
int count;
void deletePage(Session session, Record p) throws SQLException {
if(database.getLogIndexChanges()) {
storage.removeRecord(session, p.getPos());
......
......@@ -322,8 +322,8 @@ public class BtreeNode extends BtreePage {
int size = 2 + dummy.getIntLen() + dummy.getIntLen() * len;
len = pageData.size();
size += dummy.getIntLen();
size += pageData.size() * dummy.getIntLen();
for (int i = 0; i < pageData.size(); i++) {
size += len * dummy.getIntLen();
for (int i = 0; i < len; i++) {
SearchRow row = getData(i);
size += getRowSize(dummy, row);
}
......
......@@ -277,7 +277,7 @@ public class TreeIndex extends Index {
}
x = n;
}
return new TreeCursor(this, x, first, last);
return new TreeCursor(this, x, null, last);
} else {
TreeNode x = findFirstNode(first, false);
return new TreeCursor(this, x, first, last);
......
......@@ -296,9 +296,13 @@ public class JdbcConnection extends TraceObject implements Connection {
* @throws SQLException
* if the connection is closed
*/
public boolean getAutoCommit() throws SQLException {
public synchronized boolean getAutoCommit() throws SQLException {
debugCodeCall("getAutoCommit");
return getInternalAutoCommit();
}
private boolean getInternalAutoCommit() throws SQLException {
try {
debugCodeCall("getAutoCommit");
checkClosed();
getAutoCommit = prepareCommand("CALL AUTOCOMMIT()", getAutoCommit);
ResultInterface result = getAutoCommit.executeQuery(0, false);
......@@ -663,11 +667,12 @@ public class JdbcConnection extends TraceObject implements Connection {
StringBuffer buff = new StringBuffer("new Map() /* ");
try {
// Map<String, Class>
for(Iterator it = map.keySet().iterator(); it.hasNext(); ) {
String key = (String)it.next();
for(Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
buff.append(key);
buff.append(':');
Class clazz = (Class)map.get(key);
Class clazz = (Class) entry.getValue();
buff.append(clazz.getName());
}
} catch(Exception e) {
......@@ -971,7 +976,7 @@ public class JdbcConnection extends TraceObject implements Connection {
//#ifdef JDK14
// check for existence of this class (avoiding Class . forName)
Class clazz = java.sql.Savepoint.class;
clazz = clazz == null ? null : clazz;
clazz.getClass();
//#endif
} catch(Throwable e) {
throw Message.getSQLException(Message.UNSUPPORTED_JAVA_VERSION);
......@@ -1192,7 +1197,7 @@ public class JdbcConnection extends TraceObject implements Connection {
return user;
}
public void finalize() {
protected void finalize() {
if(!Constants.RUN_FINALIZERS) {
return;
}
......@@ -1349,11 +1354,11 @@ public class JdbcConnection extends TraceObject implements Connection {
*
* @return true if the connection is valid.
*/
public boolean isValid(int timeout) {
public synchronized boolean isValid(int timeout) {
try {
debugCodeCall("isValid", timeout);
checkClosed();
getAutoCommit();
getInternalAutoCommit();
return true;
} catch(Throwable e) {
// this method doesn't throw an exception, but it logs it
......
......@@ -113,14 +113,15 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
checkClosed();
String tableType;
if (types != null && types.length>0) {
tableType = "TABLE_TYPE IN(";
StringBuffer buff = new StringBuffer("TABLE_TYPE IN(");
for (int i = 0; i < types.length; i++) {
if (i>0) {
tableType += ", ";
buff.append(", ");
}
tableType += "?";
buff.append("?");
}
tableType += ")";
buff.append(")");
tableType = buff.toString();
} else {
tableType = "TRUE";
}
......@@ -1172,7 +1173,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
try {
debugCodeCall("getTypeInfo");
checkClosed();
return conn.createStatement().executeQuery("SELECT "
PreparedStatement prep = conn.prepareAutoCloseStatement("SELECT "
+ "TYPE_NAME, "
+ "DATA_TYPE, "
+ "PRECISION, "
......@@ -1193,6 +1194,8 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
+ "RADIX NUM_PREC_RADIX "
+ "FROM INFORMATION_SCHEMA.TYPE_INFO "
+ "ORDER BY DATA_TYPE, POS");
ResultSet rs = prep.executeQuery();
return rs;
} catch(Throwable e) {
throw logAndConvert(e);
}
......
......@@ -38,9 +38,9 @@ public class JdbcDataSource extends TraceObject implements XADataSource, DataSou
private static final long serialVersionUID = 1288136338451857771L;
private JdbcDataSourceFactory factory;
private transient JdbcDataSourceFactory factory;
private transient PrintWriter logWriter;
private int timeout;
private PrintWriter logWriter;
private String user;
private String password;
private String url;
......
......@@ -21,6 +21,7 @@ import javax.transaction.xa.Xid;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.TraceObject;
import org.h2.util.ByteUtils;
import org.h2.util.JdbcUtils;
//#ifdef JDK16
/*
......@@ -115,8 +116,9 @@ public class JdbcXAConnection extends TraceObject implements XAConnection, JdbcC
public Xid[] recover(int flag) throws XAException {
debugCodeCall("recover", quoteFlags(flag));
checkOpen();
Statement stat = null;
try {
Statement stat = conn.createStatement();
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.IN_DOUBT ORDER BY ID");
ArrayList list = new ArrayList();
while(rs.next()) {
......@@ -125,12 +127,15 @@ public class JdbcXAConnection extends TraceObject implements XAConnection, JdbcC
Xid xid = new JdbcXid(factory, id, tid);
list.add(xid);
}
rs.close();
Xid[] result = new Xid[list.size()];
list.toArray(result);
return result;
} catch(SQLException e) {
getTrace().debug("throw XAException.XAER_OUTSIDE", e);
throw new XAException(XAException.XAER_OUTSIDE);
} finally {
JdbcUtils.closeSilently(stat);
}
}
......@@ -148,10 +153,14 @@ public class JdbcXAConnection extends TraceObject implements XAConnection, JdbcC
getTrace().debug("throw XAException.XAER_INVAL");
throw new XAException(XAException.XAER_INVAL);
}
Statement stat = null;
try {
conn.createStatement().execute("PREPARE COMMIT");
stat = conn.createStatement();
stat.execute("PREPARE COMMIT");
} catch(SQLException e) {
throw convertException(e);
} finally {
JdbcUtils.closeSilently(stat);
}
getTrace().debug("return TMSUCCESS");
return TMSUCCESS;
......
......@@ -32,7 +32,7 @@ public class JdbcXid extends TraceObject implements Xid {
formatId = Integer.parseInt(tokenizer.nextToken());
branchQualifier = ByteUtils.convertStringToBytes(tokenizer.nextToken());
globalTransactionId = ByteUtils.convertStringToBytes(tokenizer.nextToken());
} catch(Exception e) {
} catch(Throwable e) {
throw Message.getSQLException(Message.WRONG_XID_FORMAT_1, tid);
}
}
......
......@@ -217,7 +217,7 @@ public class TraceSystem {
closed = true;
}
public void finalize() {
protected void finalize() {
if(!Constants.RUN_FINALIZERS) {
return;
}
......
......@@ -156,7 +156,7 @@ class ResultDiskBuffer {
return sort.compare(va, vb);
}
public void finalize() {
protected void finalize() {
if(!Constants.RUN_FINALIZERS) {
return;
}
......
......@@ -25,7 +25,7 @@ public class Sequence extends SchemaObject {
this.belongsToTable = belongsToTable;
}
public void setStartValue(long value) {
public synchronized void setStartValue(long value) {
this.value = value;
this.valueWithMargin = value;
}
......
......@@ -25,6 +25,7 @@ import java.util.HashMap;
import org.h2.engine.ConnectionInfo;
import org.h2.message.Message;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
/**
......@@ -206,8 +207,9 @@ public class OdbcServerThread implements Runnable {
if(columnNamePattern ==null || columnNamePattern.length()==0) {
columnNamePattern = "%";
}
PreparedStatement prep = null;
try {
PreparedStatement prep = conn.prepareStatement("SELECT "
prep = conn.prepareStatement("SELECT "
+ "TABLE_CATALOG TABLE_CAT, "
+ "TABLE_SCHEMA TABLE_SCHEM, "
+ "TABLE_NAME, "
......@@ -239,6 +241,8 @@ public class OdbcServerThread implements Runnable {
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
......@@ -250,8 +254,10 @@ public class OdbcServerThread implements Runnable {
int type = transfer.readInt();
where = " WHERE TYPE="+type+" ";
}
Statement stat = null;
try {
ResultSet rs = conn.createStatement().executeQuery("SELECT "
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT "
+ "TYPE_NAME, "
+ "DATA_TYPE, "
+ "PRECISION COLUMN_SIZE, "
......@@ -277,6 +283,8 @@ public class OdbcServerThread implements Runnable {
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(stat);
}
break;
}
......@@ -289,10 +297,11 @@ public class OdbcServerThread implements Runnable {
}
// boolean unique = transfer.readBoolean();
// boolean approximate = transfer.readBoolean();
PreparedStatement prep = null;
try {
//ResultSet rs = meta.getIndexInfo(catalog, schemaPattern, tableNamePattern, unique, approximate);
PreparedStatement prep = conn.prepareStatement("SELECT "
prep = conn.prepareStatement("SELECT "
+ "TABLE_CATALOG TABLE_CAT, "
+ "TABLE_SCHEMA TABLE_SCHEM, "
+ "TABLE_NAME, "
......@@ -316,6 +325,8 @@ public class OdbcServerThread implements Runnable {
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
......@@ -337,10 +348,11 @@ public class OdbcServerThread implements Runnable {
server.log(" catalog="+catalog+" schema="+schema+" table="+table+" tableTypes="+tableTypes);
ResultSet rs;
String[] types = null;
PreparedStatement prep = null;
try {
if(catalog.equals("%") && schema.length()==0 && table.length()==0) {
server.log(" allCatalogs");
PreparedStatement prep = conn.prepareStatement("SELECT "
prep = conn.prepareStatement("SELECT "
+ "CATALOG_NAME TABLE_CAT, "
+ "NULL TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
......@@ -350,7 +362,7 @@ public class OdbcServerThread implements Runnable {
rs = prep.executeQuery();
} else if(catalog.length()==0 && schema.equals("%") && table.length()==0) {
server.log(" allSchemas");
PreparedStatement prep = conn.prepareStatement("SELECT "
prep = conn.prepareStatement("SELECT "
+ "CATALOG_NAME TABLE_CAT, "
+ "SCHEMA_NAME TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
......@@ -360,7 +372,7 @@ public class OdbcServerThread implements Runnable {
rs = prep.executeQuery();
} else if(catalog.length()==0 && schema.length()==0 && table.length()==0 && tableTypes.equals("%")) {
server.log(" allTableTypes");
PreparedStatement prep = conn.prepareStatement("SELECT "
prep = conn.prepareStatement("SELECT "
+ "NULL TABLE_CAT, "
+ "NULL TABLE_SCHEM, "
+ "NULL TABLE_NAME, "
......@@ -391,6 +403,8 @@ public class OdbcServerThread implements Runnable {
processResultSet(rs);
} catch(SQLException e) {
sendError(e);
} finally {
JdbcUtils.closeSilently(prep);
}
break;
}
......@@ -501,15 +515,20 @@ public class OdbcServerThread implements Runnable {
transfer.writeInt(id);
transfer.writeInt(params);
} else {
Statement stat = conn.createStatement();
boolean isResultSet = stat.execute(sql);
if(isResultSet) {
transfer.writeByte((byte)'R');
ResultSet rs = stat.getResultSet();
processResultSet(rs);
} else {
transfer.writeByte((byte)'U');
transfer.writeInt(stat.getUpdateCount());
Statement stat = null;
try {
stat = conn.createStatement();
boolean isResultSet = stat.execute(sql);
if(isResultSet) {
transfer.writeByte((byte)'R');
ResultSet rs = stat.getResultSet();
processResultSet(rs);
} else {
transfer.writeByte((byte)'U');
transfer.writeInt(stat.getUpdateCount());
}
} finally {
JdbcUtils.closeSilently(stat);
}
}
} catch(SQLException e) {
......
......@@ -17,6 +17,7 @@ import java.util.HashSet;
import org.h2.engine.Constants;
import org.h2.message.TraceSystem;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -52,43 +53,29 @@ public class TcpServer implements Service {
private void initManagementDb() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:h2:" + getManagementDbName(port), "sa", managementPassword);
managementDb = conn;
Statement stat = conn.createStatement();
stat.execute("CREATE ALIAS IF NOT EXISTS STOP_SERVER FOR \"" + TcpServer.class.getName() +".stopServer\"");
Statement stat = null;
try {
stat = conn.createStatement();
stat.execute("CREATE ALIAS IF NOT EXISTS STOP_SERVER FOR \"" + TcpServer.class.getName() +".stopServer\"");
} finally {
JdbcUtils.closeSilently(stat);
}
servers.put(""+port, this);
}
private void stopManagementDb() {
if(managementDb != null) {
try {
managementDb.close();
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
synchronized(TcpServer.class) {
if(managementDb != null) {
try {
managementDb.close();
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
}
managementDb = null;
}
managementDb = null;
}
}
public static synchronized void stopServer(int port, String password, int shutdownMode) {
TcpServer server = (TcpServer) servers.get("" + port);
if(server == null) {
return;
}
if(!server.managementPassword.equals(password)) {
return;
}
if(shutdownMode == TcpServer.SHUTDOWN_NORMAL) {
server.stop = true;
try {
Socket s = new Socket("localhost", port);
s.close();
} catch (Exception e) {
// try to connect - so that accept returns
}
} else if(shutdownMode == TcpServer.SHUTDOWN_FORCE) {
server.stop();
}
}
public void init(String[] args) throws Exception {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
......@@ -126,8 +113,8 @@ public class TcpServer implements Service {
public void start() throws SQLException {
synchronized(TcpServer.class) {
initManagementDb();
serverSocket = NetUtils.createServerSocket(port, ssl);
initManagementDb();
}
}
......@@ -148,9 +135,7 @@ public class TcpServer implements Service {
TraceSystem.traceThrowable(e);
}
}
synchronized(TcpServer.class) {
stopManagementDb();
}
stopManagementDb();
}
public boolean isRunning() {
......@@ -169,6 +154,7 @@ public class TcpServer implements Service {
public synchronized void stop() {
// TODO server: share code between web and tcp servers
if(!stop) {
stopManagementDb();
stop = true;
if(serverSocket != null) {
try {
......@@ -193,6 +179,28 @@ public class TcpServer implements Service {
servers.remove(""+port);
}
public static synchronized void stopServer(int port, String password, int shutdownMode) {
TcpServer server = (TcpServer) servers.get("" + port);
if(server == null) {
return;
}
if(!server.managementPassword.equals(password)) {
return;
}
if(shutdownMode == TcpServer.SHUTDOWN_NORMAL) {
server.stopManagementDb();
server.stop = true;
try {
Socket s = new Socket("localhost", port);
s.close();
} catch (Exception e) {
// try to connect - so that accept returns
}
} else if(shutdownMode == TcpServer.SHUTDOWN_FORCE) {
server.stop();
}
}
synchronized void remove(TcpServerThread t) {
running.remove(t);
}
......@@ -212,7 +220,7 @@ public class TcpServer implements Service {
}
}
void logError(Exception e) {
void logError(Throwable e) {
if (log) {
e.printStackTrace();
}
......
......@@ -89,7 +89,7 @@ public class TcpServerThread implements Runnable {
}
}
server.log("Disconnect");
} catch(Exception e) {
} catch(Throwable e) {
server.logError(e);
} finally {
close();
......
......@@ -141,8 +141,8 @@ public class FtpServer implements Service {
return buff.toString();
}
public boolean checkUserPassword(String userName, String param) {
return userName.equals(this.writeUserName) && writePassword.equals(this.writePassword);
public boolean checkUserPassword(String userName, String password) {
return userName.equals(this.writeUserName) && password.equals(this.writePassword);
}
public boolean checkUserPasswordReadOnly(String userName, String param) {
......
......@@ -7,11 +7,8 @@ package org.h2.server.web;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -21,7 +18,6 @@ import org.h2.engine.Constants;
import org.h2.message.TraceSystem;
import org.h2.util.FileUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
public class AppServer {
......@@ -40,7 +36,7 @@ public class AppServer {
"Generic H2|org.h2.Driver|jdbc:h2:test|sa",
};
private URLClassLoader urlClassLoader;
// private URLClassLoader urlClassLoader;
private String driverList;
private static int ticker;
private int port;
......@@ -64,20 +60,20 @@ public class AppServer {
}
}
// TODO gcj: don't load drivers in case of GCJ
if(false) {
if(driverList != null) {
try {
String[] drivers = StringUtils.arraySplit(driverList, ',', false);
URL[] urls = new URL[drivers.length];
for(int i=0; i<drivers.length; i++) {
urls[i] = new URL(drivers[i]);
}
urlClassLoader = URLClassLoader.newInstance(urls);
} catch (MalformedURLException e) {
TraceSystem.traceThrowable(e);
}
}
}
// if(false) {
// if(driverList != null) {
// try {
// String[] drivers = StringUtils.arraySplit(driverList, ',', false);
// URL[] urls = new URL[drivers.length];
// for(int i=0; i<drivers.length; i++) {
// urls[i] = new URL(drivers[i]);
// }
// urlClassLoader = URLClassLoader.newInstance(urls);
// } catch (MalformedURLException e) {
// TraceSystem.traceThrowable(e);
// }
// }
// }
}
void setAllowOthers(boolean b) {
......@@ -212,22 +208,16 @@ public class AppServer {
user = user.trim();
password = password.trim();
org.h2.Driver.load();
try {
Class.forName(driver);
} catch(ClassNotFoundException e) {
if(urlClassLoader == null) {
throw e;
}
try {
Driver dr = (Driver) urlClassLoader.loadClass(driver).newInstance();
Properties p = new Properties();
p.setProperty("user", user);
p.setProperty("password", password);
return dr.connect(url, p);
} catch(ClassNotFoundException e2) {
throw e2;
}
}
Class.forName(driver);
// try {
// Driver dr = (Driver) urlClassLoader.loadClass(driver).newInstance();
// Properties p = new Properties();
// p.setProperty("user", user);
// p.setProperty("password", password);
// return dr.connect(url, p);
// } catch(ClassNotFoundException e2) {
// throw e2;
// }
return DriverManager.getConnection(url, user, password);
}
......
......@@ -21,10 +21,13 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;
import org.h2.bnf.Bnf;
import org.h2.tools.SimpleResultSet;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
import org.h2.util.ObjectArray;
......@@ -136,11 +139,12 @@ public class AppThread extends WebServerThread {
}
}
ArrayList list = new ArrayList(map.size());
Iterator it = map.keySet().iterator();
Iterator it = map.entrySet().iterator();
while(it.hasNext()) {
String key = (String)it.next();
Map.Entry entry = (Entry) it.next();
String key = (String) entry.getKey();
String type = "" + key.charAt(0);
String value = (String) map.get(key);
String value = (String) entry.getValue();
key = key.substring(2);
if(Character.isLetter(key.charAt(0)) && lowercase) {
key = StringUtils.toLowerEnglish(key);
......@@ -192,7 +196,7 @@ public class AppThread extends WebServerThread {
app.setSSL(Boolean.valueOf((String)attributes.get("ssl")).booleanValue());
app.saveSettings();
} catch(Exception e) {
// TODO ignore error?
server.trace(e.toString());
}
return admin();
}
......@@ -368,13 +372,18 @@ public class AppThread extends WebServerThread {
StringBuffer columnsBuffer = new StringBuffer();
treeIndex = addColumns(view, buff, treeIndex, showColumnTypes, columnsBuffer);
if(schema.contents.isH2) {
PreparedStatement prep = conn.prepareStatement("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?");
prep.setString(1, view.name);
ResultSet rs = prep.executeQuery();
if(rs.next()) {
String sql = rs.getString("SQL");
buff.append("setNode("+treeIndex+ identNode + " 'type', '" + PageParser.escapeJavaScript(sql)+ "', null);\n");
treeIndex++;
PreparedStatement prep = null;
try {
prep = conn.prepareStatement("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?");
prep.setString(1, view.name);
ResultSet rs = prep.executeQuery();
if(rs.next()) {
String sql = rs.getString("SQL");
buff.append("setNode("+treeIndex+ identNode + " 'type', '" + PageParser.escapeJavaScript(sql)+ "', null);\n");
treeIndex++;
}
} finally {
JdbcUtils.closeSilently(prep);
}
}
buff.append("addTable('"+PageParser.escapeJavaScript(view.name)+"', '"+PageParser.escapeJavaScript(columnsBuffer.toString())+"', "+tableId+");\n");
......@@ -414,38 +423,44 @@ public class AppThread extends WebServerThread {
treeIndex = addTablesAndViews(schema, false, buff, treeIndex);
}
if(isH2) {
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM INFORMATION_SCHEMA.SEQUENCES ORDER BY SEQUENCE_NAME");
for(int i=0; rs.next(); i++) {
if(i==0) {
buff.append("setNode("+treeIndex+", 0, 1, 'sequences', '${text.tree.sequences}', null);\n");
treeIndex++;
}
String name = rs.getString("SEQUENCE_NAME");
String current = rs.getString("CURRENT_VALUE");
String increment = rs.getString("INCREMENT");
buff.append("setNode("+treeIndex+", 1, 1, 'sequence', '" + PageParser.escapeJavaScript(name)+ "', null);\n");
treeIndex++;
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.current}: " + PageParser.escapeJavaScript(current)+ "', null);\n");
treeIndex++;
if(!increment.equals("1")) {
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.increment}: " + PageParser.escapeJavaScript(increment)+ "', null);\n");
Statement stat = null;
try {
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM INFORMATION_SCHEMA.SEQUENCES ORDER BY SEQUENCE_NAME");
for(int i=0; rs.next(); i++) {
if(i==0) {
buff.append("setNode("+treeIndex+", 0, 1, 'sequences', '${text.tree.sequences}', null);\n");
treeIndex++;
}
String name = rs.getString("SEQUENCE_NAME");
String current = rs.getString("CURRENT_VALUE");
String increment = rs.getString("INCREMENT");
buff.append("setNode("+treeIndex+", 1, 1, 'sequence', '" + PageParser.escapeJavaScript(name)+ "', null);\n");
treeIndex++;
}
}
rs = conn.createStatement().executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS ORDER BY NAME");
for(int i=0; rs.next(); i++) {
if(i==0) {
buff.append("setNode("+treeIndex+", 0, 1, 'users', '${text.tree.users}', null);\n");
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.current}: " + PageParser.escapeJavaScript(current)+ "', null);\n");
treeIndex++;
if(!increment.equals("1")) {
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.increment}: " + PageParser.escapeJavaScript(increment)+ "', null);\n");
treeIndex++;
}
}
String name = rs.getString("NAME");
String admin = rs.getString("ADMIN");
buff.append("setNode("+treeIndex+", 1, 1, 'user', '" + PageParser.escapeJavaScript(name)+ "', null);\n");
treeIndex++;
if(admin.equalsIgnoreCase("TRUE")) {
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.admin}', null);\n");
rs = conn.createStatement().executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS ORDER BY NAME");
for(int i=0; rs.next(); i++) {
if(i==0) {
buff.append("setNode("+treeIndex+", 0, 1, 'users', '${text.tree.users}', null);\n");
treeIndex++;
}
String name = rs.getString("NAME");
String admin = rs.getString("ADMIN");
buff.append("setNode("+treeIndex+", 1, 1, 'user', '" + PageParser.escapeJavaScript(name)+ "', null);\n");
treeIndex++;
if(admin.equalsIgnoreCase("TRUE")) {
buff.append("setNode("+treeIndex+", 2, 2, 'type', '${text.tree.admin}', null);\n");
treeIndex++;
}
}
} finally {
JdbcUtils.closeSilently(stat);
}
}
String version = meta.getDatabaseProductName() + " " + meta.getDatabaseProductVersion();
......@@ -542,7 +557,7 @@ public class AppThread extends WebServerThread {
conn.close();
}
} catch(Exception e) {
// TODO log error
server.trace(e.toString());
}
return "index.do";
}
......@@ -1016,12 +1031,14 @@ public class AppThread extends WebServerThread {
result += "(Statement) ";
}
result+="(";
StringBuffer buff = new StringBuffer();
for(int i=0; i<params.size(); i++) {
if(i>0) {
result+=", ";
buff.append(", ");
}
result += ((Integer)params.get(i)).intValue() == 0 ? "i" : "rnd";
buff.append(((Integer)params.get(i)).intValue() == 0 ? "i" : "rnd");
}
result += buff.toString();
result+=") " + sql;
return result;
}
......
......@@ -25,7 +25,7 @@ public class DbContents {
isH2 = url.startsWith("jdbc:h2:");
isOracle = url.startsWith("jdbc:oracle:");
isPostgreSQL = url.startsWith("jdbc:postgresql:");
isHSQLDB = url.startsWith("jdbc:hsqldb:");
// isHSQLDB = url.startsWith("jdbc:hsqldb:");
isMySQL = url.startsWith("jdbc:mysql:");
isDerby = url.startsWith("jdbc:derby:");
isFirebird = url.startsWith("jdbc:firebirdsql:");
......@@ -45,8 +45,8 @@ public class DbContents {
schema.readTables(meta, tableTypes);
}
if(defaultSchema == null) {
String best = null;
for(int i=0; i<schemas.length; i++) {
String best = null;
if("dbo".equals(schemas[i].name)) {
// MS SQL Server
defaultSchema = schemas[i];
......
......@@ -7,6 +7,8 @@ package org.h2.server.web;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.h2.bnf.Bnf;
import org.h2.bnf.Rule;
......@@ -68,9 +70,10 @@ public class DbContextRule implements Rule {
HashMap map = sentence.getAliases();
HashSet set = new HashSet();
if(map != null) {
for(Iterator it = map.keySet().iterator(); it.hasNext();) {
String alias = (String)it.next();
DbTableOrView table = (DbTableOrView)map.get(alias);
for(Iterator it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Entry) it.next();
String alias = (String) entry.getKey();
DbTableOrView table = (DbTableOrView) entry.getValue();
set.add(StringUtils.toUpperEnglish(table.name));
if(q.length()==0 || alias.startsWith(q)) {
if(q.length() < alias.length()) {
......@@ -112,12 +115,14 @@ public class DbContextRule implements Rule {
HashMap map = sentence.getAliases();
String shortName = lastTableName.substring(0, 1);
if (map != null && map.containsKey(shortName)) {
int result = 0;
for (int i = 1;; i++) {
if (!map.containsKey(shortName + i)) {
shortName += i;
result = i;
break;
}
}
shortName += result;
}
String q = StringUtils.toUpperEnglish(query.trim());
if (q.length() == 0 || StringUtils.toUpperEnglish(shortName).startsWith(q)) {
......
......@@ -153,7 +153,7 @@ public class WebServer implements Service {
c.start();
}
} catch (Exception e) {
// TODO log exception
trace(e.toString());
}
}
......@@ -192,7 +192,7 @@ public class WebServer implements Service {
try {
trace("translation: "+language);
byte[] trans = getFile("_text_"+language+".properties");
trace(" "+trans);
trace(" "+new String(trans));
text.load(new ByteArrayInputStream(trans));
} catch (IOException e) {
TraceSystem.traceThrowable(e);
......
......@@ -389,39 +389,35 @@ public class DiskFile implements CacheWriter {
return record;
}
readCount++;
try {
go(pos);
rowBuff.reset();
byte[] buff = rowBuff.getBytes();
file.readFully(buff, 0, BLOCK_SIZE);
DataPage s = DataPage.create(database, buff);
int blockCount = s.readInt();
int id = s.readInt();
if(Constants.CHECK && storageId != id) {
throw Message.getInternalError("File ID mismatch got="+id+" expected="+storageId+" pos="+pos+" "+logChanges+" "+this +" blockCount:"+blockCount);
}
if(Constants.CHECK && blockCount == 0) {
throw Message.getInternalError("0 blocks to read pos="+pos);
}
if(blockCount > 1) {
byte[] b2 = new byte[blockCount * BLOCK_SIZE];
System.arraycopy(buff, 0, b2, 0, BLOCK_SIZE);
buff = b2;
file.readFully(buff, BLOCK_SIZE, blockCount * BLOCK_SIZE - BLOCK_SIZE);
s = DataPage.create(database, buff);
s.readInt();
s.readInt();
}
s.check(blockCount*BLOCK_SIZE);
Record r = reader.read(s);
r.setStorageId(storageId);
r.setPos(pos);
r.setBlockCount(blockCount);
cache.put(r);
return r;
} catch (Exception e) {
throw Message.convert(e);
go(pos);
rowBuff.reset();
byte[] buff = rowBuff.getBytes();
file.readFully(buff, 0, BLOCK_SIZE);
DataPage s = DataPage.create(database, buff);
int blockCount = s.readInt();
int id = s.readInt();
if(Constants.CHECK && storageId != id) {
throw Message.getInternalError("File ID mismatch got="+id+" expected="+storageId+" pos="+pos+" "+logChanges+" "+this +" blockCount:"+blockCount);
}
if(Constants.CHECK && blockCount == 0) {
throw Message.getInternalError("0 blocks to read pos="+pos);
}
if(blockCount > 1) {
byte[] b2 = new byte[blockCount * BLOCK_SIZE];
System.arraycopy(buff, 0, b2, 0, BLOCK_SIZE);
buff = b2;
file.readFully(buff, BLOCK_SIZE, blockCount * BLOCK_SIZE - BLOCK_SIZE);
s = DataPage.create(database, buff);
s.readInt();
s.readInt();
}
s.check(blockCount*BLOCK_SIZE);
Record r = reader.read(s);
r.setStorageId(storageId);
r.setPos(pos);
r.setBlockCount(blockCount);
cache.put(r);
return r;
}
}
......@@ -511,7 +507,7 @@ public class DiskFile implements CacheWriter {
return pageOwners.get(page);
}
synchronized void setPageOwner(int page, int storageId) throws SQLException {
void setPageOwner(int page, int storageId) throws SQLException {
int old = pageOwners.get(page);
if(old == storageId) {
return;
......@@ -737,7 +733,7 @@ public class DiskFile implements CacheWriter {
return dataFile;
}
public void setLogChanges(boolean b) {
public synchronized void setLogChanges(boolean b) {
this.logChanges = b;
}
......
......@@ -67,7 +67,7 @@ public class FileLock {
locked = true;
}
public void finalize() {
protected void finalize() {
if (!Constants.RUN_FINALIZERS) {
return;
}
......
......@@ -131,7 +131,7 @@ public class FileStoreInputStream extends InputStream {
}
}
public void finalize() {
protected void finalize() {
if (!Constants.RUN_FINALIZERS) {
return;
}
......
......@@ -16,4 +16,8 @@ public class SessionState {
}
return lastCommitPos >= pos;
}
public String toString() {
return "sessionId:" + sessionId + " log:" + lastCommitLog + " pos:" + lastCommitPos + " inDoubt:" + inDoubtTransaction;
}
}
......@@ -461,7 +461,7 @@ public class MetaTable extends Table {
private String identifier(String s) {
if(Mode.getCurrentMode().lowerCaseIdentifiers) {
s = (s==null ? s : StringUtils.toLowerEnglish(s));
s = (s==null ? null : StringUtils.toLowerEnglish(s));
}
return s;
}
......@@ -478,7 +478,7 @@ public class MetaTable extends Table {
return true;
}
Database db = session.getDatabase();
Value v = value == null ? (Value)ValueNull.INSTANCE : ValueString.get(value);
Value v = ValueString.get(value);
if(indexFrom != null && db.compare(v, indexFrom) < 0) {
return false;
}
......
......@@ -292,13 +292,13 @@ public class TableFilter implements ColumnResolver {
}
public void addJoin(TableFilter filter, boolean outer, Expression on) throws SQLException {
if(on!=null) {
if(on != null) {
on.mapColumns(this, 0);
}
if(join==null) {
if(join == null) {
this.join = filter;
filter.outerJoin = outer;
if(on!=null) {
if(on != null) {
TableFilter f = filter;
do {
on.mapColumns(f, 0);
......@@ -311,7 +311,7 @@ public class TableFilter implements ColumnResolver {
join.addJoin(filter, outer, on);
}
if(on != null) {
on = on.optimize(session);
on.optimize(session);
}
}
......
......@@ -11,6 +11,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import org.h2.engine.Session;
......@@ -20,6 +21,7 @@ import org.h2.index.LinkedIndex;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.util.JdbcUtils;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
......@@ -71,8 +73,10 @@ public class TableLink extends Table {
columnMap.put(n, col);
}
if(columnList.size()==0) {
Statement stat = null;
try {
rs = conn.createStatement().executeQuery("SELECT * FROM " + originalTable + " T WHERE 1=0");
stat = conn.createStatement();
rs = stat.executeQuery("SELECT * FROM " + originalTable + " T WHERE 1=0");
ResultSetMetaData rsm = rs.getMetaData();
for(i=0; i<rsm.getColumnCount();) {
String n = rsm.getColumnName(i+1);
......@@ -91,6 +95,8 @@ public class TableLink extends Table {
}
} catch(SQLException e) {
throw Message.getSQLException(Message.TABLE_OR_VIEW_NOT_FOUND_1, new String[]{originalTable}, e);
} finally {
JdbcUtils.closeSilently(stat);
}
}
Column[] cols = new Column[columnList.size()];
......
......@@ -199,7 +199,7 @@ public class TableView extends Table {
}
public void recompile(Session session) throws SQLException {
for(int i=0; tables != null && i<tables.size(); i++) {
for(int i=0; i<tables.size(); i++) {
Table t = (Table)tables.get(i);
t.removeView(this);
}
......
......@@ -14,6 +14,8 @@ import java.sql.SQLException;
import java.sql.Statement;
import org.h2.message.Message;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
/**
......@@ -101,18 +103,19 @@ public class Backup {
* INTERNAL
*/
public static void executeScript(String url, String user, String password, String fileName, String options1, String options2) throws SQLException {
Connection conn = null;
Statement stat = null;
try {
org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url, user, password);
Statement stat = conn.createStatement();
conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
String sql = "SCRIPT " + options1 + " TO '" + fileName + "' " + options2;
try {
stat.execute(sql);
} finally {
conn.close();
}
stat.execute(sql);
} catch(Exception e) {
throw Message.convert(e);
} finally {
JdbcUtils.closeSilently(stat);
JdbcUtils.closeSilently(conn);
}
}
......@@ -126,11 +129,14 @@ public class Backup {
* @throws SQLException
*/
public static void execute(String url, String user, String password, String script) throws SQLException {
Connection conn = null;
Statement stat = null;
FileWriter fileWriter = null;
try {
org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url, user, password);
Statement stat = conn.createStatement();
FileWriter fileWriter = new FileWriter(script);
conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
fileWriter = new FileWriter(script);
PrintWriter writer = new PrintWriter(new BufferedWriter(fileWriter));
ResultSet rs = stat.executeQuery("SCRIPT");
while(rs.next()) {
......@@ -138,10 +144,12 @@ public class Backup {
writer.println(s + ";");
}
writer.close();
fileWriter.close();
conn.close();
} catch(Exception e) {
throw Message.convert(e);
} finally {
JdbcUtils.closeSilently(stat);
JdbcUtils.closeSilently(conn);
IOUtils.closeSilently(fileWriter);
}
}
......
......@@ -10,6 +10,7 @@ import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.message.Message;
import org.h2.util.JdbcUtils;
/**
* Tool to create a database cluster.
......@@ -82,9 +83,11 @@ public class CreateCluster {
* @throws SQLException
*/
public static void execute(String urlSource, String urlTarget, String user, String password, String serverlist) throws SQLException {
Connection conn = null;
Statement stat = null;
try {
org.h2.Driver.load();
Connection conn;
// use cluster='' so connecting is possible even if the cluster is enabled
conn = DriverManager.getConnection(urlSource + ";CLUSTER=''", user, password);
......@@ -107,16 +110,17 @@ public class CreateCluster {
// set the cluster to the serverlist on both databases
conn = DriverManager.getConnection(urlSource, user, password);
Statement stat;
stat = conn.createStatement();
stat.executeUpdate("SET CLUSTER '" + serverlist + "'");
conn.close();
conn = DriverManager.getConnection(urlTarget, user, password);
stat = conn.createStatement();
stat.executeUpdate("SET CLUSTER '" + serverlist + "'");
conn.close();
} catch(Exception e) {
throw Message.convert(e);
} finally {
JdbcUtils.closeSilently(conn);
JdbcUtils.closeSilently(stat);
}
}
......
......@@ -48,7 +48,7 @@ public class ByteUtils {
public static byte[] convertStringToBytes(String s) throws SQLException {
int len = s.length();
if (len % 2 == 1) {
if (len < 0 || len % 2 == 1) {
throw Message.getSQLException(Message.HEX_STRING_ODD_1, s);
}
len /= 2;
......
......@@ -15,7 +15,7 @@ import org.h2.message.Message;
*/
public class Cache2Q implements Cache {
public static String TYPE_NAME = "TQ";
public static final String TYPE_NAME = "TQ";
private static final int MAIN = 1, IN = 2, OUT = 3;
private int maxSize;
......
......@@ -17,7 +17,7 @@ import org.h2.message.Message;
*/
public class CacheLRU implements Cache {
public static String TYPE_NAME = "LRU";
public static final String TYPE_NAME = "LRU";
private int len;
private int maxSize;
......
......@@ -99,11 +99,11 @@ public class DateTimeUtils {
}
public static Date convertDateToCalendar(Date x, Calendar calendar) throws SQLException {
return x == null ? x : new Date(getLocalTime(x, calendar));
return x == null ? null : new Date(getLocalTime(x, calendar));
}
public static Time convertTimeToCalendar(Time x, Calendar calendar) throws SQLException {
return x == null ? x : new Time(getLocalTime(x, calendar));
return x == null ? null : new Time(getLocalTime(x, calendar));
}
public static java.util.Date parseDateTime(String s, int type, int errorCode) throws SQLException {
......
......@@ -25,7 +25,7 @@ import org.h2.message.TraceSystem;
public class FileUtils {
public static HashMap memoryFiles = new HashMap();
public static final HashMap memoryFiles = new HashMap();
private static final String MEMORY_PREFIX = "inmemory:";
private static final String MEMORY_PREFIX_2 = "mem:";
// TODO detection of 'case in sensitive filesystem' could maybe implemented using some other means
......
......@@ -101,6 +101,9 @@ public class IntArray {
}
public boolean equals(Object obj) {
if(!(obj instanceof IntArray)) {
return false;
}
IntArray other = (IntArray) obj;
if(hashCode() != other.hashCode() || size != other.size) {
return false;
......
package org.h2.util;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtils {
public static void closeSilently(Statement stat) {
if(stat != null) {
try {
stat.close();
} catch(SQLException e) {
// ignore
}
}
}
public static void closeSilently(Connection conn) {
if(conn != null) {
try {
conn.close();
} catch(SQLException e) {
// ignore
}
}
}
}
......@@ -6,157 +6,63 @@ package org.h2.util;
import org.h2.message.Message;
// code originally from http://www.koders.com/java/fidD3445CD11B1DC687F6B8911075E7F01E23171553.aspx
// http://www.koders.com/java/fidD3445CD11B1DC687F6B8911075E7F01E23171553.aspx
/**
* The Permutations class provides an enumeration of all permutations of an
* array of objects. Each permutation is simply an ordered list of the group.
* <p>
* For example, to see all of the ways we can select a school representative and
* an alternate from a list of 4 children, begin with an array of names::
* <blockquote>
*
* <pre>
* Object[] children = { Leonardo, Monica, Nathan, Olivia };
* </pre>
*
* </blockquote> To see all 2-permutations of these 4 names, create and use a
* Permutations enumeration: <blockquote>
*
* <pre>
*
* Permutations c = new Permutations(children, 2);
* while (c.hasMoreElements()) {
* Object[] perm = (Object[])c.nextElement();
* for (int i = 0; i &lt; perm.length; i++) {
* System.out.print(perm[i] + );
* }
* System.out.println();
* }
*
* </pre>
*
* </blockquote> This will print out: <blockquote>
*
* <pre>
*
* Leonardo Monica
* Leonardo Nathan
* Leonardo Olivia
* Monica Leonardo
* Monica Nathan
* Monica Olivia
* Nathan Leonardo
* Nathan Monica
* Nathan Olivia
* Olivia Leonardo
* Olivia Monica
* Olivia Nathan
*
* </pre>
*
* </blockquote>
*
* A class to iterate over all permutations of an array.
* The algorithm is from Applied Combinatorics, by Alan Tucker as implemented in
* http://www.koders.com/java/fidD3445CD11B1DC687F6B8911075E7F01E23171553.aspx
*/
public class Permutations implements java.util.Enumeration {
private Object[] inArray;
public class Permutations {
private Object[] in;
private Object[] out;
private int n, m;
private int[] index;
private boolean hasNext = true;
private boolean hasMore = true;
/**
* Create a Permutation to enumerate through all possible lineups of the
* supplied array of Objects.
*
* @param inArray
* the group to line up
* @exception CombinatoricException
* Should never happen with this interface
*
*/
public Permutations(Object[] inArray) {
this(inArray, inArray.length);
public Permutations(Object[] in, Object[] out) {
this(in, out, in.length);
}
/**
* Create a Permutation to enumerate through all possible lineups of the
* supplied array of Objects.
*
* @param inArray
* the group to line up
* @param m
* the number of objects to use
* @exception CombinatoricException
* if m is greater than the length of inArray, or less than
* 0.
*/
public Permutations(Object[] inArray, int m) {
this.inArray = inArray;
this.n = inArray.length;
public Permutations(Object[] in, Object[] out, int m) {
this.n = in.length;
this.m = m;
// throw exception unless n >= m >= 0
if (n < m || m < 0) {
throw Message.getInternalError("n < m or m < 0");
}
/**
* index is an array of ints that keep track of the next permutation to
* return. For example, an index on a permutation of 3 things might
* contain {1 2 0}. This index will be followed by {2 0 1} and {2 1 0}.
* Initially, the index is {0 ... n - 1}.
*/
this.in = in;
this.out = out;
index = new int[n];
for (int i = 0; i < n; i++) {
index[i] = i;
}
/**
* The elements from m to n are always kept ascending right to left.
* This keeps the dip in the interesting region.
*/
// The elements from m to n are always kept ascending right to left.
// This keeps the dip in the interesting region.
reverseAfter(m - 1);
}
/**
* @return true, unless we have already returned the last permutation.
*/
public boolean hasMoreElements() {
return hasMore;
}
/**
* Move the index forward a notch. The algorithm first finds the rightmost
* index that is less than its neighbor to the right. This is the dip point.
* The algorithm next finds the least element to the right of the dip that
* is greater than the dip. That element is switched with the dip. Finally,
* the list of elements to the right of the dip is reversed.
* <p>
* For example, in a permutation of 5 items, the index may be {1, 2, 4, 3,
* 0}. The dip is 2 the rightmost element less than its neighbor on its
* right. The least element to the right of 2 that is greater than 2 is 3.
* These elements are swapped, yielding {1, 3, 4, 2, 0}, and the list right
* of the dip point is reversed, yielding {1, 3, 0, 2, 4}.
* <p>
* The algorithm is from Applied Combinatorics, by Alan Tucker.
*
*/
private void moveIndex() {
// find the index of the first element that dips
int i = rightmostDip();
if (i < 0) {
hasMore = false;
hasNext = false;
return;
}
// find the least greater element to the right of the dip
int leastToRightIndex = i + 1;
for (int j = i + 2; j < n; j++) {
if (index[j] < index[leastToRightIndex] && index[j] > index[i]) {
......@@ -165,46 +71,34 @@ public class Permutations implements java.util.Enumeration {
}
// switch dip element with least greater element to its right
int t = index[i];
index[i] = index[leastToRightIndex];
index[leastToRightIndex] = t;
if (m - 1 > i) {
// reverse the elements to the right of the dip
reverseAfter(i);
// reverse the elements to the right of m - 1
reverseAfter(m - 1);
}
}
/**
* @return java.lang.Object, the next permutation of the original Object
* array.
* <p>
* Actually, an array of Objects is returned. The declaration must
* say just Object, because the Permutations class implements
* Enumeration, which declares that the nextElement() returns a
* plain Object. Users must cast the returned object to (Object[]).
* Get the index of the first element from the right that is less
* than its neighbor on the right.
*/
public Object nextElement() {
if (!hasMore) {
return null;
}
Object[] out = new Object[m];
for (int i = 0; i < m; i++) {
out[i] = inArray[index[i]];
private int rightmostDip() {
for (int i = n - 2; i >= 0; i--) {
if (index[i] < index[i + 1]) {
return i;
}
}
moveIndex();
return out;
return -1;
}
/**
* Reverse the index elements to the right of the specified index.
* Reverse the elements to the right of the specified index.
*/
private void reverseAfter(int i) {
int start = i + 1;
......@@ -216,19 +110,22 @@ public class Permutations implements java.util.Enumeration {
start++;
end--;
}
}
/**
* @return int the index of the first element from the right that is less
* than its neighbor on the right.
* Go to the next lineup, and if available, fill the target array.
*
* @return if a new lineup is available
*/
private int rightmostDip() {
for (int i = n - 2; i >= 0; i--) {
if (index[i] < index[i + 1]) {
return i;
}
public boolean next() {
if (!hasNext) {
return false;
}
return -1;
for (int i = 0; i < m; i++) {
out[i] = in[index[i]];
}
moveIndex();
return true;
}
}
......@@ -48,7 +48,7 @@ public class Transfer {
this.session = session;
}
public void finalize() {
protected void finalize() {
if (!Constants.RUN_FINALIZERS) {
return;
}
......
......@@ -77,7 +77,7 @@ public class ValueBoolean extends Value {
}
protected boolean isEqual(Value v) {
return v instanceof ValueBoolean && value == ((ValueBoolean)v).value;
return v instanceof ValueBoolean && value.booleanValue() == ((ValueBoolean)v).value.booleanValue();
}
}
......@@ -87,9 +87,82 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
TestAll test = new TestAll();
test.printSystem();
// TODO check that xml is well formed, and html is more or less.
// java.lang.Exception: query was too quick; result: 0 time:1192
// at org.h2.test.TestBase.logError(TestBase.java:219)
// at org.h2.test.db.TestCases$1.run(TestCases.java:158)
// at java.lang.Thread.run(Unknown Source)
// java.lang.Exception: query was too quick; result: 0 time:2203
// at org.h2.test.TestBase.logError(TestBase.java:219)
// at org.h2.test.db.TestCases$1.run(TestCases.java:158)
// at java.lang.Thread.run(Unknown Source)
// java.lang.Error: Results don't match: original (0):
// success
// other:
// exception: 90020: Database may be already open: Concurrent update [90020-36]
// org.h2.jdbc.JdbcSQLException: Database may be already open: Concurrent update [90020-36]
// at org.h2.message.Message.getSQLException(Message.java:67)
// at org.h2.message.Message.getSQLException(Message.java:49)
// at org.h2.store.FileLock.error(FileLock.java:310)
// at org.h2.store.FileLock.lockFile(FileLock.java:182)
// at org.h2.store.FileLock.lock(FileLock.java:65)
// at org.h2.engine.Database.open(Database.java:424)
// at org.h2.engine.Database.<init>(Database.java:382)
// at org.h2.engine.Engine.openSession(Engine.java:44)
// at org.h2.engine.Engine.getSession(Engine.java:85)
// at org.h2.engine.Session.createSession(Session.java:140)
// at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:944)
// at org.h2.Driver.connect(Driver.java:52)
// at java.sql.DriverManager.getConnection(Unknown Source)
// at java.sql.DriverManager.getConnection(Unknown Source)
// at org.h2.test.synth.DbConnection.getConnection(DbConnection.java:83)
// at org.h2.test.synth.DbConnection.connect(DbConnection.java:74)
// at org.h2.test.synth.Command.run(Command.java:229)
// at org.h2.test.synth.TestSynth.process(TestSynth.java:158)
// at org.h2.test.synth.TestSynth.testRun(TestSynth.java:145)
// at org.h2.test.synth.TestSynth.testCase(TestSynth.java:263)
// at org.h2.test.synth.TestSynth.test(TestSynth.java:274)
// at org.h2.test.TestBase.runTest(TestBase.java:59)
// at org.h2.test.TestAll.main(TestAll.java:159)
//
// at org.h2.test.synth.TestSynth.compareResults(TestSynth.java:185)
// at org.h2.test.synth.TestSynth.process(TestSynth.java:164)
// at org.h2.test.synth.TestSynth.testRun(TestSynth.java:145)
// at org.h2.test.synth.TestSynth.testCase(TestSynth.java:263)
// at org.h2.test.synth.TestSynth.test(TestSynth.java:274)
// at org.h2.test.TestBase.runTest(TestBase.java:59)
// at org.h2.test.TestAll.main(TestAll.java:159)
// java.lang.Exception: query was too quick; result: 0 time:1512
// at org.h2.test.TestBase.logError(TestBase.java:219)
// at org.h2.test.db.TestCases$1.run(TestCases.java:158)
// at java.lang.Thread.run(Unknown Source)
// Add FindBugs to Release Checklist
// Hot backup (incremental backup, online backup): backup data, log, index? files
// analyze hibernate read committed tests that fail
// Hibernate: when?
// when? server only? special test with TestAll (only this)
// java.lang.Exception: query was too quick; result: 0 time:1002
// at org.h2.test.TestBase.logError(TestBase.java:219)
// at org.h2.test.db.TestCases$1.run(TestCases.java:158)
// at java.lang.Thread.run(Unknown Source)
// PayPal donate - aaa.html/main.html
// DROP TABLE TEST;
// CREATE TABLE TEST(C CHAR(10));
// INSERT INTO TEST VALUES('1');
// SELECT COUNT(*) FROM TEST WHERE C='1 ';
// -- PostgreSQL, HSQLDB, MySQL, Derby, MS SQL Server, Oracle: 1
// -- H2: 0
// SELECT LENGTH(C), LENGTH(C || 'x') FROM TEST;
// -- MySQL: 1, 1 (??)
// -- MS SQL Server: 1, 11 (SELECT LEN(C), LEN(C + 'x') FROM TEST)
// -- Oracle, Derby: 10, 11
// -- PostgreSQL, H2, HSQLDB: 1, 2
// maybe use system property for base directory (h2.baseDir)
......@@ -98,8 +171,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
// auto-upgrade application:
// check if new version is available
// (option: digital signature)
// (option: RSS / atom newsfeed)
// (option: small XML parser)
// if yes download new version
// (option: http, https, ftp, network)
// backup database to SQL script
......@@ -127,7 +198,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
// test LIKE: compare against other databases
// TestRandomSQL is too random; most statements fails
// extend the random join test that compared the result against PostgreSQL
// Donate a translation: I am looking for people who would help translating the H2 Console into other languages. Please tell me if you think you can help
// long running test with the same database
// repeatable test with a very big database (making backups of the database files)
......
......@@ -35,15 +35,16 @@ public class MergeDocs {
"faq.html",
"license.html"
};
String finalText="";
StringBuffer buff = new StringBuffer();
for(int i=0; i<pages.length; i++) {
String text = getContent(pages[i]);
for(int j=0; j<pages.length; j++) {
text = StringUtils.replaceAll(text, pages[j] + "#", "#");
}
text = removeHeaderFooter(text);
finalText += text;
buff.append(text);
}
String finalText= buff.toString();
File output = new File(baseDir, "onePage.html");
PrintWriter writer = new PrintWriter(new FileWriter(output));
writer.println("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"><title>");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论