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

--no commit message

--no commit message
上级 a17b389f
......@@ -189,7 +189,7 @@ for each connection.
<p>
The MVCC feature allows higher concurrency than using (table level or row level) locks.
When using MVCC in this database, delete, insert and update operations will only issue a
shared lock on the table. Table are still locked exclusively when adding or removing columns,
shared lock on the table. An exclusive lock is still used when adding or removing columns,
when dropping the table, and when using SELECT ... FOR UPDATE. Connections
only 'see' committed data, and own changes. That means, if connection A updates
a row but doesn't commit this change yet, connection B will see the old value.
......@@ -261,14 +261,14 @@ java org.h2.tools.Server
Run the tool on the command line:
<pre>
java org.h2.tools.CreateCluster
-urlSource jdbc:h2:tcp://localhost:9101/test
-urlTarget jdbc:h2:tcp://localhost:9102/test
-urlSource jdbc:h2:tcp://localhost:9101/~/test
-urlTarget jdbc:h2:tcp://localhost:9102/~/test
-user sa
-serverlist localhost:9101,localhost:9102
</pre>
</li><li>You can now connect to the databases using
an application or the H2 Console using the JDBC URL
jdbc:h2:tcp://localhost:9101,localhost:9102/test
jdbc:h2:tcp://localhost:9101,localhost:9102/~/test
</li><li>If you stop a server (by killing the process),
you will notice that the other machine continues to work,
and therefore the database is still accessible.
......@@ -462,7 +462,7 @@ Problems are fixed as they are found.
Currently, statements can not be cancelled when using the PG protocol.
</p>
<p>
PostgreSQL ODBC Driver Setup requires a database password, that means it
PostgreSQL ODBC Driver Setup requires a database password; that means it
is not possible to connect to H2 databases without password. This is a limitation
of the ODBC driver.
</p>
......@@ -568,7 +568,7 @@ The test is included in the H2 download, see org.h2.test.poweroff.Test.
<h3>Ways to (Not) Achieve Durability</h3>
<p>
Making sure that committed transaction are not lost is more complicated than it seems first.
Making sure that committed transactions are not lost is more complicated than it seems first.
To guarantee complete durability, a database must ensure that the log record is on the hard drive
before the commit call returns. To do that, databases use different methods. One
is to use the 'synchronous write' file access mode. In Java, RandomAccessFile
......@@ -589,7 +589,7 @@ then the disk would need to make at least 50 thousand revolutions per second, or
or about 120 revolutions per second. There is an overhead, so the maximum write rate must be lower than that.
</p>
<p>
Buffers can be flushed by calling the function fsync. There are two ways to do that in Java:
Calling fsync flushes the buffers. There are two ways to do that in Java:
</p>
<ul>
<li>FileDescriptor.sync(). The documentation says that this forces all system buffers to synchronize with the underlying device.
......@@ -605,7 +605,7 @@ Unfortunately, even when calling FileDescriptor.sync() or FileChannel.force(),
data is not always persisted to the hard drive, because most hard drives do not obey
fsync(): see
<a href="http://hardware.slashdot.org/article.pl?sid=05/05/13/0529252">Your Hard Drive Lies to You</a>.
In Mac OS X fsync does not flush hard drive buffers, see
In Mac OS X, fsync does not flush hard drive buffers. See
<a href="http://lists.apple.com/archives/darwin-dev/2005/Feb/msg00072.html">Bad fsync?</a>.
So the situation is confusing, and tests prove there is a problem.
</p>
......@@ -835,7 +835,7 @@ By default all classes are allowed. Example:
java -Dh2.allowedClasses=java.lang.Math,com.acme.*
</pre>
This mechanism is used for all user classes, including database event listeners,
trigger classes, user defined functions, user defined aggregate functions, and JDBC
trigger classes, user-defined functions, user-defined aggregate functions, and JDBC
driver classes (with the exception of the H2 driver) when using the H2 Console.
</p>
......@@ -910,7 +910,7 @@ encrypted using the AES-128 or XTEA algorithm.
When decrypting, the operation is done in reverse. First, the block is decrypted using the key,
and then the IV is calculated combined with the decrypted text using XOR.
</p><p>
Therefore, the block cipher modes of operation is CBC (Cipher-block chaining), but each chain
Therefore, the block cipher mode of operation is CBC (Cipher-block chaining), but each chain
is only one block long. The advantage over the ECB (Electronic codebook) mode is that patterns
in the data are not revealed, and the advantage over multi block CBC is that flipped cipher text bits
are not propagated to flipped plaintext bits in the next block.
......
......@@ -199,7 +199,7 @@ Change Log
<h2>Version 1.0.63 (2007-12-02)</h2>
<ul>
<li>The SecurePassword example has been improved.
</li><li>In timezones where the summer time saving limit is at midnight, some dates do not work in some virtual machines, for example 2007-10-14 in Chile, using the Sun JVM 1.6.0_03-b05. Fixed.
</li><li>In time zones where the summer time saving limit is at midnight, some dates do not work in some virtual machines, for example 2007-10-14 in Chile, using the Sun JVM 1.6.0_03-b05. Fixed.
</li><li>The native fulltext search was not working properly after re-connecting.
</li><li>Improved FTP server: now the PORT command is supported.
</li><li>Temporary views (FROM(...)) with UNION didn't work if nested. Fixed.
......@@ -316,7 +316,7 @@ Change Log
<h2>Version 1.0.57 (2007-08-25)</h2>
<ul>
<li>New experimental feature MVCC (multi version concurrency control). Can be set as a option when opening the database (jdbc:h2:test;MVCC=TRUE) or as a system property (-Dh2.mvcc=true). This is work-in-progress, use it at your own risk. Feedback is welcome.
<li>New experimental feature MVCC (multi version concurrency control). Can be set as a option when opening the database (jdbc:h2:~/test;MVCC=TRUE) or as a system property (-Dh2.mvcc=true). This is work-in-progress, use it at your own risk. Feedback is welcome.
</li><li>The version number is now major.minor.micro where micro is the build number. Not all version are public, so there may be gaps in the micro. The minor changes when there is a file format change.
</li><li>The backup tool (org.h2.tools.Backup) did not work. The restore tool did not work when the -db parameter was used. Fixed. The documentation of the backup tool has been changed: only one database may be backed up at any time.
</li><li>Opening large read-only databases was very slow. Fixed.
......
......@@ -162,7 +162,7 @@ SQLite was not tested because the JDBC driver doesn't support transactions.
<h4>Number of Connections</h4>
<p>
This is mostly a single-connection benchmark.
BenchB uses multiple connections, the other tests one connection.
BenchB uses multiple connections; the other tests use one connection.
</p>
<h4>Real-World Tests</h4>
......@@ -193,7 +193,7 @@ The VM used is Sun JDK 1.5.
When a Java benchmark is run first, the code is not fully compiled and
therefore runs slower than when running multiple times. A benchmark
should always run the same test multiple times and ignore the first run(s).
This benchmark runs three times, the last run counts.
This benchmark runs three times, but only the last run is measured.
</p>
<h4>Memory Usage</h4>
......@@ -201,7 +201,7 @@ This benchmark runs three times, the last run counts.
It is not enough to measure the time taken, the memory usage is important as well.
Performance can be improved in databases by using a bigger in-memory cache,
but there is only a limited amount of memory available on the system.
HSQLDB tables are kept fully in memory by default, this benchmark
HSQLDB tables are kept fully in memory by default; this benchmark
uses 'disk based' tables for all databases.
Unfortunately, it is not so easy to calculate the memory usage of PostgreSQL
and MySQL, because they run in a different process than the test. This benchmark currently
......
......@@ -106,7 +106,7 @@ Roadmap
</li><li>Automatic collection of statistics (auto ANALYZE)
</li><li>Server: client ping from time to time (to avoid timeout - is timeout a problem?)
</li><li>Copy database: Tool with config GUI and batch mode, extensible (example: compare)
</li><li>Document, implement tool for long running transactions using user defined compensation statements
</li><li>Document, implement tool for long running transactions using user-defined compensation statements
</li><li>Support SET TABLE DUAL READONLY
</li><li>Linked schema using CSV files: one schema for a directory of files; support indexes for CSV files
</li><li>Don't write stack traces for common exceptions like duplicate key to the log by default
......@@ -285,7 +285,7 @@ Roadmap
</li><li>Support triggers with a string property or option: SpringTrigger, OSGITrigger
</li><li>Clustering: adding a node should be very fast and without interrupting clients (very short lock)
</li><li>Support materialized views (using triggers)
</li><li>Store dates in local timezone (portability of database files)
</li><li>Store dates in local time zone (portability of database files)
</li><li>Ability to resize the cache array when resizing the cache
</li><li>Automatic conversion from WHERE X>10 AND X>20 to X>20
</li><li>Time based cache writing (one second after writing the log)
......
......@@ -9,7 +9,7 @@ td, input, select, textarea, body, code, pre, td, th {
}
h1, h2, h3, h4, h5 {
font: 9pt Arial, Helvetica, sans-serif;
font: 9pt Tahoma, Arial, Helvetica, sans-serif;
font-weight: bold;
}
......
......@@ -39,7 +39,7 @@ Tutorial
<a href="#fulltext">
Fulltext Search</a><br />
<a href="#user_defined_variables">
User Defined Variables</a><br />
User-Defined Variables</a><br />
<a href="#date_time">
Date and Time</a><br />
......@@ -271,13 +271,13 @@ This will start the Server with the default options. To get the list of options
<pre>
java org.h2.tools.Server -?
</pre>
There are options available to use a different ports, and start or not start
There are options available to use different ports, and start or not start
parts of the Server and so on. For details, see the API documentation of the Server tool.
</p>
<h3>Connecting to the TCP Server</h3>
<p>
To remotly connect to a database using the TCP server, use the following driver and database URL:
To remotely connect to a database using the TCP server, use the following driver and database URL:
</p>
<ul>
<li>JDBC driver class: org.h2.Driver
......@@ -313,7 +313,7 @@ To stop the server from a user application, use the following code:
org.h2.tools.Server.shutdownTcpServer("tcp://localhost:9094");
</pre>
This function will call System.exit on the server.
This function should be called after all connection to the databases are closed
This function should be called after all connections to the databases are closed
to avoid recovery when the databases are opened the next time.
To stop remote server, remote connections must be enabled on the server.
</p>
......@@ -346,7 +346,7 @@ applications. Here are some examples if you use Tomcat or JBoss.
<h3>Embedded Mode</h3>
<p>
The (currently) most simple solution is to use the database in the
The (currently) simplest solution is to use the database in the
embedded mode, that means open a connection in your application when
it starts (a good solution is using a Servlet Listener, see below), or
when a session starts. A database can be accessed from multiple
......@@ -357,7 +357,7 @@ clustered mode). Tomcat uses multiple threads and multiple
classloaders. If multiple applications access the same database at the
same time, you need to put the database jar in the shared/lib or
server/lib directory. It is a good idea to open the database when the
web application starts, and close it when the web applications stops.
web application starts, and close it when the web application stops.
If using multiple applications, only one (any) of them needs to do
that. In the application, an idea is to use one connection per
Session, or even one connection per request (action). Those
......@@ -507,12 +507,12 @@ java -cp h2.jar org.h2.tools.Backup -?
The command line tools are:
</p>
<ul><li><b>Backup</b> creates a backup of a database.
</li><li><b>ChangePassword</b> allows to change the file password of a database.
</li><li><b>ChangePassword</b> allows changing the file password of a database.
</li><li><b>Console</b> starts the browser based H2 Console.
</li><li><b>ConvertTraceFile</b> converts a .trace.db file to a Java application and SQL script.
</li><li><b>CreateCluster</b> creates a cluster from a standalone database.
</li><li><b>DeleteDbFiles</b> deletes all files belonging to a database.
</li><li><b>Script</b> allows to convert a database to a SQL script for backup or migration.
</li><li><b>Script</b> allows converting a database to a SQL script for backup or migration.
</li><li><b>Recover</b> helps recovering a corrupted database.
</li><li><b>Restore</b> restores a backup of a database.
</li><li><b>RunScript</b> runs a SQL script against a database.
......@@ -535,7 +535,7 @@ The steps to connect to a H2 database are:
<li>Stop OpenOffice, including the autostart
</li><li>Copy h2.jar into the directory &lt;OpenOffice&gt;\program\classes
</li><li>Start OpenOffice Base
</li><li>Connect to an existing database, select JDBC, [Next]
</li><li>Connect to an existing database; select JDBC; [Next]
</li><li>Example datasource URL: jdbc:h2:c:/temp/test
</li><li>JDBC driver class: org.h2.Driver
</li></ul>
......@@ -655,7 +655,7 @@ org.h2.fulltext.FullText.search(conn, text, limit, offset)
<p>
To use the Lucene full text search, you need the Lucene library in the classpath.
How his is done depends on the application; if you use the H2 Console, you can add the Lucene
jar file to the the environment variables H2DRIVERS or CLASSPATH.
jar file to the environment variables H2DRIVERS or CLASSPATH.
To initialize the Lucene full text search in a database, call:
</p>
<pre>
......@@ -686,9 +686,9 @@ org.h2.fulltext.FullTextLucene.search(conn, text, limit, offset)
</pre>
<br /><a name="user_defined_variables"></a>
<h2>User Defined Variables</h2>
<h2>User-Defined Variables</h2>
<p>
This database supports user defined variables. Variables start with @ and can be used whereever
This database supports user-defined variables. Variables start with @ and can be used wherever
expressions or parameters are used. Variables not persisted and session scoped, that means only visible for
the session where they are defined. A value is usually assigned using the SET command:
</p>
......@@ -703,24 +703,24 @@ SET @TOTAL = NULL;
SELECT X, SET(@TOTAL, IFNULL(@TOTAL, 1.) * X) F FROM SYSTEM_RANGE(1, 50);
</pre>
<p>
Variables that are not set evaluate to NULL. The data type of a user defined variable is the data type
Variables that are not set evaluate to NULL. The data type of a user-defined variable is the data type
of the value assigned to it, that means it is not necessary (or possible) to declare variable names before using them.
There are no restrictions on the assigned values, large objects (LOBs) are supported as well.
There are no restrictions on the assigned values; large objects (LOBs) are supported as well.
</p>
<br /><a name="date_time"></a>
<h2>Date and Time</h2>
<p>
Date, time and timestamp values support ISO 8601 formatting, including timezone:
Date, time and timestamp values support ISO 8601 formatting, including time zone:
<pre>
CALL TIMESTAMP '2008-01-01 12:00:00+01:00';
</pre>
If the timezone is not set, the value is parsed using the current timezone setting of the system.
If the time zone is not set, the value is parsed using the current time zone setting of the system.
Date and time information is stored in H2 database files in GMT (Greenwich Mean Time).
If the database is opened using another system timezone, the date and time will change accordingly.
If you want to move a database from one timezone to the other and don't want this to happen,
If the database is opened using another system time zone, the date and time will change accordingly.
If you want to move a database from one time zone to the other and don't want this to happen,
you need to create a SQL script file using the SCRIPT command or Script tool, and then load
the database using the RUNSCRIPT command or the RunScript tool in the new timezone.
the database using the RUNSCRIPT command or the RunScript tool in the new time zone.
</p>
</div></td></tr></table><!-- analytics --></body></html>
......@@ -125,7 +125,7 @@
90102=Unsupported compression options\: {0}
90103=Unsupported compression algorithm\: {0}
90104=Compression error
90105=Exception calling user defined function
90105=Exception calling user-defined function
90106=Cannot truncate {0}
90107=Cannot drop {0} because {1} depends on it
90108=Stack overflow (recursive query or function?)
......
......@@ -9,7 +9,7 @@ import java.sql.Connection;
import java.sql.SQLException;
/**
* A user defined aggregate function needs to implement this interface.
* A user-defined aggregate function needs to implement this interface.
* The class must be public and must have a public non-argument constructor.
*/
public interface AggregateFunction {
......
......@@ -8,6 +8,6 @@ Initial Developer: H2 Group
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;">
Contains interfaces for user defined extensions, such as triggers and user defined aggregate functions.
Contains interfaces for user-defined extensions, such as triggers and user-defined aggregate functions.
</body></html>
\ No newline at end of file
......@@ -1413,7 +1413,7 @@ public class ErrorCode {
/**
* The error with code <code>90105</code> is thrown when
* an exception occured in a user defined method.
* an exception occured in a user-defined method.
* Example:
* <pre>
* CREATE ALIAS SYS_PROP FOR "java.lang.System.getProperty";
......@@ -1709,7 +1709,7 @@ public class ErrorCode {
/**
* The error with code <code>90132</code> is thrown when
* trying to drop a user defined aggregate function that doesn't exist.
* trying to drop a user-defined aggregate function that doesn't exist.
* Example:
* <pre>
* DROP AGGREGATE UNKNOWN;
......
......@@ -257,6 +257,13 @@ public class SysProperties {
*/
public static final int OBJECT_CACHE_SIZE = getIntSetting("h2.objectCacheSize", 1024);
/**
* System property <code>h2.oldCommandLineOptions</code> (default: true).<br />
* Support old command line options.
*/
// TODO change in version 1.1
public static final boolean OLD_COMMAND_LINE_OPTIONS = getBooleanSetting("h2.oldCommandLineOptions", true);
/**
* System property <code>h2.optimizeDropDependencies</code> (default:
* true).<br />
......
......@@ -86,7 +86,7 @@ public interface DbObject {
int COMMENT = 13;
/**
* This object is a user defined aggregate function.
* This object is a user-defined aggregate function.
*/
int AGGREGATE = 14;
......
......@@ -21,7 +21,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Represents a user defined function, or alias.
* Represents a user-defined function, or alias.
*/
public class FunctionAlias extends DbObjectBase {
......@@ -154,7 +154,7 @@ public class FunctionAlias extends DbObjectBase {
}
/**
* Call the user defined function and return the value.
* Call the user-defined function and return the value.
*
* @param session the session
* @param args the argument list
......
......@@ -14,7 +14,7 @@ import org.h2.message.Trace;
import org.h2.table.Table;
/**
* Represents a user defined aggregate function.
* Represents a user-defined aggregate function.
*/
public class UserAggregate extends DbObjectBase {
......
......@@ -13,7 +13,7 @@ import org.h2.table.Column;
import org.h2.table.Table;
/**
* Represents a domain (user defined data type).
* Represents a domain (user-defined data type).
*/
public class UserDataType extends DbObjectBase {
......
......@@ -1152,7 +1152,7 @@ public class Function extends Expression implements FunctionCall {
Calendar calendar = Calendar.getInstance();
long t1 = d1.getTime(), t2 = d2.getTime();
// need to convert to UTC, otherwise we get inconsistent results with
// certain timezones (those that are 30 minutes off)
// certain time zones (those that are 30 minutes off)
TimeZone zone = calendar.getTimeZone();
calendar.setTime(d1);
t1 += zone.getOffset(calendar.get(Calendar.ERA), calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
......
......@@ -13,7 +13,7 @@ import org.h2.value.ValueResultSet;
/**
* This interface is used by the built-in functions,
* as well as the user defined functions.
* as well as the user-defined functions.
*/
public interface FunctionCall {
......
......@@ -23,7 +23,7 @@ import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* This class wraps a user defined aggregate.
* This class wraps a user-defined aggregate.
*/
public class JavaAggregate extends Expression {
......
......@@ -17,7 +17,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
/**
* This class wraps a user defined function.
* This class wraps a user-defined function.
*/
public class JavaFunction extends Expression implements FunctionCall {
......
......@@ -15,7 +15,7 @@ import org.h2.table.TableFilter;
import org.h2.value.Value;
/**
* A user defined variable, for example: @ID.
* A user-defined variable, for example: @ID.
*/
public class Variable extends Expression {
......
......@@ -1133,7 +1133,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements DatabaseMetaDat
}
/**
* Gets the list of user defined data types.
* Gets the list of user-defined data types.
* This call returns an empty result set.
*
* <ul>
......
......@@ -578,8 +578,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
}
/**
* Sets the date using a specified timezone. The value will be converted to
* the local timezone.
* Sets the date using a specified time zone. The value will be converted to
* the local time zone.
*
* @param parameterIndex the parameter index (1, 2, ...)
* @param x the value
......@@ -602,8 +602,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
}
/**
* Sets the time using a specified timezone. The value will be converted to
* the local timezone.
* Sets the time using a specified time zone. The value will be converted to
* the local time zone.
*
* @param parameterIndex the parameter index (1, 2, ...)
* @param x the value
......@@ -626,8 +626,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
}
/**
* Sets the timestamp using a specified timezone. The value will be
* converted to the local timezone.
* Sets the timestamp using a specified time zone. The value will be
* converted to the local time zone.
*
* @param parameterIndex the parameter index (1, 2, ...)
* @param x the value
......
......@@ -818,7 +818,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
/**
* Returns the value of the specified column as a java.sql.Date using a
* specified timezone.
* specified time zone.
*
* @param columnIndex (1,2,...)
* @param calendar the calendar
......@@ -840,7 +840,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
/**
* Returns the value of the specified column as a java.sql.Date using a
* specified timezone.
* specified time zone.
*
* @param columnName the name of the column label
* @param calendar the calendar
......@@ -862,7 +862,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
/**
* Returns the value of the specified column as a java.sql.Time using a
* specified timezone.
* specified time zone.
*
* @param columnIndex (1,2,...)
* @param calendar the calendar
......@@ -884,7 +884,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
/**
* Returns the value of the specified column as a java.sql.Time using a
* specified timezone.
* specified time zone.
*
* @param columnName the name of the column label
* @param calendar the calendar
......@@ -906,7 +906,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
/**
* Returns the value of the specified column as a java.sql.Timestamp using a
* specified timezone.
* specified time zone.
*
* @param columnIndex (1,2,...)
* @param calendar the calendar
......
......@@ -6,6 +6,7 @@
package org.h2.message;
import org.h2.constant.SysProperties;
import org.h2.util.StringUtils;
/**
* This class represents a trace module.
......@@ -71,28 +72,10 @@ public class Trace {
}
public void infoSQL(String sql) {
sql = replaceNewline(sql);
if (sql.startsWith("/*")) {
sql = sql.substring(sql.indexOf("*/") + 2).trim();
}
sql = StringUtils.javaEncode(sql);
traceSystem.write(TraceSystem.INFO, module, lineSeparator + "/*SQL*/" + sql, null);
}
private String replaceNewline(String s) {
if (s.indexOf('\r') < 0 && s.indexOf('\n') < 0) {
return s;
}
StringBuffer buff = new StringBuffer(s.length());
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '\r' || ch == '\n') {
ch = ' ';
}
buff.append(ch);
}
return buff.toString();
}
public void debug(String s) {
traceSystem.write(TraceSystem.DEBUG, module, s, null);
}
......
......@@ -125,7 +125,7 @@
90102=Unsupported compression options\: {0}
90103=Unsupported compression algorithm\: {0}
90104=Compression error
90105=Exception calling user defined function
90105=Exception calling user-defined function
90106=Cannot truncate {0}
90107=Cannot drop {0} because {1} depends on it
90108=Stack overflow (recursive query or function?)
......
......@@ -344,7 +344,7 @@ COMMENT ON TABLE TEST IS 'Table used for testing'
"Commands (DDL)","CREATE AGGREGATE","
CREATE AGGREGATE [IF NOT EXISTS] newAggregateName FOR className
","
Creates a new user defined aggregate function. The method name must be the full qualified class name.
Creates a new user-defined aggregate function. The method name must be the full qualified class name.
The class must implement the interface org.h2.api.AggregateFunction.
Admin rights are required to execute this command.
","
......@@ -502,7 +502,7 @@ CREATE VIEW TEST_VIEW AS SELECT * FROM TEST WHERE ID < 100
"Commands (DDL)","DROP AGGREGATE","
DROP AGGREGATE [IF EXISTS] aggregateName
","
Drops an existing user defined aggregate function.
Drops an existing user-defined aggregate function.
Admin rights are required to execute this command.
","
CREATE AGGREGATE MEDIAN
......@@ -521,7 +521,7 @@ CREATE ALIAS MY_SQRT
DROP ALL OBJECTS [DELETE FILES]
","
Drops all existing views, tables, sequences, schemas, function aliases, roles,
user defined aggregate functions, domains, and users (except the current user).
user-defined aggregate functions, domains, and users (except the current user).
If DELETE FILES is specified, the database files will be
removed when the last user disconnects from the database.
Warning: This command can not be rolled back.
......@@ -732,7 +732,7 @@ SAVEPOINT HALF_DONE
"Commands (Other)","SET @","
SET @variableName [=] expression
","
Updates a user defined variable.
Updates a user-defined variable.
","
SET @TOTAL=0
"
......@@ -2518,7 +2518,7 @@ Returns a specific value from a timestamps.
EXTRACT(SECOND FROM CURRENT_TIMESTAMP)
"
"Functions (Time and Date)","FORMATDATETIME","
FORMATDATETIME(timestamp, formatString [, localeString [, timezoneString]]): string
FORMATDATETIME(timestamp, formatString [, localeString [, timeZoneString]]): string
","
Formats a date, time or timestamp as a string.
The most important format characters are: y year, M month, d day, H hour, m minute, s second
......@@ -2555,7 +2555,7 @@ Returns the name of the month (in English).
MONTHNAME(CREATED)
"
"Functions (Time and Date)","PARSEDATETIME","
PARSEDATETIME(string, formatString [, localeString [, timezoneString]]): string
PARSEDATETIME(string, formatString [, localeString [, timeZoneString]]): string
","
Parses a string and returns a timestamp.
The most important format characters are: y year, M month, d day, H hour, m minute, s second
......
......@@ -16,7 +16,7 @@ import org.h2.table.Table;
import org.h2.value.Value;
/**
* A user defined constant as created by the SQL statement
* A user-defined constant as created by the SQL statement
* CREATE CONSTANT
*/
public class Constant extends SchemaObjectBase {
......
......@@ -104,7 +104,7 @@ public class TriggerObject extends SchemaObjectBase {
}
/**
* Call the fire method of the user defined trigger class.
* Call the fire method of the user-defined trigger class.
*
* @param session the session
* @param oldRow the old row
......
......@@ -22,9 +22,11 @@ import java.util.Properties;
import java.util.Set;
import org.h2.Driver;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.message.Message;
import org.h2.message.TraceSystem;
import org.h2.tools.Server;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -47,10 +49,9 @@ public class TcpServer implements Service {
public static final int DEFAULT_PORT = 9092;
private static final int SHUTDOWN_NORMAL = 0;
private static final int SHUTDOWN_FORCE = 1;
public static boolean logInternalErrors;
private int port;
private boolean log;
private boolean trace;
private boolean ssl;
private boolean stop;
private ServerSocket serverSocket;
......@@ -147,10 +148,18 @@ public class TcpServer implements Service {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if ("-log".equals(a)) {
log = Boolean.valueOf(args[++i]).booleanValue();
if ("-trace".equals(a)) {
trace = true;
} else if ("-log".equals(a) && SysProperties.OLD_COMMAND_LINE_OPTIONS) {
trace = Server.readArgBoolean(args, i) == 1;
i++;
} else if ("-tcpSSL".equals(a)) {
ssl = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
ssl = Server.readArgBoolean(args, i) == 1;
i++;
} else {
ssl = true;
}
} else if ("-tcpPort".equals(a)) {
port = MathUtils.decodeInt(args[++i]);
} else if ("-tcpPassword".equals(a)) {
......@@ -158,9 +167,19 @@ public class TcpServer implements Service {
} else if ("-baseDir".equals(a)) {
baseDir = args[++i];
} else if ("-tcpAllowOthers".equals(a)) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
allowOthers = Server.readArgBoolean(args, i) == 1;
i++;
} else {
allowOthers = true;
}
} else if ("-ifExists".equals(a)) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
ifExists = Server.readArgBoolean(args, i) == 1;
i++;
} else {
ifExists = true;
}
}
}
org.h2.Driver.load();
......@@ -287,15 +306,14 @@ public class TcpServer implements Service {
return baseDir;
}
void log(String s) {
// TODO log: need concept for server log
if (log) {
void trace(String s) {
if (trace) {
System.out.println(s);
}
}
void logError(Throwable e) {
if (log) {
void traceError(Throwable e) {
if (trace) {
e.printStackTrace();
}
}
......@@ -312,13 +330,6 @@ public class TcpServer implements Service {
return "H2 TCP Server";
}
public void logInternalError(String string) {
if (logInternalErrors) {
System.out.println(string);
new Error(string).printStackTrace();
}
}
public boolean getIfExists() {
return ifExists;
}
......
......@@ -49,14 +49,14 @@ public class TcpServerThread implements Runnable {
transfer.setSocket(socket);
}
private void log(String s) {
server.log(this + " " + s);
private void trace(String s) {
server.trace(this + " " + s);
}
public void run() {
try {
transfer.init();
log("Connect");
trace("Connect");
// TODO server: should support a list of allowed databases and a
// list of allowed clients
try {
......@@ -94,7 +94,7 @@ public class TcpServerThread implements Runnable {
transfer.setSession(session);
transfer.writeInt(SessionRemote.STATUS_OK).flush();
server.addConnection(id, originalURL, ci.getUserName());
log("Connected");
trace("Connected");
} catch (Throwable e) {
sendError(e);
stop = true;
......@@ -106,9 +106,9 @@ public class TcpServerThread implements Runnable {
sendError(e);
}
}
log("Disconnect");
trace("Disconnect");
} catch (Throwable e) {
server.logError(e);
server.traceError(e);
} finally {
close();
}
......@@ -122,7 +122,7 @@ public class TcpServerThread implements Runnable {
session.close();
server.removeConnection(id);
} catch (Exception e) {
server.logError(e);
server.traceError(e);
} finally {
session = null;
}
......@@ -134,9 +134,9 @@ public class TcpServerThread implements Runnable {
stop = true;
closeSession();
transfer.close();
log("Close");
trace("Close");
} catch (Exception e) {
server.logError(e);
server.traceError(e);
}
server.remove(this);
}
......@@ -160,7 +160,7 @@ public class TcpServerThread implements Runnable {
transfer.writeInt(SessionRemote.STATUS_ERROR).writeString(s.getSQLState()).writeString(message)
.writeString(sql).writeInt(s.getErrorCode()).writeString(trace).flush();
} catch (IOException e2) {
server.logError(e2);
server.traceError(e2);
// if writing the error does not work, close the connection
stop = true;
}
......@@ -298,8 +298,7 @@ public class TcpServerThread implements Runnable {
break;
}
default:
server.logInternalError("Unknown operation: " + operation);
server.log("Unknown operation: " + operation);
trace("Unknown operation: " + operation);
closeSession();
close();
}
......
......@@ -74,7 +74,7 @@ public class FtpControl extends Thread {
}
}
} catch (Throwable t) {
server.logError(t);
server.traceError(t);
}
server.closeConnection();
}
......@@ -91,7 +91,7 @@ public class FtpControl extends Thread {
reply(506, "No command");
return;
}
server.log(">" + command);
server.trace(">" + command);
FtpEventListener listener = server.getEventListener();
FtpEvent event = null;
if (listener != null) {
......@@ -227,7 +227,7 @@ public class FtpControl extends Thread {
data = new FtpData(server, address, port);
reply(200, "Ok");
} else {
server.log("Port REJECTED:" + address + " expected:" + control.getInetAddress());
server.trace("Port REJECTED:" + address + " expected:" + control.getInetAddress());
reply(550, "Failed");
}
}
......@@ -254,7 +254,7 @@ public class FtpControl extends Thread {
reply(250, "Ok");
ok = true;
} catch (SQLException e) {
server.logError(e);
server.traceError(e);
}
}
if (!ok) {
......@@ -269,7 +269,7 @@ public class FtpControl extends Thread {
data.send(fs, fileName, restart);
reply(226, "Ok");
} catch (IOException e) {
server.logError(e);
server.traceError(e);
reply(426, "Failed");
}
restart = 0;
......@@ -312,7 +312,7 @@ public class FtpControl extends Thread {
}
reply(226, "Ok");
} catch (Exception e) {
server.logError(e);
server.traceError(e);
reply(426, "Failed");
}
} else {
......@@ -359,7 +359,7 @@ public class FtpControl extends Thread {
reply(257, StringUtils.quoteIdentifier(param) + " directory");
ok = true;
} catch (SQLException e) {
server.logError(e);
server.traceError(e);
}
}
if (!ok) {
......@@ -395,7 +395,7 @@ public class FtpControl extends Thread {
}
String list = server.getDirectoryListing(directory, directories);
reply(150, "Starting transfer");
server.log(list);
server.trace(list);
// need to use the current locale (UTF-8 would be wrong for the Windows
// Explorer)
data.send(list.getBytes());
......@@ -403,7 +403,7 @@ public class FtpControl extends Thread {
}
private void reply(int code, String message) throws IOException {
server.log(code + " " + message);
server.trace(code + " " + message);
output.print(code + " " + message + "\r\n");
output.flush();
replied = true;
......
......@@ -46,11 +46,11 @@ public class FtpData extends Thread {
synchronized (this) {
Socket s = serverSocket.accept();
if (s.getInetAddress().equals(address)) {
server.log("Data connected:" + s.getInetAddress() + " expected:" + address);
server.trace("Data connected:" + s.getInetAddress() + " expected:" + address);
socket = s;
notifyAll();
} else {
server.log("Data REJECTED:" + s.getInetAddress() + " expected:" + address);
server.trace("Data REJECTED:" + s.getInetAddress() + " expected:" + address);
close();
}
}
......@@ -75,7 +75,7 @@ public class FtpData extends Thread {
// ignore
}
}
server.log("connected");
server.trace("connected");
}
public void close() {
......@@ -93,7 +93,7 @@ public class FtpData extends Thread {
} finally {
socket.close();
}
server.log("closed");
server.trace("closed");
}
public synchronized void send(FileSystem fs, String fileName, long skip) throws IOException {
......@@ -107,7 +107,7 @@ public class FtpData extends Thread {
} finally {
socket.close();
}
server.log("closed");
server.trace("closed");
}
public synchronized void send(byte[] data) throws IOException {
......@@ -118,7 +118,7 @@ public class FtpData extends Thread {
} finally {
socket.close();
}
server.log("closed");
server.trace("closed");
}
}
......@@ -18,9 +18,11 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.server.Service;
import org.h2.store.fs.FileSystem;
import org.h2.tools.Server;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
......@@ -53,7 +55,7 @@ public class FtpServer implements Service {
private HashMap tasks = new HashMap();
private FileSystem fs;
private boolean log;
private boolean trace;
private boolean allowTask;
static final String TASK_SUFFIX = ".task";
......@@ -72,7 +74,7 @@ public class FtpServer implements Service {
c.start();
}
} catch (Exception e) {
logError(e);
traceError(e);
}
}
......@@ -135,7 +137,7 @@ public class FtpServer implements Service {
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
log("path: " + path);
trace("path: " + path);
return path;
}
......@@ -172,10 +174,13 @@ public class FtpServer implements Service {
writeUserName = args[++i];
} else if ("-ftpWritePassword".equals(a)) {
writePassword = args[++i];
} else if ("-log".equals(a)) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-trace".equals(a)) {
trace = true;
} else if ("-log".equals(a) && SysProperties.OLD_COMMAND_LINE_OPTIONS) {
trace = Server.readArgBoolean(args, i) == 1;
i++;
} else if ("-ftpTask".equals(a)) {
allowTask = Boolean.valueOf(args[++i]).booleanValue();
allowTask = true;
}
}
fs = FileSystem.getInstance(root);
......@@ -195,7 +200,7 @@ public class FtpServer implements Service {
try {
serverSocket.close();
} catch (IOException e) {
logError(e);
traceError(e);
}
serverSocket = null;
}
......@@ -225,14 +230,14 @@ public class FtpServer implements Service {
return "H2 FTP Server";
}
void log(String s) {
if (log) {
void trace(String s) {
if (trace) {
System.out.println(s);
}
}
void logError(Throwable e) {
if (log) {
void traceError(Throwable e) {
if (trace) {
e.printStackTrace();
}
}
......@@ -244,7 +249,7 @@ public class FtpServer implements Service {
void startTask(String path) throws IOException {
stopTask(path);
if (path.endsWith(".zip.task")) {
log("expand: " + path);
trace("expand: " + path);
Process p = Runtime.getRuntime().exec("jar -xf " + path, null, new File(root));
new StreamRedirect(path, p.getInputStream(), null).start();
return;
......@@ -254,7 +259,7 @@ public class FtpServer implements Service {
String outFile = path.substring(0, path.length() - TASK_SUFFIX.length());
String errorFile = root + "/" + prop.getProperty("error", outFile + ".err.txt");
String outputFile = root + "/" + prop.getProperty("output", outFile + ".out.txt");
log("start process: " + path + " / " + command);
trace("start process: " + path + " / " + command);
Process p = Runtime.getRuntime().exec(command, null, new File(root));
new StreamRedirect(path, p.getErrorStream(), errorFile).start();
new StreamRedirect(path, p.getInputStream(), outputFile).start();
......@@ -306,7 +311,7 @@ public class FtpServer implements Service {
}
void stopTask(String processName) {
log("kill process: " + processName);
trace("kill process: " + processName);
Process p = (Process) tasks.remove(processName);
if (p == null) {
return;
......
......@@ -18,8 +18,10 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.server.Service;
import org.h2.tools.Server;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -35,7 +37,7 @@ public class PgServer implements Service {
private int port = PgServer.DEFAULT_PORT;
private boolean stop;
private boolean log;
private boolean trace;
private ServerSocket serverSocket;
private Set running = Collections.synchronizedSet(new HashSet());
private String baseDir;
......@@ -47,16 +49,29 @@ public class PgServer implements Service {
port = DEFAULT_PORT;
for (int i = 0; i < args.length; i++) {
String a = args[i];
if ("-log".equals(a)) {
log = Boolean.valueOf(args[++i]).booleanValue();
if ("-trace".equals(a)) {
trace = true;
} else if ("-log".equals(a) && SysProperties.OLD_COMMAND_LINE_OPTIONS) {
trace = Server.readArgBoolean(args, i) == 1;
i++;
} else if ("-pgPort".equals(a)) {
port = MathUtils.decodeInt(args[++i]);
} else if ("-baseDir".equals(a)) {
baseDir = args[++i];
} else if ("-pgAllowOthers".equals(a)) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
allowOthers = Server.readArgBoolean(args, i) == 1;
i++;
} else {
allowOthers = true;
}
} else if ("-ifExists".equals(a)) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
ifExists = Server.readArgBoolean(args, i) == 1;
i++;
} else {
ifExists = true;
}
}
}
org.h2.Driver.load();
......@@ -66,12 +81,12 @@ public class PgServer implements Service {
// log = true;
}
boolean getLog() {
return log;
boolean getTrace() {
return trace;
}
void log(String s) {
if (log) {
void trace(String s) {
if (trace) {
System.out.println(s);
}
}
......@@ -80,8 +95,8 @@ public class PgServer implements Service {
running.remove(t);
}
void logError(Exception e) {
if (log) {
void traceError(Exception e) {
if (trace) {
e.printStackTrace();
}
}
......@@ -107,7 +122,7 @@ public class PgServer implements Service {
while (!stop) {
Socket s = serverSocket.accept();
if (!allow(s)) {
log("Connection not allowed");
trace("Connection not allowed");
s.close();
} else {
PgServerThread c = new PgServerThread(s, this);
......
......@@ -70,7 +70,7 @@ public class PgServerThread implements Runnable {
public void run() {
try {
server.log("Connect");
server.trace("Connect");
InputStream ins = socket.getInputStream();
out = socket.getOutputStream();
dataInRaw = new DataInputStream(ins);
......@@ -82,9 +82,9 @@ public class PgServerThread implements Runnable {
// more or less normal disconnect
} catch (Exception e) {
error("process", e);
server.logError(e);
server.traceError(e);
} finally {
server.log("Disconnect");
server.trace("Disconnect");
close();
}
}
......@@ -119,7 +119,7 @@ public class PgServerThread implements Runnable {
private void error(String message, Exception e) {
if (e != null) {
server.logError(e);
server.traceError(e);
}
}
......@@ -141,19 +141,19 @@ public class PgServerThread implements Runnable {
dataIn = new DataInputStream(new ByteArrayInputStream(data, 0, len));
switch (x) {
case 0:
server.log("Init");
server.trace("Init");
int version = readInt();
if (version == 80877102) {
server.log("CancelRequest (not supported)");
server.log(" pid: " + readInt());
server.log(" key: " + readInt());
server.trace("CancelRequest (not supported)");
server.trace(" pid: " + readInt());
server.trace(" key: " + readInt());
error("CancelRequest", null);
} else if (version == 80877103) {
server.log("SSLRequest");
server.trace("SSLRequest");
out.write('N');
} else {
server.log("StartupMessage");
server.log(" version " + version + " (" + (version >> 16) + "." + (version & 0xff) + ")");
server.trace("StartupMessage");
server.trace(" version " + version + " (" + (version >> 16) + "." + (version & 0xff) + ")");
while (true) {
String param = readString();
if (param.length() == 0) {
......@@ -176,7 +176,7 @@ public class PgServerThread implements Runnable {
}
break;
case 'p': {
server.log("PasswordMessage");
server.trace("PasswordMessage");
String password = readString();
try {
ConnectionInfo ci = new ConnectionInfo(databaseName);
......@@ -208,7 +208,7 @@ public class PgServerThread implements Runnable {
break;
}
case 'P': {
server.log("Parse");
server.trace("Parse");
Prepared p = new Prepared();
p.name = readString();
p.sql = getSQL(readString());
......@@ -229,7 +229,7 @@ public class PgServerThread implements Runnable {
break;
}
case 'B': {
server.log("Bind");
server.trace("Bind");
Portal portal = new Portal();
portal.name = readString();
String prepName = readString();
......@@ -268,7 +268,7 @@ public class PgServerThread implements Runnable {
case 'D': {
char type = (char) readByte();
String name = readString();
server.log("Describe");
server.trace("Describe");
PreparedStatement prep;
if (type == 'S') {
Prepared p = (Prepared) prepared.get(name);
......@@ -297,7 +297,7 @@ public class PgServerThread implements Runnable {
}
case 'E': {
String name = readString();
server.log("Execute");
server.trace("Execute");
Portal p = (Portal) portals.get(name);
if (p == null) {
sendErrorResponse("Portal not found: " + name);
......@@ -305,7 +305,7 @@ public class PgServerThread implements Runnable {
}
int maxRows = readShort();
PreparedStatement prep = p.prep;
server.log(p.sql);
server.trace(p.sql);
try {
prep.setMaxRows(maxRows);
boolean result = prep.execute();
......@@ -330,12 +330,12 @@ public class PgServerThread implements Runnable {
break;
}
case 'S': {
server.log("Sync");
server.trace("Sync");
sendReadyForQuery();
break;
}
case 'Q': {
server.log("Query");
server.trace("Query");
String query = readString();
ScriptReader reader = new ScriptReader(new StringReader(query));
while (true) {
......@@ -369,7 +369,7 @@ public class PgServerThread implements Runnable {
break;
}
case 'X': {
server.log("Terminate");
server.trace("Terminate");
close();
break;
}
......@@ -393,8 +393,8 @@ public class PgServerThread implements Runnable {
s = "set DATESTYLE ISO";
}
// s = StringUtils.replaceAll(s, "i.indkey[ia.attnum-1]", "0");
if (server.getLog()) {
server.log(s + ";");
if (server.getTrace()) {
server.trace(s + ";");
}
return s;
}
......@@ -462,7 +462,7 @@ public class PgServerThread implements Runnable {
if (text) {
s = new String(d2, getEncoding());
} else {
server.logError(new SQLException("Binary format not supported"));
server.traceError(new SQLException("Binary format not supported"));
s = new String(d2, getEncoding());
}
} catch (Exception e) {
......@@ -634,9 +634,9 @@ public class PgServerThread implements Runnable {
if (socket != null) {
socket.close();
}
server.log("Close");
server.trace("Close");
} catch (Exception e) {
server.logError(e);
server.traceError(e);
}
conn = null;
socket = null;
......
......@@ -30,6 +30,7 @@ import org.h2.engine.Constants;
import org.h2.message.TraceSystem;
import org.h2.server.Service;
import org.h2.server.ShutdownHandler;
import org.h2.tools.Server;
import org.h2.util.ByteUtils;
import org.h2.util.FileUtils;
import org.h2.util.JdbcUtils;
......@@ -115,6 +116,7 @@ public class WebServer implements Service {
private Thread listenerThread;
private boolean ifExists;
private boolean allowScript;
private boolean trace;
byte[] getFile(String file) throws IOException {
trace("getFile <" + file + ">");
......@@ -195,16 +197,36 @@ public class WebServer implements Service {
if ("-webPort".equals(a)) {
port = MathUtils.decodeInt(args[++i]);
} else if ("-webSSL".equals(a)) {
ssl = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
ssl = Server.readArgBoolean(args, i) == 1;
i++;
} else {
ssl = true;
}
} else if ("-webAllowOthers".equals(a)) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
allowOthers = Server.readArgBoolean(args, i) == 1;
i++;
} else {
allowOthers = true;
}
} else if ("-webScript".equals(a)) {
allowScript = Boolean.valueOf(args[++i]).booleanValue();
allowScript = true;
} else if ("-baseDir".equals(a)) {
String baseDir = args[++i];
SysProperties.setBaseDir(baseDir);
} else if ("-ifExists".equals(a)) {
ifExists = Boolean.valueOf(args[++i]).booleanValue();
if (Server.readArgBoolean(args, i) != 0) {
ifExists = Server.readArgBoolean(args, i) == 1;
i++;
} else {
ifExists = true;
}
} else if ("-trace".equals(a)) {
trace = true;
} else if ("-log".equals(a) && SysProperties.OLD_COMMAND_LINE_OPTIONS) {
trace = Server.readArgBoolean(args, i) == 1;
i++;
}
}
// if(driverList != null) {
......@@ -308,7 +330,9 @@ public class WebServer implements Service {
}
void trace(String s) {
// System.out.println(s);
if (trace) {
System.out.println(s);
}
}
public void traceError(Exception e) {
......
......@@ -42,7 +42,9 @@ public class WebServlet extends HttpServlet {
name = "-" + name;
}
list.add(name);
list.add(value);
if (value.length() > 0) {
list.add(value);
}
}
String[] args = new String[list.size()];
list.toArray(args);
......
......@@ -7,6 +7,7 @@ package org.h2.server.web;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
......@@ -14,6 +15,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
......@@ -48,7 +50,17 @@ import org.h2.bnf.Bnf;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.Message;
import org.h2.message.TraceSystem;
import org.h2.tools.Backup;
import org.h2.tools.ChangePassword;
import org.h2.tools.ConvertTraceFile;
import org.h2.tools.CreateCluster;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Recover;
import org.h2.tools.Restore;
import org.h2.tools.RunScript;
import org.h2.tools.Script;
import org.h2.tools.SimpleResultSet;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
......@@ -59,6 +71,7 @@ import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.util.ScriptReader;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
/**
* For each connection to a session, an object of this class is created.
......@@ -412,6 +425,8 @@ class WebThread extends Thread implements DatabaseEventListener {
file = adminShutdown();
} else if ("autoCompleteList.do".equals(file)) {
file = autoCompleteList();
} else if ("tools.do".equals(file)) {
file = tools();
} else {
file = "error.jsp";
}
......@@ -529,6 +544,52 @@ class WebThread extends Thread implements DatabaseEventListener {
return admin();
}
private String tools() {
try {
String toolName = (String) attributes.get("tool");
session.put("tool", toolName);
String args = (String) attributes.get("args");
String[] argList = StringUtils.arraySplit(args, ',', false);
Tool tool = null;
if ("Backup".equals(toolName)) {
tool = new Backup();
} else if ("Restore".equals(toolName)) {
tool = new Restore();
} else if ("Recover".equals(toolName)) {
tool = new Recover();
} else if ("DeleteDbFiles".equals(toolName)) {
tool = new DeleteDbFiles();
} else if ("ChangePassword".equals(toolName)) {
tool = new ChangePassword();
} else if ("Script".equals(toolName)) {
tool = new Script();
} else if ("RunScript".equals(toolName)) {
tool = new RunScript();
} else if ("ConvertTraceFile".equals(toolName)) {
tool = new ConvertTraceFile();
} else if ("CreateCluster".equals(toolName)) {
tool = new CreateCluster();
} else {
throw Message.getInternalError(toolName);
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bout, false, "UTF-8");
tool.setPrintStream(out);
try {
tool.run(argList);
out.flush();
byte[] data = bout.toByteArray();
String result = new String(data, "UTF-8");
session.put("toolResult", PageParser.escapeHtml(result));
} catch (Exception e) {
session.put("toolResult", getStackTrace(0, e, true));
}
} catch (Exception e) {
server.traceError(e);
}
return "tools.jsp";
}
private String adminShutdown() {
server.shutdown();
return "admin.jsp";
......@@ -1084,6 +1145,7 @@ class WebThread extends Thread implements DatabaseEventListener {
session.remove("result");
session.remove("tables");
session.remove("user");
session.remove("tool");
if (conn != null) {
conn.close();
}
......
......@@ -22,8 +22,8 @@ Initial Developer: H2 Group
</select>
&nbsp;&nbsp; <a href="admin.do?jsessionid=${sessionId}">${text.login.goAdmin}</a>
<!--
&nbsp;&nbsp; <a href="tools.jsp?jsessionid=${sessionId}">${text.login.goTools}</a>
-->
&nbsp;&nbsp; <a href="tools.jsp?jsessionid=${sessionId}">${text.login.goTools}</a>
&nbsp;&nbsp; <a href="help.jsp?jsessionid=${sessionId}">${text.a.help}</a>
</p>
<table class="login" cellspacing="0" cellpadding="0">
......@@ -61,7 +61,9 @@ Initial Developer: H2 Group
<td class="login"><input type="text" name="driver" value="${driver}" style="width:300px;" /></td>
</tr>
<tr class="login">
<td class="login">${text.login.jdbcUrl}:</td>
<td class="login">
<a href="#" onclick="var x=document.getElementById('url').style;x.display=x.display==''?'none':'';">
${text.login.jdbcUrl}</a>:</td>
<td class="login"><input type="text" name="url" value="${url}" style="width:300px;" /></td>
</tr>
<tr class="login">
......@@ -84,6 +86,45 @@ Initial Developer: H2 Group
</tr>
</table>
<br />
<div id="url" style="display: none">
<h2>H2 Database URLs</h2>
<h3>Embedded</h3>
<p>
The URL <code>jdbc:h2:~/test</code> means the database is stored in
the user home directory in files starting with 'test'.
Absolute locations like <code>jdbc:h2:/data/db/test</code> are supported.
In embedded mode, the database runs in the same process as the application.
Only one process may access a database at any time.
Databases are automatically created if they don't exist.
<b>Warning</b>: If no path is used (for example jdbc:h2:test),
then the database is stored in the current working directory
(the directory where the application was started).
URLs of the form jdbc:h2:data/test are relative to
the current working directory. It is recommended to use locations relative to ~
or absolute locations.
</p>
<h4>Remote (client/server)</h4>
<p>
The URL <code>jdbc:h2:tcp://localhost/~/test</code> means connect
over TCP/IP to the H2 TCP server running on this computer, and open a database
called test in the user home directory. The server must be started first.
Any number of clients can connect to the same database.
The same location rules as for embedded databases apply.
</p>
<h4>In-Memory</h4>
<p>
The URL <code>jdbc:h2:mem:test</code> means open an in-memory database
named 'test'. Data is not persisted, and lost when the last connection to the database
is closed. Multiple threads can access the same database, but data is only visible
within the same process.
</p>
<p>
For more information, see <a target="_blank" href="http://www.h2database.com/html/features.html#database_url">Database URL Overview</a>.
</p>
</div>
<p class="error">${error}</p>
</form>
</body></html>
\ No newline at end of file
......@@ -7,25 +7,33 @@ td, input, select, textarea, body, code, pre {
font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif;
}
h1, h2, h3, h4, h5 {
font: 9pt Tahoma, Arial, Helvetica, sans-serif;
font-weight: bold;
}
body {
margin: 4px;
}
code {
background-color: #ece9d8;
padding: 0px 2px;
}
h1 {
border-bottom: 1px solid #CCC;
color: #800;
font-size: 16pt;
background-color: #0000bb;
padding: 2px 4px 2px 4px;
color: #fff;
font-size: 15pt;
line-height: normal;
}
h2 {
border-bottom: 1px solid #CCC;
color: #800;
font-size: 13pt;
}
h3 {
color: #800;
font-size: 10pt;
}
......@@ -39,8 +47,36 @@ li {
margin-top: 6px;
}
.toolbar {
table {
background-color: #ffffff;
border-collapse: collapse;
border: 1px solid #aca899;
}
th {
font-size: 9pt;
font-weight: normal;
text-align: left;
background-color: #ece9d8;
padding: 2px;
border: 1px solid #aca899;
}
td {
background-color: #ffffff;
font-size: 9pt;
padding: 2px;
text-align: left;
vertical-align:top;
border: 1px solid #aca899;
}
form {
}
textarea {
width: 100%;
overflow: auto;
}
.result {
......@@ -48,8 +84,11 @@ li {
margin: 10px;
}
.toolbar {
background-color: #ece9d8;
}
table.toolbar {
background-color: #ffffff;
border-collapse: collapse;
border: 0px;
padding: 0px 0px;
......@@ -140,38 +179,6 @@ p.error {
color: #ff0000;
}
table {
background-color: #ffffff;
border-collapse: collapse;
border: 1px solid #aca899;
}
th {
font-size: 9pt;
font-weight: normal;
text-align: left;
background-color: #ece9d8;
padding: 2px;
border: 1px solid #aca899;
}
td {
background-color: #ffffff;
font-size: 9pt;
padding: 2px;
text-align: left;
vertical-align:top;
border: 1px solid #aca899;
}
form {
}
textarea {
width: 100%;
overflow: auto;
}
input.button {
padding: 1px;
}
......@@ -309,3 +316,7 @@ td.autoCompHide {
display: none;
}
table.tool, table.tool tr, table.tool tr td {
padding: 0px;
border: 0px;
}
......@@ -54,6 +54,8 @@ public class FileSystemDisk extends FileSystem {
}
public void rename(String oldName, String newName) throws SQLException {
oldName = translateFileName(oldName);
newName = translateFileName(newName);
File oldFile = new File(oldName);
File newFile = new File(newName);
if (oldFile.getAbsolutePath().equals(newFile.getAbsolutePath())) {
......
......@@ -27,7 +27,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
/**
* A table backed by a system or user defined function that returns a result set.
* A table backed by a system or user-defined function that returns a result set.
*/
public class FunctionTable extends Table {
......
......@@ -20,16 +20,21 @@ import org.h2.message.Message;
import org.h2.store.FileLister;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.Tool;
/**
* Backs up a H2 database by creating a .zip file from the database files.
*/
public class Backup {
public class Backup extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " [-file <filename>] [-dir <dir>] [-db <database>] [-quiet]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/Backup.html");
out.println("Creates a backup of a database.");
out.println("java "+getClass().getName() + "\n" +
" [-file <filename>] The target file name (default: backup.zip)\n" +
" [-dir <dir>] Source directory (default: .)\n" +
" [-db <database>] Source database name\n" +
" [-quiet] Do not print progress information");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -51,7 +56,7 @@ public class Backup {
new Backup().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String zipFileName = "backup.zip";
String dir = ".";
String db = null;
......@@ -70,12 +75,12 @@ public class Backup {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
}
Backup.execute(zipFileName, dir, db, quiet);
process(zipFileName, dir, db, quiet);
}
/**
......@@ -88,10 +93,14 @@ public class Backup {
* @throws SQLException
*/
public static void execute(String zipFileName, String directory, String db, boolean quiet) throws SQLException {
new Backup().process(zipFileName, directory, db, quiet);
}
private void process(String zipFileName, String directory, String db, boolean quiet) throws SQLException {
ArrayList list = FileLister.getDatabaseFiles(directory, db, true);
if (list.size() == 0) {
if (!quiet) {
System.out.println("No database files found");
out.println("No database files found");
}
return;
}
......@@ -99,10 +108,10 @@ public class Backup {
if (FileUtils.exists(zipFileName)) {
FileUtils.delete(zipFileName);
}
OutputStream out = null;
OutputStream fileOut = null;
try {
out = FileUtils.openFileOutputStream(zipFileName, false);
ZipOutputStream zipOut = new ZipOutputStream(out);
fileOut = FileUtils.openFileOutputStream(zipFileName, false);
ZipOutputStream zipOut = new ZipOutputStream(fileOut);
String base = "";
for (int i = 0; i < list.size(); i++) {
String fileName = (String) list.get(i);
......@@ -132,7 +141,7 @@ public class Backup {
}
zipOut.closeEntry();
if (!quiet) {
System.out.println("processed: " + fileName);
out.println("Processed: " + fileName);
}
}
zipOut.closeEntry();
......@@ -140,7 +149,7 @@ public class Backup {
} catch (IOException e) {
throw Message.convertIOException(e, zipFileName);
} finally {
IOUtils.closeSilently(out);
IOUtils.closeSilently(fileOut);
}
}
......
......@@ -15,26 +15,29 @@ import org.h2.security.SHA256;
import org.h2.store.FileLister;
import org.h2.store.FileStore;
import org.h2.util.FileUtils;
import org.h2.util.Tool;
/**
* A tools to change, remove or set a file password of a database without
* opening it.
*/
public class ChangePassword {
public class ChangePassword extends Tool {
private String dir;
private String cipher;
private byte[] decrypt;
private byte[] encrypt;
// TODO security: maybe allow functions in the url
// jdbc:h2:test;action=[decrypt|encrypt|check|reindex|recover|compress...]
// and/or implement SQL commands that call this functions (only for the admin)
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " [-dir <dir>] [-db <database>] [-cipher <cipher>] [-decrypt <pwd>] [-encrypt <pwd>] [-quiet]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/ChangePassword.html");
out.println("Allows changing the database file password.");
out.println("java "+getClass().getName() + "\n" +
" -cipher <type> AES or XTEA\n" +
" [-dir <dir>] The database directory (default: .)\n" +
" [-db <database>] The database name (default: all databases)\n" +
" [-decrypt <pwd>] The decryption password (default: the database is not yet encrypted)\n" +
" [-encrypt <pwd>] The encryption password (default: the database should not be encrypted)\n" +
" [-quiet] Do not print progress information");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -58,7 +61,7 @@ public class ChangePassword {
new ChangePassword().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String dir = ".";
String cipher = null;
char[] decryptPassword = null;
......@@ -83,16 +86,16 @@ public class ChangePassword {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
}
if (encryptPassword == null && decryptPassword == null) {
if ((encryptPassword == null && decryptPassword == null) || cipher == null) {
showUsage();
return;
}
execute(dir, db, cipher, decryptPassword, encryptPassword, quiet);
process(dir, db, cipher, decryptPassword, encryptPassword, quiet);
}
/**
......@@ -123,7 +126,19 @@ public class ChangePassword {
* @throws SQLException
*/
public static void execute(String dir, String db, String cipher, char[] decryptPassword, char[] encryptPassword, boolean quiet) throws SQLException {
new ChangePassword().process(dir, db, cipher, decryptPassword, encryptPassword, quiet);
}
private void process(String dir, String db, String cipher, char[] decryptPassword, char[] encryptPassword, boolean quiet) throws SQLException {
ChangePassword change = new ChangePassword();
if (encryptPassword != null) {
for (int i = 0; i < encryptPassword.length; i++) {
if (encryptPassword[i] == ' ') {
throw new SQLException("The file password may not contain spaces");
}
}
}
change.out = out;
change.dir = dir;
change.cipher = cipher;
change.decrypt = getFileEncryptionKey(decryptPassword);
......@@ -147,7 +162,7 @@ public class ChangePassword {
change.process(fileName);
}
if (files.size() == 0 && !quiet) {
System.out.println("No database files found");
out.println("No database files found");
}
}
......@@ -168,32 +183,32 @@ public class ChangePassword {
String temp = dir + "/temp.db";
FileUtils.delete(temp);
byte[] magic = Database.getMagic(textStorage);
FileStore out;
FileStore fileOut;
if (key == null) {
out = FileStore.open(null, temp, "rw", magic);
fileOut = FileStore.open(null, temp, "rw", magic);
} else {
out = FileStore.open(null, temp, "rw", magic, cipher, key);
fileOut = FileStore.open(null, temp, "rw", magic, cipher, key);
}
out.init();
fileOut.init();
byte[] buffer = new byte[4 * 1024];
long remaining = in.length() - FileStore.HEADER_LENGTH;
long total = remaining;
in.seek(FileStore.HEADER_LENGTH);
out.seek(FileStore.HEADER_LENGTH);
fileOut.seek(FileStore.HEADER_LENGTH);
long time = System.currentTimeMillis();
while (remaining > 0) {
if (System.currentTimeMillis() - time > 1000) {
System.out.println(fileName + ": " + (100 - 100 * remaining / total) + "%");
out.println(fileName + ": " + (100 - 100 * remaining / total) + "%");
time = System.currentTimeMillis();
}
int len = (int) Math.min(buffer.length, remaining);
in.readFully(buffer, 0, len);
out.write(buffer, 0, len);
fileOut.write(buffer, 0, len);
remaining -= len;
}
try {
in.close();
out.close();
fileOut.close();
} catch (IOException e) {
throw Message.convertIOException(e, null);
}
......
......@@ -12,17 +12,22 @@ import java.sql.SQLException;
import org.h2.message.Message;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
/**
* Convert a trace file to a java class.
* This is required because the find command truncates lines.
*/
public class ConvertTraceFile {
public class ConvertTraceFile extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " [-traceFile <trace file name>]\n [-javaClass <java class name>] [-script <sql script file>]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/ConvertTraceFile.html");
out.println("Converts a .trace.db file to a SQL script and Java source code.");
out.println("java "+getClass().getName() + "\n" +
" [-traceFile <file>] The trace file name (default: test.trace.db)\n" +
" [-script <file>] The script file name (default: test.sql)\n" +
" [-javaClass <file>] The Java directory and class file name (default: Test)");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -43,7 +48,7 @@ public class ConvertTraceFile {
new ConvertTraceFile().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String traceFile = "test.trace.db";
String javaClass = "Test";
String script = "test.sql";
......@@ -59,7 +64,7 @@ public class ConvertTraceFile {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
......@@ -86,7 +91,12 @@ public class ConvertTraceFile {
javaWriter.println("import java.sql.*;");
javaWriter.println("import java.math.*;");
javaWriter.println("import java.util.Calendar;");
javaWriter.println("public class " + javaClassName + " {");
String cn = javaClassName.replace('\\', '/');
int idx = cn.lastIndexOf('/');
if (idx > 0) {
cn = cn.substring(idx + 1);
}
javaWriter.println("public class " + cn + " {");
javaWriter.println(" public static void main(String[] args) throws Exception {");
javaWriter.println(" Class.forName(\"org.h2.Driver\");");
while (true) {
......@@ -99,7 +109,7 @@ public class ConvertTraceFile {
javaWriter.println(line);
} else if (line.startsWith("/*SQL*/")) {
line = line.substring("/*SQL*/".length());
scriptWriter.println(line);
scriptWriter.println(StringUtils.javaDecode(line));
}
}
javaWriter.println(" }");
......
......@@ -12,17 +12,23 @@ import java.sql.Statement;
import org.h2.util.FileUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.Tool;
/**
* Tool to create a database cluster. This will copy a database to another
* location if required, and modify the cluster setting.
*/
public class CreateCluster {
public class CreateCluster extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " -urlSource <url> -urlTarget <url> -user <user> [-password <pwd>] -serverlist <serverlist>");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/CreateCluster.html");
out.println("Creates a cluster from a standalone database.");
out.println("java "+getClass().getName() + "\n" +
" -urlSource <url> The database URL of the source database (jdbc:h2:...)\n" +
" -urlTarget <url> The database URL of the target database (jdbc:h2:...)\n" +
" -user <user> The user name\n" +
" [-password <pwd>] The password\n" +
" -serverlist <list> The comma separated list of host names or IP addresses");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -34,8 +40,10 @@ public class CreateCluster {
* <li>-urlSource jdbc:h2:... (the database URL of the source database)
* </li>
* <li>-urlTarget jdbc:h2:... (the database URL of the target database)
* </li>
* </ul>
* </li><li>-user (the user name)
* </li><li>-password (the password)
* </li><li>-serverlist (the server list)
* </li></ul>
*
* @param args the command line arguments
* @throws SQLException
......@@ -44,7 +52,7 @@ public class CreateCluster {
new CreateCluster().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String urlSource = null;
String urlTarget = null;
String user = null;
......@@ -66,7 +74,7 @@ public class CreateCluster {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
......@@ -75,8 +83,7 @@ public class CreateCluster {
showUsage();
return;
}
execute(urlSource, urlTarget, user, password, serverlist);
process(urlSource, urlTarget, user, password, serverlist);
}
/**
......@@ -89,7 +96,11 @@ public class CreateCluster {
* @param serverlist the server list
* @throws SQLException
*/
public static void execute(String urlSource, String urlTarget, String user, String password, String serverlist) throws SQLException {
public void execute(String urlSource, String urlTarget, String user, String password, String serverlist) throws SQLException {
new CreateCluster().process(urlSource, urlTarget, user, password, serverlist);
}
private void process(String urlSource, String urlTarget, String user, String password, String serverlist) throws SQLException {
Connection conn = null;
Statement stat = null;
try {
......@@ -116,8 +127,12 @@ public class CreateCluster {
// But there is currently no exclusive mode.
String scriptFile = "backup.sql";
Script.execute(urlSource, user, password, scriptFile);
RunScript.execute(urlTarget, user, password, scriptFile, null, false);
Script sc = new Script();
sc.setPrintStream(out);
sc.process(urlSource, user, password, scriptFile);
RunScript runscript = new RunScript();
runscript.setPrintStream(out);
runscript.process(urlTarget, user, password, scriptFile, null, false);
FileUtils.delete(scriptFile);
// set the cluster to the serverlist on both databases
......
......@@ -11,16 +11,21 @@ import java.util.ArrayList;
import org.h2.engine.Constants;
import org.h2.store.FileLister;
import org.h2.util.FileUtils;
import org.h2.util.Tool;
/**
* Delete the database files. The database must be closed before calling this
* tool.
*/
public class DeleteDbFiles {
public class DeleteDbFiles extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()+" [-dir <dir>] [-db <database>] [-quiet]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/DeleteDbFiles.html");
out.println("Deletes all files belonging to a database.");
out.println("java "+getClass().getName() + "\n" +
" [-dir <dir>] The directory (default: .)\n" +
" [-db <database>] The database name\n" +
" [-quiet] Do not print progress information");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -41,7 +46,7 @@ public class DeleteDbFiles {
new DeleteDbFiles().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String dir = ".";
String db = null;
boolean quiet = false;
......@@ -57,14 +62,14 @@ public class DeleteDbFiles {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
}
execute(dir, db, quiet);
process(dir, db, quiet);
}
/**
* Deletes the database files.
*
......@@ -74,17 +79,29 @@ public class DeleteDbFiles {
* @throws SQLException
*/
public static void execute(String dir, String db, boolean quiet) throws SQLException {
new DeleteDbFiles().process(dir, db, quiet);
}
/**
* Deletes the database files.
*
* @param dir the directory
* @param db the database name (null for all databases)
* @param quiet don't print progress information
* @throws SQLException
*/
private void process(String dir, String db, boolean quiet) throws SQLException {
DeleteDbFiles delete = new DeleteDbFiles();
ArrayList files = FileLister.getDatabaseFiles(dir, db, true);
for (int i = 0; i < files.size(); i++) {
String fileName = (String) files.get(i);
delete.process(fileName, quiet);
if (!quiet) {
System.out.println("processed: " + fileName);
out.println("Processed: " + fileName);
}
}
if (files.size() == 0 && !quiet) {
System.out.println("No database files found");
out.println("No database files found");
}
}
......
......@@ -47,6 +47,7 @@ import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.util.RandomUtils;
import org.h2.util.SmallLRUCache;
import org.h2.util.Tool;
import org.h2.value.Value;
import org.h2.value.ValueLob;
......@@ -58,7 +59,7 @@ import org.h2.value.ValueLob;
* system software, or if an application writes into the database file that
* doesn't understand the the file format, or if there is a hardware problem.
*/
public class Recover implements DataHandler {
public class Recover extends Tool implements DataHandler {
private String databaseName;
private boolean textStorage;
......@@ -67,12 +68,16 @@ public class Recover implements DataHandler {
private int storageId;
private int recordLength;
private int valueId;
private boolean log;
private boolean trace;
private boolean lobFilesInDirectories;
private void showUsage() {
System.out.println("java "+getClass().getName()+" [-dir <dir>] [-db <database>] [-log true]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/Recover.html");
out.println("Helps recovering a corrupted database.");
out.println("java "+getClass().getName() + "\n" +
" [-dir <dir>] The directory (default: .)\n" +
" [-db <database>] The database name\n" +
" [-trace] Print additional trace information");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -83,7 +88,7 @@ public class Recover implements DataHandler {
* <li>-help or -? (print the list of options)
* </li><li>-dir database directory (the default is the current directory)
* </li><li>-db database name (all databases if no name is specified)
* </li><li>-log {true|false} (log additional messages)
* </li><li>-trace (print additional trace information while processing)
* </li></ul>
*
* @param args the command line arguments
......@@ -93,7 +98,7 @@ public class Recover implements DataHandler {
new Recover().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String dir = ".";
String db = null;
boolean removePassword = false;
......@@ -105,14 +110,13 @@ public class Recover implements DataHandler {
db = args[++i];
} else if ("-removePassword".equals(arg)) {
removePassword = true;
log = true;
} else if ("-log".equals(arg)) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-trace".equals(arg)) {
trace = true;
} else if (arg.equals("-help") || arg.equals("-?")) {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
......@@ -148,15 +152,15 @@ public class Recover implements DataHandler {
}
}
private void log(String message) {
if (log) {
System.out.println(message);
private void trace(String message) {
if (trace) {
out.println(message);
}
}
private void logError(String message, Throwable t) {
System.out.println(message + ": " + t.toString());
if (log) {
private void traceError(String message, Throwable t) {
out.println(message + ": " + t.toString());
if (trace) {
t.printStackTrace();
}
}
......@@ -263,8 +267,8 @@ public class Recover implements DataHandler {
s.updateChecksum();
store.seek(start);
store.write(s.getBytes(), 0, s.length());
if (log) {
System.out.println("User: " + userName);
if (trace) {
out.println("User: " + userName);
}
break;
} catch (Throwable e) {
......@@ -306,7 +310,7 @@ public class Recover implements DataHandler {
private PrintWriter getWriter(String fileName, String suffix) throws IOException, SQLException {
fileName = fileName.substring(0, fileName.length() - 3);
String outputFile = fileName + suffix;
log("Created file: " + outputFile);
trace("Created file: " + outputFile);
return new PrintWriter(new BufferedWriter(FileUtils.openFileWriter(outputFile, false)));
}
......@@ -336,13 +340,13 @@ public class Recover implements DataHandler {
}
private void dumpLob(String fileName, boolean lobCompression) {
OutputStream out = null;
OutputStream fileOut = null;
FileStore store = null;
int size = 0;
String n = fileName + (lobCompression ? ".comp" : "") + ".txt";
InputStream in = null;
try {
out = FileUtils.openFileOutputStream(n, false);
fileOut = FileUtils.openFileOutputStream(n, false);
textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, "r", magic);
......@@ -354,18 +358,18 @@ public class Recover implements DataHandler {
if (l < 0) {
break;
}
out.write(buffer, 0, l);
fileOut.write(buffer, 0, l);
size += l;
}
out.close();
fileOut.close();
} catch (Throwable e) {
// this is usually not a problem, because we try both compressed and
// uncompressed
if (log) {
logError(fileName, e);
if (trace) {
traceError(fileName, e);
}
} finally {
IOUtils.closeSilently(out);
IOUtils.closeSilently(fileOut);
IOUtils.closeSilently(in);
closeSilently(store);
}
......@@ -373,7 +377,7 @@ public class Recover implements DataHandler {
try {
FileUtils.delete(n);
} catch (SQLException e) {
logError(n, e);
traceError(n, e);
}
}
}
......@@ -403,8 +407,8 @@ public class Recover implements DataHandler {
}
sb.append(getSQL(v));
} catch (Exception e) {
if (log) {
logError("log data", e);
if (trace) {
traceError("log data", e);
}
writeDataError(writer, "exception " + e, s.getBytes(), blockCount);
continue;
......@@ -875,7 +879,7 @@ public class Recover implements DataHandler {
if (writer != null) {
writer.println("// error: " + e);
}
logError("Error", e);
traceError("Error", e);
}
/**
......
......@@ -17,16 +17,21 @@ import org.h2.message.Message;
import org.h2.store.FileLister;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.Tool;
/**
* Restores a H2 database by extracting the database files from a .zip file.
*/
public class Restore {
public class Restore extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " [-file <filename>] [-dir <dir>] [-db <database>] [-quiet]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/Restore.html");
out.println("Restores a database backup.");
out.println("java "+getClass().getName() + "\n" +
" [-file <filename>] The source file name (default: backup.zip)\n" +
" [-dir <dir>] Target directory (default: .)\n" +
" [-db <database>] Target database name\n" +
" [-quiet] Do not print progress information");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -48,7 +53,7 @@ public class Restore {
new Restore().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String zipFileName = "backup.zip";
String dir = ".";
String db = null;
......@@ -67,12 +72,12 @@ public class Restore {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
}
Restore.execute(zipFileName, dir, db, quiet);
process(zipFileName, dir, db, quiet);
}
private static String getOriginalDbName(String fileName, String db) throws IOException {
......@@ -125,6 +130,19 @@ public class Restore {
* @throws SQLException
*/
public static void execute(String zipFileName, String directory, String db, boolean quiet) throws SQLException {
new Restore().process(zipFileName, directory, db, quiet);
}
/**
* Restores database files.
*
* @param zipFileName the name of the backup file
* @param directory the directory name
* @param db the database name (null for all databases)
* @param quiet don't print progress information
* @throws SQLException
*/
private void process(String zipFileName, String directory, String db, boolean quiet) throws SQLException {
InputStream in = null;
try {
if (!FileUtils.exists(zipFileName)) {
......
......@@ -26,15 +26,24 @@ import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.ScriptReader;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
/**
* Executes the contents of a SQL script file against a database.
*/
public class RunScript {
public class RunScript extends Tool {
private void showUsage() {
System.out.println("java " + getClass().getName() + " -url <url> -user <user> [-password <pwd>] [-script <file>] [-driver <driver] [-options <option> ...]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/RunScript.html");
out.println("Runs a SQL script.");
out.println("java "+getClass().getName() + "\n" +
" -url <url> The database URL\n" +
" -user <user> The user name\n" +
" [-password <pwd>] The password\n" +
" [-script <file>] The script file to run (default: backup.sql)\n" +
" [-driver <class>] The JDBC driver class to use (not required in most cases)\n" +
" [-quiet] Do not print progress information\n" +
" [-options ...] The list of options (only for H2 embedded mode)");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -69,7 +78,7 @@ public class RunScript {
new RunScript().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String url = null;
String user = null;
String password = "";
......@@ -110,7 +119,7 @@ public class RunScript {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
......@@ -121,13 +130,13 @@ public class RunScript {
}
long time = System.currentTimeMillis();
if (options != null) {
executeRunscript(url, user, password, script, options);
processRunscript(url, user, password, script, options);
} else {
execute(url, user, password, script, null, continueOnError);
process(url, user, password, script, null, continueOnError);
}
if (showTime) {
time = System.currentTimeMillis() - time;
System.out.println("Done in " + time + " ms");
out.println("Done in " + time + " ms");
}
}
......@@ -139,6 +148,10 @@ public class RunScript {
* @return the last result set
*/
public static ResultSet execute(Connection conn, Reader reader) throws SQLException {
return new RunScript().process(conn, reader);
}
private ResultSet process(Connection conn, Reader reader) throws SQLException {
reader = new BufferedReader(reader);
Statement stat = conn.createStatement();
ResultSet rs = null;
......@@ -160,19 +173,19 @@ public class RunScript {
return rs;
}
private static void execute(Connection conn, String fileName, boolean continueOnError, String charsetName) throws SQLException, IOException {
private void process(Connection conn, String fileName, boolean continueOnError, String charsetName) throws SQLException, IOException {
InputStream in = FileUtils.openFileInputStream(fileName);
String path = FileUtils.getParent(fileName);
try {
in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE);
Reader reader = new InputStreamReader(in, charsetName);
execute(conn, continueOnError, path, reader, charsetName);
process(conn, continueOnError, path, reader, charsetName);
} finally {
IOUtils.closeSilently(in);
}
}
private static void execute(Connection conn, boolean continueOnError, String path, Reader reader, String charsetName) throws SQLException, IOException {
private void process(Connection conn, boolean continueOnError, String path, Reader reader, String charsetName) throws SQLException, IOException {
Statement stat = conn.createStatement();
ScriptReader r = new ScriptReader(new BufferedReader(reader));
while (true) {
......@@ -186,7 +199,7 @@ public class RunScript {
if (!FileUtils.isAbsolute(sql)) {
sql = path + File.separator + sql;
}
execute(conn, sql, continueOnError, charsetName);
process(conn, sql, continueOnError, charsetName);
} else {
try {
if (sql.trim().length() > 0) {
......@@ -203,7 +216,7 @@ public class RunScript {
}
}
private static void executeRunscript(String url, String user, String password, String fileName, String options) throws SQLException {
private static void processRunscript(String url, String user, String password, String fileName, String options) throws SQLException {
Connection conn = null;
Statement stat = null;
try {
......@@ -230,6 +243,10 @@ public class RunScript {
* @throws SQLException
*/
public static void execute(String url, String user, String password, String fileName, String charsetName, boolean continueOnError) throws SQLException {
new RunScript().process(url, user, password, fileName, charsetName, continueOnError);
}
void process(String url, String user, String password, String fileName, String charsetName, boolean continueOnError) throws SQLException {
try {
org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url, user, password);
......@@ -237,7 +254,7 @@ public class RunScript {
charsetName = Constants.UTF8;
}
try {
execute(conn, fileName, continueOnError, charsetName);
process(conn, fileName, continueOnError, charsetName);
} finally {
conn.close();
}
......
......@@ -17,16 +17,23 @@ import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
/**
* Creates a SQL script file by extracting the schema and data of a database.
*/
public class Script {
public class Script extends Tool {
private void showUsage() {
System.out.println("java "+getClass().getName()
+ " -url <url> -user <user> [-password <pwd>] [-script <filename>] [-options <option> ...]");
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/Script.html");
out.println("Allows converting a database to a SQL script.");
out.println("java "+getClass().getName() + "\n" +
" -url <url> The database URL\n" +
" -user <user> The user name\n" +
" [-password <pwd>] The password\n" +
" [-script <file>] The script file to run (default: backup.sql)\n" +
" [-quiet] Do not print progress information\n" +
" [-options ...] The list of options (only for H2 embedded mode)");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
/**
......@@ -49,7 +56,7 @@ public class Script {
new Script().run(args);
}
private void run(String[] args) throws SQLException {
public void run(String[] args) throws SQLException {
String url = null;
String user = null;
String password = "";
......@@ -86,7 +93,7 @@ public class Script {
showUsage();
return;
} else {
System.out.println("Unsupported option: " + arg);
out.println("Unsupported option: " + arg);
showUsage();
return;
}
......@@ -96,16 +103,13 @@ public class Script {
return;
}
if (options1 != null) {
executeScript(url, user, password, file, options1, options2);
processScript(url, user, password, file, options1, options2);
} else {
execute(url, user, password, file);
process(url, user, password, file);
}
}
/**
* INTERNAL
*/
public static void executeScript(String url, String user, String password, String fileName, String options1, String options2) throws SQLException {
private void processScript(String url, String user, String password, String fileName, String options1, String options2) throws SQLException {
Connection conn = null;
Statement stat = null;
try {
......@@ -130,6 +134,10 @@ public class Script {
* @throws SQLException
*/
public static void execute(String url, String user, String password, String fileName) throws SQLException {
new Script().process(url, user, password, fileName);
}
void process(String url, String user, String password, String fileName) throws SQLException {
Connection conn = null;
Statement stat = null;
Writer fileWriter = null;
......
......@@ -59,8 +59,13 @@ public class Shell {
}
private void showUsage() {
out.println("java " + getClass().getName() + " [-url <url> -user <user> -password <pwd> -driver <driver]");
out.println("See also http://h2database.com/javadoc/org/h2/tools/Prompt.html");
out.println("An interactive command line database tool.");
out.println("java "+getClass().getName() + "\n" +
" [-url <url>] The database URL\n" +
" [-user <user>] The user name\n" +
" [-password <pwd>] The password\n" +
" [-driver <class>] The JDBC driver class to use (not required in most cases)");
out.println("See also http://h2database.com/javadoc/" + getClass().getName().replace('.', '/') + ".html");
}
private void run(String[] args) throws SQLException {
......@@ -97,12 +102,12 @@ public class Shell {
private void showHelp() {
out.println("Commands are case insensitive; SQL statements end with ';'");
out.println("help or ? - Display this help");
out.println("list - Toggle result list mode");
out.println("maxwidth - Set maximum column width (default is 100)");
out.println("show - List all tables");
out.println("describe - Describe a table");
out.println("quit or exit - Close the connection and exit");
out.println("help or ? Display this help");
out.println("list Toggle result list mode");
out.println("maxwidth Set maximum column width (default is 100)");
out.println("show List all tables");
out.println("describe Describe a table");
out.println("quit or exit Close the connection and exit");
out.println();
}
......
......@@ -154,17 +154,17 @@ public class DateTimeUtils {
s = s.substring(0, s.length() - 1);
tz = TimeZone.getTimeZone("UTC");
} else {
int timezoneStart = s.indexOf('+', s2 + 1);
if (timezoneStart < 0) {
timezoneStart = s.indexOf('-', s2 + 1);
int timeZoneStart = s.indexOf('+', s2 + 1);
if (timeZoneStart < 0) {
timeZoneStart = s.indexOf('-', s2 + 1);
}
if (timezoneStart >= 0) {
String tzName = "GMT" + s.substring(timezoneStart);
if (timeZoneStart >= 0) {
String tzName = "GMT" + s.substring(timeZoneStart);
tz = TimeZone.getTimeZone(tzName);
if (!tz.getID().equals(tzName)) {
throw Message.getSQLException(errorCode, new String[] { s, tz.getID() + " <>" + tzName });
}
s = s.substring(0, timezoneStart).trim();
s = s.substring(0, timeZoneStart).trim();
}
}
......
......@@ -378,8 +378,8 @@ public class StringUtils {
/**
* Formats a date using a format string
*/
public static String formatDateTime(Date date, String format, String locale, String timezone) throws SQLException {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timezone);
public static String formatDateTime(Date date, String format, String locale, String timeZone) throws SQLException {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
synchronized (dateFormat) {
return dateFormat.format(date);
}
......@@ -388,8 +388,8 @@ public class StringUtils {
/**
* Parses a date using a format string
*/
public static Date parseDateTime(String date, String format, String locale, String timezone) throws SQLException {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timezone);
public static Date parseDateTime(String date, String format, String locale, String timeZone) throws SQLException {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
try {
synchronized (dateFormat) {
return dateFormat.parse(date);
......@@ -399,7 +399,7 @@ public class StringUtils {
}
}
private static SimpleDateFormat getDateFormat(String format, String locale, String timezone) throws SQLException {
private static SimpleDateFormat getDateFormat(String format, String locale, String timeZone) throws SQLException {
try {
// currently, a new instance is create for each call
// however, could cache the last few instances
......@@ -417,12 +417,12 @@ public class StringUtils {
//#endif
df = new SimpleDateFormat(format, l);
}
if (timezone != null) {
df.setTimeZone(TimeZone.getTimeZone(timezone));
if (timeZone != null) {
df.setTimeZone(TimeZone.getTimeZone(timeZone));
}
return df;
} catch (Exception e) {
throw Message.getSQLException(ErrorCode.PARSE_ERROR_1, new String []{format + "/" + locale + "/" + timezone}, e);
throw Message.getSQLException(ErrorCode.PARSE_ERROR_1, new String []{format + "/" + locale + "/" + timeZone}, e);
}
}
......
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.io.PrintStream;
import java.sql.SQLException;
/**
* Command line tools implement the tool interface so that they can be used in
* the H2 Console.
*/
public abstract class Tool {
protected PrintStream out = System.out;
/**
* Sets the print stream.
*
* @param out the new print stream
*/
public void setPrintStream(PrintStream out) {
this.out = out;
}
/**
* Run the tool with the given output stream and arguments.
*
* @param out the print stream, for example System.out
* @param args the argument list
*/
public abstract void run(String[] args) throws SQLException;
}
......@@ -26,7 +26,7 @@ public class ValueTimestamp extends Value {
private final Timestamp value;
/**
* This is used to find out if a date is possibly BC. Because of timezone
* This is used to find out if a date is possibly BC. Because of time zone
* issues (the date is time zone specific), the second day is used. That
* means the value is not exact, but it does not need to be.
*/
......
......@@ -20,7 +20,7 @@ public class MixedMode {
public static void main(String[] args) throws Exception {
// start the server, allows to access the database remotly
// start the server, allows to access the database remotely
Server server = Server.createTcpServer(new String[] { "-tcpPort", "9081" });
server.start();
System.out.println("You can access the database remotely now, using the URL:");
......
......@@ -215,7 +215,7 @@ INSERT INTO ITEM VALUES(33,
</li></ul>
<b>Bugfixes:</b>
<ul><li>Certain setting in the Server didn''t work.
</li><li>In timezones where the summer time saving limit is at midnight,
</li><li>In time zones where the summer time saving limit is at midnight,
some dates did not work in some virtual machines,
for example 2007-10-14 in Chile, using the Sun JVM 1.6.0_03-b05.
</li><li>The native fulltext search was not working properly after re-connecting.
......
......@@ -8,7 +8,6 @@ package org.h2.test;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.server.TcpServer;
import org.h2.store.fs.FileSystemDisk;
import org.h2.test.db.TestAutoRecompile;
import org.h2.test.db.TestBackup;
......@@ -160,6 +159,31 @@ java org.h2.test.TestAll timer
/*
database.tgz
output.zip
function table called twice: document:
Yes. The first call is to get the list of columns, and the second call is to get the data.
maven: upload source code and javadocs as well
Browser problems:
The H2 Console doesn't work.
Try with another browser.
There has been a reported incompatibility with the
RealPlayer Browser Record Plugin 1.0 when using Firefox 2.0 and Vista
web server: support trace
remove 'log true' everywhere
tools
cd ....
add a shell script
add %DRIVERS% if required
how to quote quotes in command line (windows, linux)
simplify command line options (no 'true' settings)
better command line help
should write (log) to system table before adding to internal data structures
//new TestCrashAPI().init(test).testCase(2046453618);
......@@ -200,6 +224,11 @@ Can sometimes not delete log file? need test case
Add where required // TODO: change in version 1.1
History:
The command line options in the tools have changed:
instead of '-log true' now '-trace' is used.
Also, '-ifExists', '-tcpSSL' and '-tcpAllowOthers' and so on have changed:
now the 'true' is no longer needed.
The old behavior is still supported.
Roadmap:
......@@ -536,7 +565,6 @@ Roadmap:
DeleteDbFiles.execute(TestBase.baseDir, null, true);
FileSystemDisk.getInstance().deleteRecursive("trace.db");
if (networked) {
TcpServer.logInternalErrors = true;
String[] args = ssl ? new String[] { "-tcpSSL", "true", "-tcpPort", "9192" } : new String[] { "-tcpPort",
"9192" };
server = Server.createTcpServer(args);
......
......@@ -226,8 +226,8 @@ class Database {
}
}
public void update(PreparedStatement prep, String log) throws Exception {
test.log(log);
public void update(PreparedStatement prep, String trace) throws Exception {
test.trace(trace);
prep.executeUpdate();
executedStatements++;
}
......
......@@ -27,7 +27,7 @@ import org.h2.util.JdbcUtils;
public class TestPerformance {
boolean collect;
boolean log;
boolean trace;
public static void main(String[] args) throws Exception {
new TestPerformance().test(args);
......@@ -66,8 +66,8 @@ public class TestPerformance {
init = true;
} else if (args[i].equals("-out")) {
out = args[++i];
} else if (args[i].equals("-log")) {
log = Boolean.valueOf(args[++i]).booleanValue();
} else if (args[i].equals("-trace")) {
trace = true;
}
}
openResults(init);
......@@ -232,8 +232,8 @@ public class TestPerformance {
bench.runTest();
}
public void log(String s) {
if (log) {
public void trace(String s) {
if (trace) {
System.out.println(s);
}
}
......
......@@ -635,10 +635,10 @@ public class TestResultSet extends TestBase {
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?, ?, ?)");
Calendar regular = Calendar.getInstance();
Calendar other = null;
String[] timezones = TimeZone.getAvailableIDs();
String[] timeZones = TimeZone.getAvailableIDs();
// search a locale that has a _different_ raw offset
for (int i = 0; i < timezones.length; i++) {
TimeZone zone = TimeZone.getTimeZone(timezones[i]);
for (int i = 0; i < timeZones.length; i++) {
TimeZone zone = TimeZone.getTimeZone(timeZones[i]);
if (regular.getTimeZone().getRawOffset() != zone.getRawOffset()) {
other = Calendar.getInstance(zone);
break;
......
......@@ -24,7 +24,7 @@ public class TestPgServer extends TestBase {
public void test() throws Exception {
deleteDb("test");
Server server = Server.createPgServer(new String[]{"-baseDir", baseDir, "-ifExists", "false", "-pgAllowOthers", "false", "-pgPort", "5535"});
Server server = Server.createPgServer(new String[]{"-baseDir", baseDir, "-pgPort", "5535"});
server.start();
try {
Class.forName("org.postgresql.Driver");
......
......@@ -46,7 +46,7 @@ public class Player {
// TODO support Map
// TODO support SQLXML
private boolean log;
private boolean trace;
private static final String[] IMPORTED_PACKAGES = { "", "java.lang.", "java.sql.", "javax.sql." };
private HashMap objects = new HashMap();
......@@ -82,8 +82,8 @@ public class Player {
try {
fileName = args[args.length - 1];
for (int i = 0; i < args.length - 1; i++) {
if ("-log".equals(args[i])) {
log = true;
if ("-trace".equals(args[i])) {
trace = true;
} else {
throw new Error("Unknown setting: " + args[i]);
}
......@@ -91,14 +91,14 @@ public class Player {
} catch (Exception e) {
e.printStackTrace();
System.out.println("Usage: java " + getClass().getName()
+ " [-log] <fileName>");
+ " [-trace] <fileName>");
return;
}
runFile(fileName, log);
runFile(fileName, trace);
}
private void runFile(String fileName, boolean log) throws IOException {
this.log = log;
private void runFile(String fileName, boolean trace) throws IOException {
this.trace = trace;
LineNumberReader reader = new LineNumberReader(new BufferedReader(
new FileReader(fileName)));
while (true) {
......@@ -110,8 +110,8 @@ public class Player {
}
}
void log(String s) {
if (log) {
void trace(String s) {
if (trace) {
System.out.println(s);
}
}
......@@ -122,12 +122,12 @@ public class Player {
}
line = line.substring("/**/".length()) + ";";
Statement s = Parser.parseStatement(this, line);
log("> " + s.toString());
trace("> " + s.toString());
try {
s.execute();
} catch (Exception e) {
e.printStackTrace();
log("error: " + e.toString());
trace("error: " + e.toString());
}
}
......
......@@ -47,7 +47,7 @@ class Statement {
Object execute() throws Exception {
if (object == player) {
// there was an exception previously
player.log("> " + assignVariable + " not set");
player.trace("> " + assignVariable + " not set");
if (assignment) {
player.assign(assignVariable, player);
}
......@@ -81,7 +81,7 @@ class Statement {
e.printStackTrace();
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
player.log("> " + t.toString());
player.trace("> " + t.toString());
if (assignment) {
player.assign(assignVariable, player);
}
......
......@@ -33,15 +33,11 @@ public class TestSampleApps extends TestBase {
// tools
testApp(org.h2.tools.ChangePassword.class, new String[] { "-help" },
"java org.h2.tools.ChangePassword [-dir <dir>] "
+ "[-db <database>] [-cipher <cipher>] [-decrypt <pwd>] [-encrypt <pwd>] [-quiet]\n"
+ "See also http://h2database.com/javadoc/org/h2/tools/ChangePassword.html");
testApp(org.h2.tools.ChangePassword.class, null, "java org.h2.tools.ChangePassword [-dir <dir>] "
+ "[-db <database>] [-cipher <cipher>] [-decrypt <pwd>] [-encrypt <pwd>] [-quiet]\n"
+ "See also http://h2database.com/javadoc/org/h2/tools/ChangePassword.html");
"Allows changing the database file password*");
testApp(org.h2.tools.ChangePassword.class, null,
"Allows changing the database file password*");
testApp(org.h2.tools.DeleteDbFiles.class, new String[] { "-help" },
"java org.h2.tools.DeleteDbFiles [-dir <dir>] [-db <database>] [-quiet]\n"
+ "See also http://h2database.com/javadoc/org/h2/tools/DeleteDbFiles.html");
"Deletes all files belonging to a database.*");
}
private void testApp(Class clazz, String[] args, String expected) throws Exception {
......@@ -62,6 +58,15 @@ public class TestSampleApps extends TestBase {
System.setErr(oldErr);
String s = new String(buff.toByteArray(), "UTF-8");
s = StringUtils.replaceAll(s, "\r\n", "\n");
check(s.trim(), expected.trim());
s = s.trim();
expected = expected.trim();
if (expected.endsWith("*")) {
expected = expected.substring(0, expected.length() - 1);
if (!s.startsWith(expected)) {
check(s.trim(), expected.trim());
}
} else {
check(s.trim(), expected.trim());
}
}
}
......@@ -67,31 +67,31 @@ public class TestTools extends TestBase {
org.h2.Driver.load();
result = runServer(new String[]{"-?"}, 1);
check(result.indexOf("[options]") >= 0);
check(result.indexOf("Starts H2 Servers") >= 0);
check(result.indexOf("Unknown option") < 0);
result = runServer(new String[]{"-xy"}, 1);
check(result.indexOf("[options]") >= 0);
check(result.indexOf("Starts H2 Servers") >= 0);
check(result.indexOf("Unsupported option") >= 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "false", "-tcpPort", "9001", "-tcpPassword", "abc"}, 0);
result = runServer(new String[]{"-tcp", "-tcpPort", "9001", "-tcpPassword", "abc"}, 0);
check(result.indexOf("tcp://") >= 0);
check(result.indexOf(":9001") >= 0);
check(result.indexOf("only local") >= 0);
check(result.indexOf("[options]") < 0);
check(result.indexOf("Starts H2 Servers") < 0);
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:9001/mem:", "sa", "sa");
conn.close();
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9001", "-tcpPassword", "abc", "-tcpShutdownForce", "true"}, 0);
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9001", "-tcpPassword", "abc", "-tcpShutdownForce"}, 0);
check(result.indexOf("Shutting down") >= 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "true", "-tcpPort", "9001", "-tcpPassword", "abcdef", "-tcpSSL", "true"}, 0);
result = runServer(new String[]{"-tcp", "-tcpAllowOthers", "-tcpPort", "9001", "-tcpPassword", "abcdef", "-tcpSSL"}, 0);
check(result.indexOf("ssl://") >= 0);
check(result.indexOf(":9001") >= 0);
check(result.indexOf("others can") >= 0);
check(result.indexOf("[options]") < 0);
check(result.indexOf("Starts H2 Servers") < 0);
conn = DriverManager.getConnection("jdbc:h2:ssl://localhost:9001/mem:", "sa", "sa");
conn.close();
result = runServer(new String[]{"-tcpShutdown", "ssl://localhost:9001", "-tcpPassword", "abcdef", "-tcpShutdownForce", "false"}, 0);
result = runServer(new String[]{"-tcpShutdown", "ssl://localhost:9001", "-tcpPassword", "abcdef"}, 0);
check(result.indexOf("Shutting down") >= 0);
try {
conn = DriverManager.getConnection("jdbc:h2:ssl://localhost:9001/mem:", "sa", "sa");
......@@ -101,10 +101,10 @@ public class TestTools extends TestBase {
}
result = runServer(new String[]{
"-web", "-webPort", "9002", "-webAllowOthers", "true", "-webSSL", "true",
"-pg", "-pgAllowOthers", "true", "-pgPort", "9003",
"-ftp", "-ftpPort", "9004", "-ftpDir", ".", "-ftpRead", "guest", "-ftpWrite", "sa", "-ftpWritePassword", "sa", "-ftpTask", "true",
"-tcp", "-tcpAllowOthers", "true", "-tcpPort", "9005", "-tcpPassword", "abc"}, 0);
"-web", "-webPort", "9002", "-webAllowOthers", "-webSSL",
"-pg", "-pgAllowOthers", "-pgPort", "9003",
"-ftp", "-ftpPort", "9004", "-ftpDir", ".", "-ftpRead", "guest", "-ftpWrite", "sa", "-ftpWritePassword", "sa", "-ftpTask",
"-tcp", "-tcpAllowOthers", "-tcpPort", "9005", "-tcpPassword", "abc"}, 0);
Server stop = server;
check(result.indexOf("https://") >= 0);
check(result.indexOf(":9002") >= 0);
......@@ -117,7 +117,7 @@ public class TestTools extends TestBase {
check(result.indexOf("tcp://") >= 0);
check(result.indexOf(":9005") >= 0);
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9005", "-tcpPassword", "abc", "-tcpShutdownForce", "true"}, 0);
result = runServer(new String[]{"-tcpShutdown", "tcp://localhost:9005", "-tcpPassword", "abc", "-tcpShutdownForce"}, 0);
check(result.indexOf("Shutting down") >= 0);
stop.shutdown();
try {
......@@ -185,7 +185,7 @@ public class TestTools extends TestBase {
private void testTraceFile(String url) throws Exception {
Connection conn;
Recover.main(new String[]{"-removePassword", "-log", "false", "-dir", baseDir, "-db", "toolsConvertTraceFile"});
Recover.main(new String[]{"-removePassword", "-dir", baseDir, "-db", "toolsConvertTraceFile"});
conn = DriverManager.getConnection(url, "sa", "");
Statement stat = conn.createStatement();
ResultSet rs;
......@@ -226,7 +226,7 @@ public class TestTools extends TestBase {
FileUtils.delete(fileName);
}
}
Recover.main(new String[]{"-dir", baseDir, "-db", "toolsRemove", "-removePassword", "-log", "false"});
Recover.main(new String[]{"-dir", baseDir, "-db", "toolsRemove", "-removePassword"});
conn = DriverManager.getConnection(url, "sa", "");
stat = conn.createStatement();
ResultSet rs;
......@@ -405,12 +405,12 @@ public class TestTools extends TestBase {
private void testServer() throws Exception {
Connection conn;
deleteDb("test");
Server server = Server.createTcpServer(new String[] { "-ifExists", "false", "-baseDir", baseDir, "-tcpPort", "9192" }).start();
Server server = Server.createTcpServer(new String[] { "-baseDir", baseDir, "-tcpPort", "9192" }).start();
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:9192/test", "sa", "");
conn.close();
server.stop();
server = Server.createTcpServer(
new String[] { "-ifExists", "true", "-tcpPassword", "abc", "-baseDir", baseDir, "-tcpPort", "9192" }).start();
new String[] { "-ifExists", "-tcpPassword", "abc", "-baseDir", baseDir, "-tcpPort", "9192" }).start();
try {
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:9192/test2", "sa", "");
error("should not be able to create new db");
......
......@@ -17,8 +17,8 @@ Initial Developer: H2 Group
<servlet-name>H2Console</servlet-name>
<servlet-class>org.h2.server.web.WebServlet</servlet-class>
<init-param>
<param-name>log</param-name>
<param-value>true</param-value>
<param-name>trace</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
......
......@@ -352,7 +352,7 @@ regular regularly regulation rehash rein reindex rejected rekord rel related
relating relation relational relations relationship relative relatively release
released releases relevant reliable relies reload rely relying remain remainder
remaining remains remap remark remarks remco remember remembered remote remotely
remoting remotly remove removed removes removing rename renamed renames renaming
remoting remove removed removes removing rename renamed renames renaming
reopen repair repeat repeatable repeated repeatedly repeating repl replace
replaced replacement replaces replacing replayed replicating replication replied
reply repo report reported reporting reports repositories repository represent
......@@ -433,7 +433,7 @@ theoretically theory there thereafter therefore thereof these theta thetasym the
thin thing things think thinsp third this thomas thorn those thousand thousands
thread threaded threading threads three threshold threw throttle throttling
through throw throwable throwing thrown throws thus ticker tid tilde time timed
timeout timer times timestamp timestamps timezone timezones timing tiny tinyblob
timeout timer times timestamp timestamps timing tiny tinyblob
tinyint tinytext tired title titled tls tmendrscan tmfail tmjoin tmnoflags
tmonephase tmp tmresume tmstartrscan tmsuccess tmsuspend today todo together
token tokenize tokenized tokenizer tokens tolerant tom tomcat too took tool
......@@ -470,7 +470,7 @@ vulnerability wait waiting waits walk walker want wants warehouse warehouses war
warning warnings warranties warranty was washington watchdog watermark way
wayback ways weak web webclient weblog webserver website week weeks wegorkiewicz
weierp weight weights weightx weighty weird welcome well welt were werkzeugkasten
what when whenever where whereever wherever whether which while whirlpool white
what when whenever where wherever whether which while whirlpool white
whitespace who whole whom why wide widely width wiki wikipedia wildcard wildcards
will william win window windows wiscorp with withdraw withdrawn within without
wizard wlam wondering wood word wordid words work workaround workarounds
......@@ -488,4 +488,4 @@ greenwich sqli informix pointbase fbj pervasive jtds ifx syb mimer sybase
frontbase intersys maxwidth belonging learning mono typical toggle winexe
hider ikvmc invert recycle filtering lesser recycled assertion runner teradata
christian lgpl elapsed ncr disposed heureuse tera years retrieves unlocked
selecting
\ No newline at end of file
selecting vista everywhere locations zones fragment
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论