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

Improved documentation

上级 e584183b
......@@ -39,8 +39,8 @@ Features
Database File Locking</a><br />
<a href="#database_only_if_exists">
Opening a Database Only if it Already Exists</a><br />
<a href="#closing_the_database">
Closing the Database</a><br />
<a href="#closing_a_database">
Closing a Database</a><br />
<a href="#ignore_unknown_settings">
Ignore Unknown Settings</a><br />
<a href="#other_settings">
......@@ -627,13 +627,13 @@ class loader environment.
</p><p>
It is also possible to access a memory-only database remotely
(or from multiple processes in the same machine) using TCP/IP or SSL/TLS.
An example database URL is: <code>jdbc:h2:tcp://localhost/mem:db1</code>
(using private database remotely is also possible).
An example database URL is: <code>jdbc:h2:tcp://localhost/mem:db1</code>.
</p><p>
By default, when the last connection to a in-memory database is closed, the contents are lost.
This can be disabled by adding ;DB_CLOSE_DELAY=-1 to the database URL. That means to keep
the contents of an in-memory database as long as the virtual machine is alive, use
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
By default, closing the last connection to a database closes the database.
For an in-memory database, this means the content is lost.
To keep the database open, add ;DB_CLOSE_DELAY=-1 to the database URL.
To keep the content of an in-memory database as long as the virtual machine is alive, use
<code>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</code>.
</p>
<br /><a name="file_encryption"></a>
......@@ -653,9 +653,9 @@ To create an encrypted database, connect to it as it would already exist.
<h3>Connecting to an Encrypted Database</h3>
<p>
The encryption algorithm is set in the database URL, and the file password is specified in the password field,
before the user password. A single space needs to be added between the file password
before the user password. A single space separates the file password
and the user password; the file password itself may not contain spaces. File passwords
(as well as user passwords) are case sensitive. Here is an example to connect to a
and user passwords are case sensitive. Here is an example to connect to a
password-encrypted database:
</p>
<pre>
......@@ -669,9 +669,9 @@ conn = DriverManager.
<h3>Encrypting or Decrypting a Database</h3>
<p>
If you want to encrypt an existing database, use the ChangeFileEncryption tool.
To encrypt an existing database, use the ChangeFileEncryption tool.
This tool can also decrypt an encrypted database, or change the file encryption key.
It is available from within the H2 Console in the Tools section, or you can run it from the command line.
The tool is available from within the H2 Console in the Tools section, or you can run it from the command line.
The following command line will encrypt the database 'test' in the user home directory
with the file password 'filepwd' and the encryption algorithm AES:
</p>
......@@ -693,7 +693,7 @@ The following file locking methods are implemented:
protect the database file. The watchdog reads the lock file each second.
</li><li>The second method is 'socket' and opens a server socket. The socket method does
not require reading the lock file every second. The socket method should only be used
if the database files are only accessed by the one (and always the same) computer.
if the database files are only accessed by one (and always the same) computer.
</li><li>It is also possible to open the database without file locking;
in this case it is up to the application to protect the database files.
</li></ul>
......@@ -713,18 +713,18 @@ data corruption:
String url = "jdbc:h2:~/test;FILE_LOCK=NO";
</pre>
<p>
For more information about the algorithms please see in Advanced Topics under
File Locking Protocol.
For more information about the algorithms, see
<a href="advanced.html#file_locking_protocols">Advanced / File Locking Protocols</a>.
</p>
<br /><a name="database_only_if_exists"></a>
<h2>Opening a Database Only if it Already Exists</h2>
<p>
By default, when an application calls <code>DriverManager.getConnection(url,...)</code>
By default, when an application calls <code>DriverManager.getConnection(url, ...)</code>
and the database specified in the URL does not yet exist, a new (empty) database is created.
In some situations, it is better to restrict creating new database, and only open
the database if it already exists. This can be done by adding <code>;ifexists=true</code>
to the URL. In this case, if the database does not already exist, an exception is thrown when
In some situations, it is better to restrict creating new databases, and only allow to open
existing databases. To do this, add <code>;ifexists=true</code>
to the database URL. In this case, if the database does not already exist, an exception is thrown when
trying to connect. The connection only succeeds when the database already exists.
The complete URL may look like this:
</p>
......@@ -732,33 +732,33 @@ The complete URL may look like this:
String url = "jdbc:h2:/data/sample;IFEXISTS=TRUE";
</pre>
<br /><a name="closing_the_database"></a>
<h2>Closing the Database</h2>
<br /><a name="closing_a_database"></a>
<h2>Closing a Database</h2>
<h3>Delayed Database Closing</h3>
<p>
Usually, the database is closed when the last connection to it is closed. In some situations
this slows down the application, for example when it is not possible leave the connection open.
The automatic closing of the database can be delayed or disabled with the SQL statement
SET DB_CLOSE_DELAY &lt;seconds&gt;. The seconds specifies the number of seconds to keep
a database open after the last connection to it was closed. For example the following statement
will keep the database open for 10 seconds:
Usually, a database is closed when the last connection to it is closed. In some situations
this slows down the application, for example when it is not possible to keep at least one connection open.
The automatic closing of a database can be delayed or disabled with the SQL statement
SET DB_CLOSE_DELAY &lt;seconds&gt;. The parameter &lt;seconds&gt; specifies the number of seconds to keep
a database open after the last connection to it was closed. The following statement
will keep a database open for 10 seconds after the last connection was closed:
</p>
<pre>
SET DB_CLOSE_DELAY 10
</pre>
<p>
The value -1 means the database is never closed automatically.
The value -1 means the database is not closed automatically.
The value 0 is the default and means the database is closed when the last connection is closed.
This setting is persistent and can be set by an administrator only.
It is possible to set the value in the database URL: <code>jdbc:h2:~/test;DB_CLOSE_DELAY=10</code>.
</p>
<br /><a name="do_not_close_on_exit"></a>
<h3>Don't Close the Database when the VM Exits</h3>
<h3>Don't Close a Database when the VM Exits</h3>
<p>
By default, a database is closed when the last connection is closed. However, if it is never closed,
the database is closed when the virtual machine exits normally. This is done using a shutdown hook.
the database is closed when the virtual machine exits normally, using a shutdown hook.
In some situations, the database should not be closed in this case, for example because the
database is still used at virtual machine shutdown (to store the shutdown process in the database for example).
For those cases, the automatic closing of the database can be disabled in the database URL.
......@@ -781,7 +781,7 @@ In some situations, for example when using very large databases (over a few hund
re-creating the index file takes very long.
In these situations it may be better to log changes to the index file,
so that recovery from a corrupted index file is fast.
To enable log index changes, add LOG=2 to the URL, as in jdbc:h2:~/test;LOG=2
To enable log index changes, add LOG=2 to the URL, as in <code>jdbc:h2:~/test;LOG=2</code>.
This setting should be specified when connecting.
The update performance of the database will be reduced when using this option.
</p>
......@@ -801,12 +801,11 @@ saying the parameter is not supported. It is possible to ignored such parameters
<br /><a name="other_settings"></a>
<h2>Changing Other Settings when Opening a Connection</h2>
<p>
In addition to the settings already described (cipher, file_lock, ifexists, user, password),
In addition to the settings already described,
other database settings can be passed in the database URL.
Adding <code>setting=value</code> at the end of an URL is the
Adding <code>;setting=value</code> at the end of a database URL is the
same as executing the statement <code>SET setting value</code> just after
connecting. For a list of settings supported by this database please see the
SQL grammar documentation.
connecting. For a list of supported settings, see <a href="grammar.html">SQL Grammar</a>.
</p>
<br /><a name="custom_access_mode"></a>
......@@ -849,8 +848,8 @@ other processes (that could reside on other computers as well) connect to the se
<h3>Multithreading Support</h3>
<p>
This database is multithreading-safe. That means, if an application is multi-threaded, it does not need
o worry about synchronizing the access to the database. Internally, most requests to the same database
are synchronized. That means an application can use multiple threads accessing the same database
to worry about synchronizing access to the database. Internally, most requests to the same database
are synchronized. That means an application can use multiple threads that access the same database
at the same time, however if one thread executes a long running query, the other threads
need to wait.
</p>
......@@ -861,17 +860,17 @@ The database uses table level locks to give each connection a consistent state o
There are two kinds of locks: read locks (shared locks) and write locks (exclusive locks).
If a connection wants to reads from a table, and there is no write lock on the table,
then a read lock is added to the table. If there is a write lock, then this connection waits
for the other connection to release the lock. If connection cannot get a lock for a specified time,
for the other connection to release the lock. If a connection cannot get a lock for a specified time,
then a lock timeout exception is thrown.
</p><p>
Usually, SELECT statement will generate read locks. This includes subqueries.
Usually, SELECT statements will generate read locks. This includes subqueries.
Statements that modify data use write locks. It is also possible to lock a table exclusively without modifying data,
using the statement SELECT ... FOR UPDATE.
The statements COMMIT and ROLLBACK releases all open locks.
The commands SAVEPOINT and ROLLBACK TO SAVEPOINT don't affect locks.
The locks are also released when the autocommit mode changes, and for connections with
autocommit set to true (this is the default), locks are released after each statement.
Here is an overview on what statements generate what type of lock:
The following statements generate locks:
</p>
<table>
<tr>
......@@ -880,26 +879,26 @@ Here is an overview on what statements generate what type of lock:
</tr>
<tr>
<td>Read</td>
<td>SELECT * FROM TEST<br />
CALL SELECT MAX(ID) FROM TEST<br />
SCRIPT</td>
<td>SELECT * FROM TEST;<br />
CALL SELECT MAX(ID) FROM TEST;<br />
SCRIPT;</td>
</tr>
<tr>
<td>Write</td>
<td>SELECT * FROM TEST WHERE 1=0 FOR UPDATE</td>
<td>SELECT * FROM TEST WHERE 1=0 FOR UPDATE;</td>
</tr>
<tr>
<td>Write</td>
<td>INSERT INTO TEST VALUES(1, 'Hello')<br />
INSERT INTO TEST SELECT * FROM TEST<br />
UPDATE TEST SET NAME='Hi'<br />
DELETE FROM TEST</td>
<td>INSERT INTO TEST VALUES(1, 'Hello');<br />
INSERT INTO TEST SELECT * FROM TEST;<br />
UPDATE TEST SET NAME='Hi';<br />
DELETE FROM TEST;</td>
</tr>
<tr>
<td>Write</td>
<td>ALTER TABLE TEST ...<br />
CREATE INDEX ... ON TEST ...<br />
DROP INDEX ...</td>
<td>ALTER TABLE TEST ...;<br />
CREATE INDEX ... ON TEST ...;<br />
DROP INDEX ...;</td>
</tr>
</table>
<p>
......@@ -912,11 +911,11 @@ SET DEFAULT_LOCK_TIMEOUT &lt;milliseconds&gt;. The default lock timeout is persi
<br /><a name="database_file_layout"></a>
<h2>Database File Layout</h2>
<p>
There are a number of files created for persistent databases. Other than some databases,
There are a number of files created for persistent databases. Unlike some other databases,
not every table and/or index is stored in its own file. Instead, usually only the following files are created:
A data file, an index file, a log file, and a database lock file (exists only while the database is in use).
In addition to that, a file is created for each large object (CLOB/BLOB), a file for each linear index,
and temporary files for large result sets. Then the command SCRIPT can create script files.
In addition to that, a file is created for each large object (CLOB/BLOB) larger than a certain size,
and temporary files for large result sets.
If the database trace option is enabled, trace files are created.
The following files can be created by the database:
</p>
......@@ -924,8 +923,8 @@ The following files can be created by the database:
<tr><td>
test.data.db
</td><td>
Data file<br />
Contains the data for all tables<br />
Data file.<br />
Contains the data for all tables.<br />
Format: &lt;database&gt;.data.db
</td><td>
1 per database
......@@ -933,8 +932,8 @@ The following files can be created by the database:
<tr><td>
test.index.db
</td><td>
Index file<br />
Contains the data for all (btree) indexes<br />
Index file.<br />
Contains the data for all (b tree) indexes.<br />
Format: &lt;database&gt;.index.db
</td><td>
1 per database
......@@ -942,8 +941,8 @@ The following files can be created by the database:
<tr><td>
test.0.log.db
</td><td>
Log file<br />
The log file is used for recovery<br />
Transaction log file.<br />
The transaction log is used for recovery.<br />
Format: &lt;database&gt;.&lt;id&gt;.log.db
</td><td>
0 or more per database
......@@ -951,8 +950,8 @@ The following files can be created by the database:
<tr><td>
test.lock.db
</td><td>
Database lock file<br />
Exists only if the database is open<br />
Database lock file.<br />
Exists only while the database is open.<br />
Format: &lt;database&gt;.lock.db
</td><td>
1 per database
......@@ -960,45 +959,36 @@ The following files can be created by the database:
<tr><td>
test.trace.db
</td><td>
Trace file<br />
Contains trace information<br />
Trace file.<br />
Contains trace information.<br />
Format: &lt;database&gt;.trace.db<br />
If the file is too big, it is renamed to &lt;database&gt;.trace.db.old
</td><td>
1 per database
</td></tr>
<tr><td>
test.14.15.lob.db
test.lobs.db/1.t15.lob.db
</td><td>
Large object<br />
Contains the data for BLOB or CLOB<br />
Format: &lt;database&gt;.&lt;tableid&gt;.&lt;id&gt;.lob.db
Large object.<br />
Contains the data for BLOB or CLOB values.<br />
Format: &lt;id&gt;.t&lt;tableId&gt;.lob.db
</td><td>
1 per object
1 per value
</td></tr>
<tr><td>
test.123.temp.db
</td><td>
Temporary file<br />
Contains a temporary blob or a large result set<br />
Format: &lt;database&gt;.&lt;session id&gt;.&lt;object id&gt;.temp.db
Temporary file.<br />
Contains a temporary blob or a large result set.<br />
Format: &lt;database&gt;.&lt;id&gt;.temp.db
</td><td>
1 per object
</td></tr>
<tr><td>
test.7.hash.db
</td><td>
Hash index file<br />
Contains the data for a linear hash index<br />
Format: &lt;database&gt;.&lt;object id&gt;.hash.db
</td><td>
1 per linear hash index
</td></tr>
</table>
<h3>Moving and Renaming Database Files</h3>
<p>
Database name and location are not stored inside the database names.
Database name and location are not stored inside the database files.
</p><p>
While a database is closed, the files can be moved to another directory, and they can be renamed
as well (as long as all files start with the same name).
......@@ -1049,14 +1039,14 @@ and tries to be compatible to other databases. There are still a few differences
<p>
In MySQL text columns are case insensitive by default, while in H2 they are case sensitive. However
H2 supports case insensitive columns as well. To create the tables with case insensitive texts, append
IGNORECASE=TRUE to the database URL (example: jdbc:h2:~/test;IGNORECASE=TRUE).
IGNORECASE=TRUE to the database URL (example: <code>jdbc:h2:~/test;IGNORECASE=TRUE</code>).
</p>
<h3>Compatibility Modes</h3>
<p>
For certain features, this database can emulate the behavior of specific databases.
Not all features or differences of those databases are implemented.
Here is the list of currently supported modes and the difference to the regular mode:
Here is the list of currently supported modes and the differences to the regular mode:
</p>
<h3>DB2 Compatibility Mode</h3>
......@@ -1067,7 +1057,7 @@ or the SQL statement <code>SET MODE DB2</code>.
<ul><li>For aliased columns, ResultSetMetaData.getColumnName() returns the alias name
and getTableName() returns null.
</li><li>Support for the syntax [OFFSET .. ROW] [FETCH ... ONLY]
as an alternative syntax for LIMIT .. OFFSET.
as an alternative for LIMIT .. OFFSET.
</li></ul>
<h3>Derby Compatibility Mode</h3>
......@@ -1089,9 +1079,9 @@ or the SQL statement <code>SET MODE HSQLDB</code>.
<ul><li>For aliased columns, ResultSetMetaData.getColumnName() returns the alias name
and getTableName() returns null.
</li><li>When converting the scale of decimal data, the number is only converted if the new scale is
smaller then current scale. Usually, the scale is converted and 0s are added if required.
</li><li>Concatenation of a NULL with another value results in NULL. Usually, the NULL is treated as an empty
string if only one of the operators is NULL, and NULL is only returned if both values are NULL.
smaller than the current scale. Usually, the scale is converted and 0s are added if required.
</li><li>Concatenation with NULL results in NULL. Usually, NULL is treated as an empty
string if only one of the operands is NULL, and NULL is only returned if both operands are NULL.
</li><li>For unique indexes, NULL is distinct. That means only one row with NULL
in one of the columns is allowed.
</li></ul>
......@@ -1116,10 +1106,10 @@ or the SQL statement <code>SET MODE MySQL</code>.
<ul><li>When inserting data, if a column is defined to be NOT NULL and NULL is inserted,
then a 0 (or empty string, or the current timestamp for timestamp columns) value is used.
Usually, this operation is not allowed and an exception is thrown.
</li><li>Creating indexes in the CREATE TABLE statement should be supported.
</li><li>The identifiers should be returned in lower case.
</li><li>When converting a floating point number to a integer, the fractional
digits should not be truncated, but the value should be rounded.
</li><li>Creating indexes in the CREATE TABLE statement is allowed.
</li><li>Meta data calls return identifiers in lower case.
</li><li>When converting a floating point number to an integer, the fractional
digits are not truncated, but the value is rounded.
</li></ul>
<h3>Oracle Compatibility Mode</h3>
......@@ -1141,11 +1131,11 @@ or the SQL statement <code>SET MODE PostgreSQL</code>.
</p>
<ul><li>For aliased columns, ResultSetMetaData.getColumnName() returns the alias name
and getTableName() returns null.
</li><li>Concatenation of a NULL with another value results in NULL. Usually, the NULL is treated as an empty
string if only one of the operators is NULL, and NULL is only returned if both values are NULL.
</li><li>When converting a floating point number to a integer, the fractional
digits should not be truncated, but the value should be rounded.
</li><li>The system columns 'CTID' and 'OID' should be supported.
</li><li>Concatenation with NULL results in NULL. Usually, NULL is treated as an empty
string if only one of the operands is NULL, and NULL is only returned if both operands are NULL.
</li><li>When converting a floating point number to an integer, the fractional
digits are not be truncated, but the value is rounded.
</li><li>The system columns 'CTID' and 'OID' are supported.
</li></ul>
<br /><a name="auto_reconnect"></a>
......@@ -1212,7 +1202,7 @@ where executed. This database offers the following trace features:
<li>Trace to System.out and/or a file
</li><li>Support for trace levels OFF, ERROR, INFO, and DEBUG
</li><li>The maximum size of the trace file can be set
</li><li>The Java code generation is possible
</li><li>It is possible to generate Java source code from the trace file
</li><li>Trace can be enabled at runtime by manually creating a file
</li></ul>
......@@ -1240,11 +1230,11 @@ SET TRACE_LEVEL_SYSTEM_OUT 3
<h3>Setting the Maximum Size of the Trace File</h3>
<p>
When using a high trace level, the trace file can get very big quickly.
The size of the file can be limited by executing the SQL statement
<code>SET TRACE_MAX_FILE_SIZE maximumFileSizeInMB</code>.
If the log file exceeds the limit, the file is renamed to .old and a new file is created.
The default size limit is 16 MB, if the trace file exceeds this limit, it is renamed to .old and a new file is created.
If another .old file exists, it is deleted.
The default setting is 16 MB. Example:
The size limit can be changed using the SQL statement
<code>SET TRACE_MAX_FILE_SIZE maximumFileSizeInMB</code>.
Example:
</p>
<pre>
SET TRACE_MAX_FILE_SIZE 1
......@@ -1252,8 +1242,8 @@ SET TRACE_MAX_FILE_SIZE 1
<h3>Java Code Generation</h3>
<p>
When setting the trace level to INFO or DEBUG, Java source code is generated as well, so that
problem can be reproduced more easily. The trace file looks like this:
When setting the trace level to INFO or DEBUG, Java source code is generated as well.
This allows to reproduce problems more easily. The trace file looks like this:
</p>
<pre>
...
......@@ -1264,24 +1254,17 @@ problem can be reproduced more easily. The trace file looks like this:
...
</pre>
<p>
You need to filter out the lines without /**/ to get the Java source code.
In Windows, a simple way to do that is:
To filter the Java source code, use the ConvertTraceFile tool as follows:
</p>
<pre>
find "**" test.trace.db > Trace.java
java -cp h2*.jar org.h2.tools.ConvertTraceFile
-traceFile "~/test.trace.db" -javaClass "Test"
</pre>
<p>
Afterwards, you need to complete the file Trace.java before it can be compiled, for example with:
</p>
<pre>
import java.sql.*;
public class Trace { public static void main(String[]a)throws Exception {
Class.forName("org.h2.Driver");
...
}}
</pre>
<p>
Also, the user name and password needs to be set, because they are not listed in the trace file.
The generated file <code>Test.java</code> will contain the Java source code.
The generated source code may be too large to compile (the size of a Java method is limited).
If this is the case, the source code needs to be split in multiple methods.
The password is not listed in the trace file and therefore not included in the source code.
</p>
<br /><a name="other_logging"></a>
......@@ -1309,7 +1292,7 @@ jdbc:h2:~/test;TRACE_LEVEL_FILE=4
Changing the log mechanism is not possible after the database is open, that means
executing the SQL statement SET TRACE_LEVEL_FILE 4 when the database is already open
will not have the desired effect. To use SLF4J, all required jar files need to be in the classpath.
If it does not work, check in the file &lt;database&gt;.trace.db for error messages.
If it does not work, check the file &lt;database&gt;.trace.db for error messages.
</p>
<br /><a name="read_only"></a>
......@@ -1317,18 +1300,18 @@ If it does not work, check in the file &lt;database&gt;.trace.db for error messa
<p>
If the database files are read-only, then the database is read-only as well.
It is not possible to create new tables, add or modify data in this database.
Only SELECT statements are allowed.
Only SELECT and CALL statements are allowed.
To create a read-only database, close the database so that the log file gets smaller. Do not delete the log file.
Then, make the database files read-only using the operating system.
When you open the database now, it is read-only.
There are two ways an application can find out a database is read-only:
There are two ways an application can find out whether database is read-only:
By calling Connection.isReadOnly() or by executing the SQL statement CALL READONLY().
</p>
<br /><a name="database_in_zip"></a>
<h2>Read Only Databases in Zip or Jar File</h2>
<p>
To create a read-only database in a zip, first create a regular persistent database, and then create a backup.
To create a read-only database in a zip file, first create a regular persistent database, and then create a backup.
If you are using a database named 'test', an easy way to do that is using the Backup tool or the BACKUP SQL statement:
</p>
<pre>
......@@ -1343,10 +1326,10 @@ and directly open the database in the zip file using the following database URL:
jdbc:h2:zip:~/data.zip!/test
</pre>
<p>
Databases in a zip file are read-only. The performance for some queries will be slower than when using
Databases in zip files are read-only. The performance for some queries will be slower than when using
a regular database, because random access in zip files is not supported (only streaming). How much this
affects the performance depends on the queries and the data. The database
is not read in memory; so large databases are supported as well. The same indexes are used than when using
is not read in memory; therefore large databases are supported as well. The same indexes are used as when using
a regular database.
</p>
......@@ -1372,10 +1355,10 @@ The exceptions are logged, but opening the database will continue.
<br /><a name="computed_columns"></a>
<h2>Computed Columns / Function Based Index</h2>
<p>
Function indexes are not directly supported by this database, but they can be easily emulated
Function indexes are not directly supported by this database, but they can be emulated
by using computed columns. For example, if an index on the upper-case version of
a column is required, just create a computed column with the upper-case version of the original column,
and index this column:
a column is required, create a computed column with the upper-case version of the original column,
and create an index for this column:
</p>
<pre>
CREATE TABLE ADDRESS(
......@@ -1386,7 +1369,7 @@ CREATE TABLE ADDRESS(
CREATE INDEX IDX_U_NAME ON ADDRESS(UPPER_NAME);
</pre>
<p>
When inserting data, it is not required (better: not allowed) to specify a value for the upper-case
When inserting data, it is not required (and not allowed) to specify a value for the upper-case
version of the column, because the value is generated. But you can use the
column when querying the table:
</p>
......@@ -1450,25 +1433,30 @@ This database supports using char arrays instead of String to pass user and file
The following code can be used to do that:
</p>
<pre>
Class.forName("org.h2.Driver");
String url = "jdbc:h2:~/simple";
String user = "sam";
char[] password =
{'t','i','a','S','&amp;',E','t','r','p'};
Properties prop = new Properties();
prop.setProperty("user", user);
prop.put("password", password);
Connection conn = null;
try {
conn = DriverManager.
getConnection(url, prop);
} finally {
Arrays.fill(password, 0);
import java.sql.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver");
String url = "jdbc:h2:~/test";
Properties prop = new Properties();
prop.setProperty("user", "sa");
System.out.print("Password?");
char[] password = System.console().readPassword();
prop.put("password", password);
Connection conn = null;
try {
conn = DriverManager.getConnection(url, prop);
} finally {
Arrays.fill(password, (char) 0);
}
conn.close();
}
}
</pre>
<p>
In this example, the password is hard code in the application, which is not secure of course.
However, Java Swing supports a way to get passwords using a char array (JPasswordField).
This example requires Java 1.6.
When using Swing, use javax.swing.JPasswordField.
</p>
<h3>Passing the User Name and/or Password in the URL</h3>
......@@ -1496,8 +1484,8 @@ Only static Java methods are supported; both the class and the method must be pu
Example Java method:
</p>
<pre>
package org.h2.samples;
...
package acme;
import java.math.*;
public class Function {
public static boolean isPrime(int value) {
return new BigInteger(String.valueOf(value)).isProbablePrime(100);
......@@ -1508,7 +1496,7 @@ public class Function {
The Java function must be registered in the database by calling CREATE ALIAS:
</p>
<pre>
CREATE ALIAS IS_PRIME FOR "org.h2.samples.Function.isPrime"
CREATE ALIAS IS_PRIME FOR "acme.Function.isPrime"
</pre>
<p>
For a complete sample application, see src/test/org/h2/samples/Function.java.
......@@ -1517,14 +1505,16 @@ For a complete sample application, see src/test/org/h2/samples/Function.java.
<h3>Function Data Type Mapping</h3>
<p>
Functions that accept non-nullable parameters such as 'int' will not be called if one of those parameters is NULL.
In this case, the value NULL is used as the result. If the function should be called in this case, you need
Instead, the result of the function is NULL. If the function should be called if a parameter is NULL, you need
to use 'java.lang.Integer' instead of 'int'.
</p>
<h3>Functions that require a Connection</h3>
<p>
If the first parameter in a Java function is a java.sql.Connection, then the connection
If the first parameter of a Java function is a java.sql.Connection, then the connection
to database is provided. This connection does not need to be closed before returning.
When calling the method from within the SQL statement, this connection parameter
does not need to be (can not be) specified.
</p>
<h3>Functions throwing an Exception</h3>
......@@ -1548,7 +1538,7 @@ CALL QUERY('SELECT * FROM TEST');
<h3>Using SimpleResultSet</h3>
<p>
A function that returns a result set can create this result set from scratch using the SimpleResultSet tool:
A function can create a result set using the SimpleResultSet tool:
</p>
<pre>
import org.h2.tools.SimpleResultSet;
......@@ -1568,32 +1558,36 @@ CALL SIMPLE();
<h3>Using a Function as a Table</h3>
<p>
A function returning a result set can be like a table.
A function that returns a result set can be used like a table.
However, in this case the function is called at least twice:
First while parsing the statement to collect the column names
(with parameters set to null where not known at compile time).
And then, while executing the statement to get the data (may be repeatedly if this is a join).
And then, while executing the statement to get the data (maybe multiple times if this is a join).
If the function is called just to get the column list, the URL of the connection passed to the function is
jdbc:columnlist:connection. Otherwise, the URL of the connection is jdbc:default:connection.
<code>jdbc:columnlist:connection</code>. Otherwise, the URL of the connection is
<code>jdbc:default:connection</code>.
</p>
<pre>
public static ResultSet getMatrix(Integer id) throws SQLException {
public static ResultSet getMatrix(Connection conn, Integer size)
throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("X", Types.INTEGER, 10, 0);
rs.addColumn("Y", Types.INTEGER, 10, 0);
if(id == null) {
String url = conn.getMetaData().getURL();
if (url.equals("jdbc:columnlist:connection")) {
return rs;
}
for(int x = 0; x &lt; id.intValue(); x++) {
for(int y = 0; y &lt; id.intValue(); y++) {
rs.addRow(new Object[] { new Integer(x), new Integer(y) });
for (int s = size.intValue(), x = 0; x &lt; s; x++) {
for (int y = 0; y &lt; s; y++) {
rs.addRow(new Object[] {
new Integer(x), new Integer(y) });
}
}
return rs;
}
CREATE ALIAS MATRIX FOR "org.h2.samples.Function.getMatrix";
SELECT * FROM MATRIX(3) WHERE X>0;
SELECT * FROM MATRIX(4) ORDER BY X, Y;
</pre>
<br /><a name="triggers"></a>
......@@ -1609,8 +1603,8 @@ A Java trigger must implement the interface org.h2.api.Trigger:
import org.h2.api.Trigger;
...
public class TriggerSample implements Trigger {
public void init(String triggerName, String tableName) {
}
public void init(Connection conn, String schemaName, String triggerName,
String tableName, boolean before, int type) {
public void fire(Connection conn,
Object[] oldRow, Object[] newRow)
throws SQLException {
......@@ -1626,7 +1620,7 @@ CREATE TRIGGER INV_INS AFTER INSERT ON INVOICE
FOR EACH ROW CALL "org.h2.samples.TriggerSample"
</pre>
<p>
The trigger can be used to veto a change, by throwing a SQL Exception.
The trigger can be used to veto a change, by throwing a SQLException.
</p>
<br /><a name="compacting"></a>
......
......@@ -44,31 +44,31 @@ public class Mode {
/**
* When converting the scale of decimal data, the number is only converted
* if the new scale is smaller then current scale. Usually, the scale is
* if the new scale is smaller than the current scale. Usually, the scale is
* converted and 0s are added if required.
*/
public boolean convertOnlyToSmallerScale;
/**
* Creating indexes in the CREATE TABLE statement should be supported.
* Creating indexes in the CREATE TABLE statement is allowed.
*/
public boolean indexDefinitionInCreateTable;
/**
* The identifiers should be returned in lower case.
* Meta data calls return identifiers in lower case.
*/
public boolean lowerCaseIdentifiers;
/**
* Concatenation of a NULL with another value results in NULL. Usually, the
* NULL is treated as an empty string if only one of the operators is NULL,
* and NULL is only returned if both values are NULL.
* Concatenation with NULL results in NULL. Usually, NULL is treated as an
* empty string if only one of the operands is NULL, and NULL is only
* returned if both operands are NULL.
*/
public boolean nullConcatIsNull;
/**
* When converting a floating point number to a integer, the fractional
* digits should not be truncated, but the value should be rounded.
* When converting a floating point number to an integer, the fractional
* digits are not truncated, but the value is rounded.
*/
public boolean roundWhenConvertToLong;
......@@ -79,12 +79,12 @@ public class Mode {
/**
* Support for the syntax [OFFSET .. ROW] [FETCH ... ONLY]
* as an alternative syntax for LIMIT .. OFFSET.
* as an alternative for LIMIT .. OFFSET.
*/
public boolean supportOffsetFetch;
/**
* The system columns 'CTID' and 'OID' should be supported.
* The system columns 'CTID' and 'OID' are supported.
*/
public boolean systemColumns;
......
......@@ -49,7 +49,8 @@ public class Compact {
* @param user the user name
* @param password the password
*/
public static void compact(String dir, String dbName, String user, String password) throws SQLException {
public static void compact(String dir, String dbName,
String user, String password) throws SQLException {
String url = "jdbc:h2:" + dir + "/" + dbName;
String file = "data/test.sql";
Script.execute(url, user, password, file);
......
......@@ -55,9 +55,19 @@ public class Function {
new Integer[] { new Integer(30), new Integer(20) });
prep.setObject(2,
new Integer[] { new Integer(1), new Integer(2) });
ResultSet rs2 = prep.executeQuery();
while (rs2.next()) {
System.out.println(rs2.getInt(1));
rs = prep.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1));
}
// Using a custom function like table
stat.execute("CREATE ALIAS MATRIX FOR \"org.h2.samples.Function.getMatrix\" ");
prep = conn.prepareStatement("SELECT * FROM MATRIX(?) " +
"ORDER BY X, Y");
prep.setInt(1, 2);
rs = prep.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1) + "/" + rs.getInt(2));
}
conn.close();
......@@ -97,4 +107,29 @@ public class Function {
return rs;
}
/**
* Creates a simple result set with two columns.
*
* @param conn the connection
* @param size the number of x and y values
* @return the result set with two columns
*/
public static ResultSet getMatrix(Connection conn, Integer size)
throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("X", Types.INTEGER, 10, 0);
rs.addColumn("Y", Types.INTEGER, 10, 0);
String url = conn.getMetaData().getURL();
if (url.equals("jdbc:columnlist:connection")) {
return rs;
}
for (int s = size.intValue(), x = 0; x < s; x++) {
for (int y = 0; y < s; y++) {
rs.addRow(new Object[] {
new Integer(x), new Integer(y) });
}
}
return rs;
}
}
......@@ -131,6 +131,11 @@ public class TaskProcess {
process.destroy();
}
/**
* Trace the operation. Tracing is disabled by default.
*
* @param s the string to print
*/
private void traceOperation(String s) {
// ignore
}
......
......@@ -46,7 +46,7 @@ public class TestSampleApps extends TestBase {
+ "PHONE: +41123456789\n\n" + "NAME: John Jones\n" + "EMAIL: john.jones@abcde.abc\n"
+ "PHONE: +41976543210\n");
testApp(org.h2.samples.Function.class, null,
"2 is prime\n3 is prime\n5 is prime\n7 is prime\n11 is prime\n13 is prime\n17 is prime\n19 is prime\n30\n20");
"2 is prime\n3 is prime\n5 is prime\n7 is prime\n11 is prime\n13 is prime\n17 is prime\n19 is prime\n30\n20\n0/0\n0/1\n1/0\n1/1");
// Not compatible with PostgreSQL JDBC driver (throws a NullPointerException)
//testApp(org.h2.samples.SecurePassword.class, null, "Joe");
// TODO test ShowProgress (percent numbers are hardware specific)
......
......@@ -586,4 +586,4 @@ soerensen favicon glass restarts flexive fish resulted vpda mvc kotek jan
consistently springfuse grep signatures wrote symbolic parents caches readers
animate scaladoc models disadvantages vladykin sergi trims requesting
handing bonita placed euros embeds reliability singular unregister quotas
overall httpdocs tigris eclemma
\ No newline at end of file
overall httpdocs tigris eclemma separates
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论