提交 2d919fb1 authored 作者: isuruperera's avatar isuruperera

Merge branch 'master' of https://github.com/h2database/h2database

distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
\ No newline at end of file \ No newline at end of file
...@@ -5,24 +5,59 @@ Welcome to H2, the Java SQL database. The main features of H2 are: ...@@ -5,24 +5,59 @@ Welcome to H2, the Java SQL database. The main features of H2 are:
* Very fast, open source, JDBC API * Very fast, open source, JDBC API
* Embedded and server modes; in-memory databases * Embedded and server modes; in-memory databases
* Browser based Console application * Browser based Console application
* Small footprint: around 1.5 MB jar file size * Small footprint: around 2 MB jar file size
## Experimental Building & Testing with Maven ## Experimental Building & Testing with Maven
### Preparation
Use non-Maven build to create all necessary resources:
```Batchfile
./build.cmd compile
```
or
```sh
./build.sh compile
```
### Building ### Building
H2 uses [Maven Wrapper](https://github.com/takari/maven-wrapper) setup, you can instruct users to run wrapper scripts: To build only the database jar use
```sh
mvn -Dmaven.test.skip=true package
```
If you don't have Maven installed use included [Maven Wrapper](https://github.com/takari/maven-wrapper) setup:
> $ ./mvnw clean test ```sh
./mvnw -Dmaven.test.skip=true package
```
or or
> $ ./mvnw.cmd clean test ```Batchfile
./mvnw.cmd -Dmaven.test.skip=true package
```
Please note that jar generated with Maven is larger than official one and it does not include OSGi attributes.
Use build script with `jar` target instead if you need a compatible jar.
### Testing
To run the tests use
```sh
mvn clean test
```
### Running ### Running
You can run the server like this You can run the server like this
``` ```sh
mvn exec:java -Dexec.mainClass=org.h2.tools.Server mvn exec:java -Dexec.mainClass=org.h2.tools.Server
``` ```
\ No newline at end of file
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
<properties> <properties>
<maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target> <maven.compiler.target>1.7</maven.compiler.target>
<derby.version>10.10.1.1</derby.version>
<osgi.version>4.2.0</osgi.version> <osgi.version>4.2.0</osgi.version>
<slf4j.version>1.6.0</slf4j.version> <slf4j.version>1.6.0</slf4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
...@@ -56,7 +55,17 @@ ...@@ -56,7 +55,17 @@
<dependency> <dependency>
<groupId>org.apache.lucene</groupId> <groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId> <artifactId>lucene-core</artifactId>
<version>3.6.2</version> <version>5.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>5.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>5.5.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
...@@ -88,40 +97,10 @@ ...@@ -88,40 +97,10 @@
<version>${slf4j.version}</version> <version>${slf4j.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>${derby.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>${derby.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
<version>${derby.version}</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>9.4.1209.jre6</version> <version>42.2.5.jre7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
...@@ -210,7 +189,7 @@ ...@@ -210,7 +189,7 @@
<directory>src/test</directory> <directory>src/test</directory>
<includes> <includes>
<include>org/h2/test/scripts/testSimple.in.txt</include> <include>org/h2/test/scripts/testSimple.in.txt</include>
<include>org/h2/test/scripts/testScript.sql</include> <include>org/h2/test/scripts/**/*.sql</include>
<include>org/h2/samples/newsfeed.sql</include> <include>org/h2/samples/newsfeed.sql</include>
<include>org/h2/samples/optimizations.sql</include> <include>org/h2/samples/optimizations.sql</include>
</includes> </includes>
...@@ -220,6 +199,7 @@ ...@@ -220,6 +199,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
...@@ -299,7 +279,7 @@ ...@@ -299,7 +279,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version> <version>2.22.0</version>
<configuration> <configuration>
<includes> <includes>
<include>TestAllJunit.java</include> <include>TestAllJunit.java</include>
......
...@@ -273,10 +273,21 @@ When using the isolation level 'serializable', dirty reads, non-repeatable reads ...@@ -273,10 +273,21 @@ When using the isolation level 'serializable', dirty reads, non-repeatable reads
</li> </li>
</ul> </ul>
<h3>Table Level Locking</h3> <h3 id="mvcc">Multi-Version Concurrency Control (MVCC)</h3>
<p> <p>
The database allows multiple concurrent connections to the same database. With default MVStore engine delete, insert and update operations only issue a shared lock on the table.
To make sure all connections only see consistent data, table level locking is used by default. An exclusive lock is still used when adding or removing columns,
when dropping the table, and when using <code>SELECT ... FOR UPDATE</code>.
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.
Only when the change is committed, the new value is visible by other connections
(read committed). If multiple connections concurrently try to update the same row, the
database waits until it can apply the change, but at most until the lock timeout expires.
</p>
<h3>Table Level Locking (PageStore engine)</h3>
<p>
With PageStore engine to make sure all connections only see consistent data, table level locking is used.
This mechanism does not allow high concurrency, but is very fast. This mechanism does not allow high concurrency, but is very fast.
Shared locks and exclusive locks are supported. Shared locks and exclusive locks are supported.
Before reading from a table, the database tries to add a shared lock to the table Before reading from a table, the database tries to add a shared lock to the table
...@@ -300,26 +311,6 @@ connection will get a lock timeout exception. The lock timeout can be set indivi ...@@ -300,26 +311,6 @@ connection will get a lock timeout exception. The lock timeout can be set indivi
for each connection. for each connection.
</p> </p>
<h2 id="mvcc">Multi-Version Concurrency Control (MVCC)</h2>
<p>
The MVCC feature allows higher concurrency than using (table level or row level) locks.
Delete, insert and update operations will only issue a shared lock on the table.
An exclusive lock is still used when adding or removing columns,
when dropping the table, and when using <code>SELECT ... FOR UPDATE</code>.
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.
Only when the change is committed, the new value is visible by other connections
(read committed). If multiple connections concurrently try to update the same row, the
database waits until it can apply the change, but at most until the lock timeout expires.
</p>
<p>
This feature is only available with the default MVStore storage engine.
Changing the lock mode with it (<code>LOCK_MODE</code>) has no effect.
</p>
<p>
MVCC is not used when using the PageStore storage engine.
</p>
<h2 id="clustering">Clustering / High Availability</h2> <h2 id="clustering">Clustering / High Availability</h2>
<p> <p>
This database supports a simple clustering / high availability mechanism. The architecture is: This database supports a simple clustering / high availability mechanism. The architecture is:
...@@ -488,10 +479,10 @@ ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DI ...@@ -488,10 +479,10 @@ ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DI
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS, EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS,
IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER,
PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE, PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
WITH WINDOW, WITH
</code> </code>
</p><p> </p><p>
Certain words of this list are keywords because they are functions that can be used without '()' for compatibility, Certain words of this list are keywords because they are functions that can be used without '()',
for example <code>CURRENT_TIMESTAMP</code>. for example <code>CURRENT_TIMESTAMP</code>.
</p> </p>
...@@ -1559,6 +1550,7 @@ The following file systems are included: ...@@ -1559,6 +1550,7 @@ The following file systems are included:
</li><li><code>nioMapped:</code> file system that uses memory mapped files (faster in some operating systems). </li><li><code>nioMapped:</code> file system that uses memory mapped files (faster in some operating systems).
Please note that there currently is a file size limitation of 2 GB when using this file system. Please note that there currently is a file size limitation of 2 GB when using this file system.
To work around this limitation, combine it with the split file system: <code>split:nioMapped:test</code>. To work around this limitation, combine it with the split file system: <code>split:nioMapped:test</code>.
</li><li><code>async:</code> experimental file system that uses <code>AsynchronousFileChannel</code> instead of <code>RandomAccessFile</code> (faster in some operating systems).
</li><li><code>memFS:</code> in-memory file system (slower than mem; experimental; mainly used for testing the database engine itself). </li><li><code>memFS:</code> in-memory file system (slower than mem; experimental; mainly used for testing the database engine itself).
</li><li><code>memLZF:</code> compressing in-memory file system (slower than memFS but uses less memory; experimental; mainly used for testing the database engine itself). </li><li><code>memLZF:</code> compressing in-memory file system (slower than memFS but uses less memory; experimental; mainly used for testing the database engine itself).
</li><li><code>nioMemFS:</code> stores data outside of the VM's heap - useful for large memory DBs without incurring GC costs. </li><li><code>nioMemFS:</code> stores data outside of the VM's heap - useful for large memory DBs without incurring GC costs.
...@@ -1572,8 +1564,9 @@ The following file systems are included: ...@@ -1572,8 +1564,9 @@ The following file systems are included:
The default value is 1%. The default value is 1%.
</li></ul> </li></ul>
<p> <p>
As an example, to use the the <code>nio</code> file system, use the following database URL: As an example, to use the the <code>nio</code> file system with PageStore storage engine,
<code>jdbc:h2:nio:~/test</code>. use the following database URL: <code>jdbc:h2:nio:~/test;MV_STORE=FALSE</code>.
With MVStore storage engine nio file system is used by default.
</p> </p>
<p> <p>
To register a new file system, extend the classes <code>org.h2.store.fs.FilePath, FileBase</code>, To register a new file system, extend the classes <code>org.h2.store.fs.FilePath, FileBase</code>,
......
...@@ -115,8 +115,8 @@ build jarClient ...@@ -115,8 +115,8 @@ build jarClient
<h3>Using Apache Lucene</h3> <h3>Using Apache Lucene</h3>
<p> <p>
Apache Lucene 3.6.2 is used for testing. Apache Lucene 5.5.5 is used for testing.
Newer versions may work, however they are not tested. Newer versions up to 7.5.0 can also be used.
</p> </p>
<h2 id="maven2">Using Maven 2</h2> <h2 id="maven2">Using Maven 2</h2>
......
...@@ -21,6 +21,136 @@ Change Log ...@@ -21,6 +21,136 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1565: SOME / ANY conflict
</li>
<li>PR #1564: Refactor Expression implementations
</li>
<li>Issue #1561: Incorrect documentation and strange fallback value of SysProperties.FILE_ENCODING
</li>
<li>Issue #1566: MVStore implements Closeable/AutoCloseable
</li>
<li>Issue #1550: OutOfMemoryError during "shutdown defrag"
</li>
<li>Issue #1440: OOM when executing "shutdown compact" in server mode
</li>
<li>Issue #1561: Incorrect documentation and strange fallback value of SysProperties.FILE_ENCODING
</li>
<li>PR #1557: increase lock timeout to TestConcurrentUpdate due to Travis failures
</li>
<li>Issue #1554: REGEXP_REPLACE - accept 'g' flag in PostgreSQL compatibility mode
</li>
<li>Issue #950: Comparison between databases in README.md and in features.html
</li>
<li>Issue #1549: [RFE] Implement locking modes (select for update)
</li>
<li>PR #1548: Add AsynchronousFileChannel-based experimental FilePathAsync
</li>
<li>PR #1547: Speedup unused chunks collection
</li>
<li>PR #1546: Tiny optimization: use `System.arraycopy` when possible
</li>
<li>PR #1545: Export datetime value functions to SQL using standard syntax
</li>
<li>Issue #1371: NPE in CacheLRU
</li>
<li>Issue #1534: Typo in message
</li>
<li>Issue #1527: Parser performance: Excessive use of regular expressions to validate column names
</li>
<li>PR #1543: MVStore assorted re-factorings
</li>
<li>PR #1538: Add support for newer Lucene versions without recompilation
</li>
<li>Issue #1536: CURRENT_TIMESTAMP result doesn't change under Transactions
</li>
<li>Issue #239: Consider supporting Lucene 5 indexes
</li>
<li>PR #1520: Fixes bug in PutIfAbsentDecisionMaker
</li>
<li>Issue #1518: ENUM and VIEW with filtering on enum column
</li>
<li>Issue #1516: Array element reference array[index] should be 1-based
</li>
<li>Issue #1512: TestMVTableEngine.testLowRetentionTime(): NPE in VersionedValue.Type
</li>
<li>PR #1513: Assorted minor changes
</li>
<li>PR #1510: Add optional EXCEPT clause to wildcards
</li>
<li>PR #1509: Use domain term everywhere
</li>
<li>Issue #1507: Add INFORMATION_SCHEMA.COLUMNS.COLUMN_TYPE qualification for domains
</li>
<li>Issue #1499: TestScript::envelope.sql failure in &#8220;big&#8221; mode
</li>
<li>Issue #1498: NPE in SimpleResultSet.getColumnCount()
</li>
<li>Issue #1495: MERGE statement doesn't affect any rows when Oracle UPDATE .. WHERE .. DELETE .. WHERE is used
</li>
<li>Issue #1493: MERGE statement fails when it updates more than one row
</li>
<li>Issue #1492: Unnecessary restriction on MERGE USING statement when ON clause doesn't reference any target table columns
</li>
<li>Issue #1491: Unnecessary restriction on MERGE USING statement when ON predicate doesn't match inserted row
</li>
<li>Issue #1490: NullPointerException when running invalid MERGE statement
</li>
<li>Issue #1489: MERGE USING documentation has misleading railroad diagram
</li>
<li>Issue #1488: Improve documentation of window and some other functions
</li>
<li>Issue #1485: Default window frame in presence of ORDER BY is RANGE .., not ROWS
</li>
<li>PR #1484: New tests, reimplemented EXCLUDE clause, and assorted changes
</li>
<li>Issue #1338: MSSQLServer compatibility enhancements
</li>
<li>PR #1480: Update Maven build instruction and fix some problems
</li>
<li>PR #1478: Upgrade maven-surefire-plugin
</li>
<li>PR #1476: Add TransactionStore to MVStore jar
</li>
<li>Issue #1475: Dropping column used by a view produces misleading error message
</li>
<li>Issue #1473: TestScript needs better detection of sorted result
</li>
<li>PR #1471: issue 1350: TestCrashAPI: PageStore.freeListPagesPerList
</li>
<li>PR #1470: Fix window functions in queries with HAVING
</li>
<li>PR #1469: Forbid incorrect nesting of aggregates and window functions
</li>
<li>Issue #1437: Generated as Identity has a different behaviour.
</li>
<li>PR #1467: Fix subtraction of timestamps
</li>
<li>PR #1464: Assorted minor changes in window processing code
</li>
<li>PR #1463: Fix some window aggregates and reduce amount of collecting implementations
</li>
<li>PR #1462: Separate aggregate and window code in some places
</li>
<li>PR #1461: Add WINDOW clause support
</li>
<li>Issue #1427: Scalability problem in MVSpatialIndex
</li>
<li>PR #1459: Improve window clause correctness checks
</li>
<li>PR #1457: Add NTILE(), LEAD() and LAG() window functions
</li>
<li>PR #1456: Add experimental implementation of remaining types of window frames
</li>
<li>PR #1454: Add FIRST_VALUE(), LAST_VALUE(), and NTH_VALUE()
</li>
<li>PR #1453, Issue #1161: Add ROW_NUMBER(), RANK(), DENSE_RANK(), PERCENT_RANK(), and CUME_DIST() window functions
</li>
<li>PR #1452: Reset aggregates before reuse
</li>
<li>PR #1451: Add experimental support for aggregates with OVER (ORDER BY *)
</li>
<li>PR #1450: Evaluate window aggregates only once for each partition
</li>
<li>PR #1449: Move more code from Aggregate and JavaAggregate to AbstractAggregate <li>PR #1449: Move more code from Aggregate and JavaAggregate to AbstractAggregate
</li> </li>
<li>PR #1448: Add experimental implementation of grouped window queries <li>PR #1448: Add experimental implementation of grouped window queries
...@@ -33,6 +163,8 @@ Change Log ...@@ -33,6 +163,8 @@ Change Log
</li> </li>
<li>PR #1444: Add experimental unoptimized support for OVER ([PARTITION BY ...]) in aggregates <li>PR #1444: Add experimental unoptimized support for OVER ([PARTITION BY ...]) in aggregates
</li> </li>
<li>PR #1442: Bugfix - Release MVStore lock and file resources rightly even if errors when compacting database
</li>
<li>PR #1441: Add GEOMETRY type subtypes with type and SRID constraints <li>PR #1441: Add GEOMETRY type subtypes with type and SRID constraints
</li> </li>
<li>PR #1434: Add support for ENUM in CAST and other changes <li>PR #1434: Add support for ENUM in CAST and other changes
......
...@@ -180,7 +180,8 @@ Areas considered experimental are: ...@@ -180,7 +180,8 @@ Areas considered experimental are:
<li>The PostgreSQL server <li>The PostgreSQL server
</li><li>Clustering (there are cases were transaction isolation can be broken </li><li>Clustering (there are cases were transaction isolation can be broken
due to timing issues, for example one session overtaking another session). due to timing issues, for example one session overtaking another session).
</li><li>Multi-threading within the engine using <code>SET MULTI_THREADED=1</code>. </li><li>Multi-threading within the old PageStore engine using <code>SET MULTI_THREADED=1</code>.
Default MVStore engine is multi-threaded by default.
</li><li>Compatibility modes for other databases (only some features are implemented). </li><li>Compatibility modes for other databases (only some features are implemented).
</li><li>The soft reference cache (<code>CACHE_TYPE=SOFT_LRU</code>). It might not improve performance, </li><li>The soft reference cache (<code>CACHE_TYPE=SOFT_LRU</code>). It might not improve performance,
and out of memory issues have been reported. and out of memory issues have been reported.
......
...@@ -159,6 +159,34 @@ syntax-end --> ...@@ -159,6 +159,34 @@ syntax-end -->
</table> </table>
<!-- railroad-end --> <!-- railroad-end -->
<h3>Window Functions</h3>
<!-- syntax-start
<p class="notranslate">
<c:forEach var="item" items="functionsWindow">
<a href="#${item.link}" >${item.topic}</a><br />
</c:forEach>
</p>
syntax-end -->
<!-- railroad-start -->
<table class="notranslate index">
<tr>
<td class="index">
<c:forEach var="item" items="functionsWindow-0">
<a href="#${item.link}" >${item.topic}</a><br />
</c:forEach>
</td><td class="index">
<c:forEach var="item" items="functionsWindow-1">
<a href="#${item.link}" >${item.topic}</a><br />
</c:forEach>
</td><td class="index">
<c:forEach var="item" items="functionsWindow-2">
<a href="#${item.link}" >${item.topic}</a><br />
</c:forEach>
</td>
</tr>
</table>
<!-- railroad-end -->
<!-- railroad-start --> <!-- railroad-start -->
<h2>Details</h2> <h2>Details</h2>
<p>Click on the header to switch between railroad diagram and BNF.</p> <p>Click on the header to switch between railroad diagram and BNF.</p>
...@@ -269,6 +297,27 @@ syntax-end --> ...@@ -269,6 +297,27 @@ syntax-end -->
<p class="notranslate">${item.example}</p> <p class="notranslate">${item.example}</p>
</c:forEach> </c:forEach>
<h2>Window Functions</h2>
<c:forEach var="item" items="functionsWindow">
<h3 id="${item.link}" class="notranslate" onclick="switchBnf(this)">${item.topic}</h3>
<!-- railroad-start -->
<pre name="bnf" style="display: none">
${item.syntax}
</pre>
<div name="railroad">
${item.railroad}
</div>
<!-- railroad-end -->
<!-- syntax-start
<pre>
${item.syntax}
</pre>
syntax-end -->
<p>${item.text}</p>
<p>Example:</p>
<p class="notranslate">${item.example}</p>
</c:forEach>
<!--[if lte IE 7]><script language="javascript">switchBnf(null);</script><![endif]--> <!--[if lte IE 7]><script language="javascript">switchBnf(null);</script><![endif]-->
<!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html> <!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html>
......
...@@ -256,7 +256,12 @@ ${item.example}</p> ...@@ -256,7 +256,12 @@ ${item.example}</p>
<c:forEach var="item" items="otherGrammar"> <c:forEach var="item" items="otherGrammar">
<h3 id="${item.link}" class="notranslate" onclick="switchBnf(this)">${item.topic}</h3> <h3 id="${item.link}" class="notranslate" onclick="switchBnf(this)">${item.topic}</h3>
<!-- railroad-start --> <!-- railroad-start -->
<pre name="bnf" style="display: none">
${item.syntax}
</pre>
<div name="railroad">
${item.railroad} ${item.railroad}
</div>
<!-- railroad-end --> <!-- railroad-end -->
<!-- syntax-start <!-- syntax-start
<pre> <pre>
......
...@@ -146,9 +146,6 @@ Welcome to H2, the Java SQL database. The main features of H2 are: ...@@ -146,9 +146,6 @@ Welcome to H2, the Java SQL database. The main features of H2 are:
<td>~700 KB</td> <td>~700 KB</td>
</tr> </tr>
</table> </table>
<p>
See also the <a href="features.html#comparison">detailed comparison</a>.
</p>
</td></tr> </td></tr>
<tr><td colspan="3" style="border: 0px; background-color: #eee;"> <tr><td colspan="3" style="border: 0px; background-color: #eee;">
......
...@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example: ...@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example:
</p> </p>
<pre> <pre>
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"SELECT * FROM TEST WHERE ID = ANY(?)"); "SELECT * FROM TEST WHERE ID IN(UNNEST(?))");
prep.setObject(1, new Object[] { "1", "2" }); prep.setObject(1, new Object[] { "1", "2" });
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
</pre> </pre>
......
...@@ -60,8 +60,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -60,8 +60,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
DBMS_METADATA.GET_DDL / GET_DEPENDENT_DDL. DBMS_METADATA.GET_DDL / GET_DEPENDENT_DDL.
</li><li>Clustering: support mixed clustering mode (one embedded, others in server mode). </li><li>Clustering: support mixed clustering mode (one embedded, others in server mode).
</li><li>Clustering: reads should be randomly distributed (optional) or to a designated database on RAM (parameter: READ_FROM=3). </li><li>Clustering: reads should be randomly distributed (optional) or to a designated database on RAM (parameter: READ_FROM=3).
</li><li>Window functions: RANK() and DENSE_RANK(), partition using OVER().
select *, count(*) over() as fullCount from ... limit 4;
</li><li>PostgreSQL catalog: use BEFORE SELECT triggers instead of views over metadata tables. </li><li>PostgreSQL catalog: use BEFORE SELECT triggers instead of views over metadata tables.
</li><li>Test very large databases and LOBs (up to 256 GB). </li><li>Test very large databases and LOBs (up to 256 GB).
</li><li>Store all temp files in the temp directory. </li><li>Store all temp files in the temp directory.
...@@ -87,7 +85,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -87,7 +85,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Index usage for (ID, NAME)=(1, 'Hi'); document. </li><li>Index usage for (ID, NAME)=(1, 'Hi'); document.
</li><li>Set a connection read only (Connection.setReadOnly) or using a connection parameter. </li><li>Set a connection read only (Connection.setReadOnly) or using a connection parameter.
</li><li>Access rights: finer grained access control (grant access for specific functions). </li><li>Access rights: finer grained access control (grant access for specific functions).
</li><li>ROW_NUMBER() OVER([PARTITION BY columnName][ORDER BY columnName]).
</li><li>Version check: docs / web console (using Javascript), and maybe in the library (using TCP/IP). </li><li>Version check: docs / web console (using Javascript), and maybe in the library (using TCP/IP).
</li><li>Web server classloader: override findResource / getResourceFrom. </li><li>Web server classloader: override findResource / getResourceFrom.
</li><li>Cost for embedded temporary view is calculated wrong, if result is constant. </li><li>Cost for embedded temporary view is calculated wrong, if result is constant.
...@@ -120,7 +117,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -120,7 +117,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>The HELP information schema can be directly exposed in the Console. </li><li>The HELP information schema can be directly exposed in the Console.
</li><li>Maybe use the 0x1234 notation for binary fields, see MS SQL Server. </li><li>Maybe use the 0x1234 notation for binary fields, see MS SQL Server.
</li><li>Support Oracle CONNECT BY in some way: http://www.adp-gmbh.ch/ora/sql/connect_by.html http://philip.greenspun.com/sql/trees.html </li><li>Support Oracle CONNECT BY in some way: http://www.adp-gmbh.ch/ora/sql/connect_by.html http://philip.greenspun.com/sql/trees.html
</li><li>SQL Server 2005, Oracle: support COUNT(*) OVER(). See http://www.orafusion.com/art_anlytc.htm
</li><li>SQL 2003: http://www.wiscorp.com/sql_2003_standard.zip </li><li>SQL 2003: http://www.wiscorp.com/sql_2003_standard.zip
</li><li>Version column (number/sequence and timestamp based). </li><li>Version column (number/sequence and timestamp based).
</li><li>Test and document UPDATE TEST SET (ID, NAME) = (SELECT ID*10, NAME || '!' FROM TEST T WHERE T.ID=TEST.ID). </li><li>Test and document UPDATE TEST SET (ID, NAME) = (SELECT ID*10, NAME || '!' FROM TEST T WHERE T.ID=TEST.ID).
...@@ -413,7 +409,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -413,7 +409,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Issue 196: Function based indexes </li><li>Issue 196: Function based indexes
</li><li>Fix the disk space leak (killing the process at the exact right moment will increase </li><li>Fix the disk space leak (killing the process at the exact right moment will increase
the disk space usage; this space is not re-used). See TestDiskSpaceLeak.java the disk space usage; this space is not re-used). See TestDiskSpaceLeak.java
</li><li>ROWNUM: Oracle compatibility when used within a subquery. Issue 198.
</li><li>Allow to access the database over HTTP (possibly using port 80) and a servlet in a REST way. </li><li>Allow to access the database over HTTP (possibly using port 80) and a servlet in a REST way.
</li><li>ODBC: encrypted databases are not supported because the ;CIPHER= can not be set. </li><li>ODBC: encrypted databases are not supported because the ;CIPHER= can not be set.
</li><li>Support CLOB and BLOB update, specially conn.createBlob().setBinaryStream(1); </li><li>Support CLOB and BLOB update, specially conn.createBlob().setBinaryStream(1);
......
...@@ -1234,8 +1234,8 @@ org.h2.fulltext.FullText.searchData(conn, text, limit, offset); ...@@ -1234,8 +1234,8 @@ org.h2.fulltext.FullText.searchData(conn, text, limit, offset);
<h3>Using the Apache Lucene Fulltext Search</h3> <h3>Using the Apache Lucene Fulltext Search</h3>
<p> <p>
To use the Apache Lucene full text search, you need the Lucene library in the classpath. To use the Apache Lucene full text search, you need the Lucene library in the classpath.
Currently, Apache Lucene 3.6.2 is used for testing. Apache Lucene 5.5.5 or later version up to 7.5.0 is required.
Newer versions may work, however they are not tested. Newer versions may also work, but were not tested.
How to do that depends on the application; if you use the H2 Console, you can add the Lucene How to do that depends on the application; if you use the H2 Console, you can add the Lucene
jar file to the environment variables <code>H2DRIVERS</code> or jar file to the environment variables <code>H2DRIVERS</code> or
<code>CLASSPATH</code>. <code>CLASSPATH</code>.
......
...@@ -149,8 +149,8 @@ ...@@ -149,8 +149,8 @@
90116=Literals of this kind are not allowed 90116=Literals of this kind are not allowed
90117=Remote connections to this server are not allowed, see -tcpAllowOthers 90117=Remote connections to this server are not allowed, see -tcpAllowOthers
90118=Cannot drop table {0} 90118=Cannot drop table {0}
90119=User data type {0} already exists 90119=Domain {0} already exists
90120=User data type {0} not found 90120=Domain {0} not found
90121=Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) 90121=Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL)
90122=The WITH TIES clause is not allowed without a corresponding ORDER BY clause. 90122=The WITH TIES clause is not allowed without a corresponding ORDER BY clause.
90123=Cannot mix indexed and non-indexed parameters 90123=Cannot mix indexed and non-indexed parameters
...@@ -166,7 +166,7 @@ ...@@ -166,7 +166,7 @@
90133=Cannot change the setting {0} when the database is already open 90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied 90134=Access to the class {0} is denied
90135=The database is open in exclusive mode; can not open additional connections 90135=The database is open in exclusive mode; can not open additional connections
90136=Unsupported outer join condition: {0} 90136=Window not found: {0}
90137=Can only assign to a variable, not to: {0} 90137=Can only assign to a variable, not to: {0}
90138=Invalid database name: {0} 90138=Invalid database name: {0}
90139=The public static Java method was not found: {0} 90139=The public static Java method was not found: {0}
...@@ -175,6 +175,7 @@ ...@@ -175,6 +175,7 @@
90142=Step size must not be zero 90142=Step size must not be zero
90143=Row {1} not found in primary index {0} 90143=Row {1} not found in primary index {0}
90144=Authenticator not enabled on database {0} 90144=Authenticator not enabled on database {0}
90145=FOR UPDATE is not allowed in DISTINCT or grouped select
HY000=General error: {0} HY000=General error: {0}
HY004=Unknown data type: {0} HY004=Unknown data type: {0}
HYC00=Feature not supported: {0} HYC00=Feature not supported: {0}
......
...@@ -14,8 +14,10 @@ Bundle-Vendor: H2 Group ...@@ -14,8 +14,10 @@ Bundle-Vendor: H2 Group
Bundle-Version: ${version} Bundle-Version: ${version}
Bundle-License: http://www.h2database.com/html/license.html Bundle-License: http://www.h2database.com/html/license.html
Bundle-Category: utility Bundle-Category: utility
Multi-Release: true
Import-Package: javax.crypto, Import-Package: javax.crypto,
javax.crypto.spec javax.crypto.spec
Export-Package: org.h2.mvstore;version="${version}", Export-Package: org.h2.mvstore;version="${version}",
org.h2.mvstore.tx;version="${version}",
org.h2.mvstore.type;version="${version}", org.h2.mvstore.type;version="${version}",
org.h2.mvstore.rtree;version="${version}" org.h2.mvstore.rtree;version="${version}"
...@@ -56,6 +56,9 @@ Update org.h2.engine.Constants.java: ...@@ -56,6 +56,9 @@ Update org.h2.engine.Constants.java:
set BUILD_DATE to today set BUILD_DATE to today
increment BUILD_ID increment BUILD_ID
Update org.h2.value.Transfer.java:
if the last TCP_PROTOCOL_VERSION_## doesn't have a release date set it to current BUILD_DATE
Update changelog.html: Update changelog.html:
* create a new "Next Version (unreleased)" with an empty list * create a new "Next Version (unreleased)" with an empty list
* add a new version * add a new version
......
...@@ -41,14 +41,14 @@ Import-Package: javax.crypto, ...@@ -41,14 +41,14 @@ Import-Package: javax.crypto,
org.w3c.dom;resolution:=optional, org.w3c.dom;resolution:=optional,
org.xml.sax;resolution:=optional, org.xml.sax;resolution:=optional,
org.xml.sax.helpers;resolution:=optional, org.xml.sax.helpers;resolution:=optional,
org.apache.lucene.analysis;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.analysis;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.analysis.standard;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.analysis.standard;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.document;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.document;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.index;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.index;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.queryParser;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.queryparser;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.search;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.search;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.store;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.store;version="[5.5.5,8.0.0)";resolution:=optional,
org.apache.lucene.util;version="[3.6.2,4.0.0)";resolution:=optional, org.apache.lucene.util;version="[5.5.5,8.0.0)";resolution:=optional,
org.locationtech.jts.geom;version="1.15.0";resolution:=optional, org.locationtech.jts.geom;version="1.15.0";resolution:=optional,
org.locationtech.jts.io;version="1.15.0";resolution:=optional, org.locationtech.jts.io;version="1.15.0";resolution:=optional,
org.osgi.framework;version="1.5", org.osgi.framework;version="1.5",
......
...@@ -1748,7 +1748,13 @@ public class ErrorCode { ...@@ -1748,7 +1748,13 @@ public class ErrorCode {
* CREATE DOMAIN EMAIL AS VARCHAR CHECK LOCATE('@', VALUE) > 0; * CREATE DOMAIN EMAIL AS VARCHAR CHECK LOCATE('@', VALUE) > 0;
* </pre> * </pre>
*/ */
public static final int USER_DATA_TYPE_ALREADY_EXISTS_1 = 90119; public static final int DOMAIN_ALREADY_EXISTS_1 = 90119;
/**
* Deprecated since 1.4.198. Use {@link #DOMAIN_ALREADY_EXISTS_1} instead.
*/
@Deprecated
public static final int USER_DATA_TYPE_ALREADY_EXISTS_1 = DOMAIN_ALREADY_EXISTS_1;
/** /**
* The error with code <code>90120</code> is thrown when * The error with code <code>90120</code> is thrown when
...@@ -1758,7 +1764,13 @@ public class ErrorCode { ...@@ -1758,7 +1764,13 @@ public class ErrorCode {
* DROP DOMAIN UNKNOWN; * DROP DOMAIN UNKNOWN;
* </pre> * </pre>
*/ */
public static final int USER_DATA_TYPE_NOT_FOUND_1 = 90120; public static final int DOMAIN_NOT_FOUND_1 = 90120;
/**
* Deprecated since 1.4.198. Use {@link #DOMAIN_NOT_FOUND_1} instead.
*/
@Deprecated
public static final int USER_DATA_TYPE_NOT_FOUND_1 = DOMAIN_NOT_FOUND_1;
/** /**
* The error with code <code>90121</code> is thrown when * The error with code <code>90121</code> is thrown when
...@@ -1926,6 +1938,16 @@ public class ErrorCode { ...@@ -1926,6 +1938,16 @@ public class ErrorCode {
*/ */
public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135; public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135;
/**
* The error with code <code>90136</code> is thrown when
* trying to reference a window that does not exist.
* Example:
* <pre>
* SELECT LEAD(X) OVER W FROM TEST;
* </pre>
*/
public static final int WINDOW_NOT_FOUND_1 = 90136;
/** /**
* The error with code <code>90137</code> is thrown when * The error with code <code>90137</code> is thrown when
* trying to assign a value to something that is not a variable. * trying to assign a value to something that is not a variable.
...@@ -2008,8 +2030,20 @@ public class ErrorCode { ...@@ -2008,8 +2030,20 @@ public class ErrorCode {
*/ */
public static final int AUTHENTICATOR_NOT_AVAILABLE = 90144; public static final int AUTHENTICATOR_NOT_AVAILABLE = 90144;
/**
* The error with code <code>90145</code> is thrown when trying to execute a
* SELECT statement with non-window aggregates, DISTINCT, GROUP BY, or
* HAVING clauses together with FOR UPDATE clause.
*
* <pre>
* SELECT DISTINCT NAME FOR UPDATE;
* SELECT MAX(VALUE) FOR UPDATE;
* </pre>
*/
public static final int FOR_UPDATE_IS_NOT_ALLOWED_IN_DISTINCT_OR_GROUPED_SELECT = 90145;
// next are 90136, 90145 // next is 90146
private ErrorCode() { private ErrorCode() {
// utility class // utility class
......
...@@ -628,7 +628,8 @@ public final class Interval { ...@@ -628,7 +628,8 @@ public final class Interval {
@Override @Override
public String toString() { public String toString() {
return IntervalUtils.intervalToString(qualifier, negative, leading, remaining); return IntervalUtils.appendInterval(new StringBuilder(), getQualifier(), negative, leading, remaining)
.toString();
} }
} }
...@@ -7,6 +7,7 @@ package org.h2.api; ...@@ -7,6 +7,7 @@ package org.h2.api;
import java.io.Serializable; import java.io.Serializable;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.value.ValueTimestampTimeZone;
/** /**
* How we expose "TIMESTAMP WITH TIME ZONE" in our ResultSets. * How we expose "TIMESTAMP WITH TIME ZONE" in our ResultSets.
...@@ -109,7 +110,9 @@ public class TimestampWithTimeZone implements Serializable, Cloneable { ...@@ -109,7 +110,9 @@ public class TimestampWithTimeZone implements Serializable, Cloneable {
@Override @Override
public String toString() { public String toString() {
return DateTimeUtils.timestampTimeZoneToString(dateValue, timeNanos, timeZoneOffsetMins); StringBuilder builder = new StringBuilder(ValueTimestampTimeZone.MAXIMUM_PRECISION);
DateTimeUtils.appendTimestampTimeZone(builder, dateValue, timeNanos, timeZoneOffsetMins);
return builder.toString();
} }
@Override @Override
......
...@@ -405,7 +405,7 @@ public abstract class Prepared { ...@@ -405,7 +405,7 @@ public abstract class Prepared {
for (Value v : values) { for (Value v : values) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
if (v != null) { if (v != null) {
buff.append(v.getSQL()); v.getSQL(buff.builder());
} }
} }
return buff.toString(); return buff.toString();
...@@ -418,14 +418,9 @@ public abstract class Prepared { ...@@ -418,14 +418,9 @@ public abstract class Prepared {
* @return the SQL snippet * @return the SQL snippet
*/ */
protected static String getSQL(Expression[] list) { protected static String getSQL(Expression[] list) {
StatementBuilder buff = new StatementBuilder(); StringBuilder builder = new StringBuilder();
for (Expression e : list) { Expression.writeExpressions(builder, list);
buff.appendExceptFirst(", "); return builder.toString();
if (e != null) {
buff.append(e.getSQL());
}
}
return buff.toString();
} }
/** /**
......
...@@ -3,15 +3,13 @@ ...@@ -3,15 +3,13 @@
* and the EPL 1.0 (http://h2database.com/html/license.html). * and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.command.dml; package org.h2.command.ddl;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.ddl.SchemaCommand;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
...@@ -19,21 +17,19 @@ import org.h2.table.Column; ...@@ -19,21 +17,19 @@ import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
/** /**
* This class represents the statement * This class represents the statement ALTER SEQUENCE.
* ALTER SEQUENCE
*/ */
public class AlterSequence extends SchemaCommand { public class AlterSequence extends SchemaCommand {
private boolean ifExists; private boolean ifExists;
private Table table; private Table table;
private String sequenceName; private String sequenceName;
private Sequence sequence; private Sequence sequence;
private Expression start;
private Expression increment; private SequenceOptions options;
private Boolean cycle;
private Expression minValue;
private Expression maxValue;
private Expression cacheSize;
public AlterSequence(Session session, Schema schema) { public AlterSequence(Session session, Schema schema) {
super(session, schema); super(session, schema);
...@@ -47,6 +43,10 @@ public class AlterSequence extends SchemaCommand { ...@@ -47,6 +43,10 @@ public class AlterSequence extends SchemaCommand {
this.sequenceName = sequenceName; this.sequenceName = sequenceName;
} }
public void setOptions(SequenceOptions options) {
this.options = options;
}
@Override @Override
public boolean isTransactional() { public boolean isTransactional() {
return true; return true;
...@@ -60,30 +60,6 @@ public class AlterSequence extends SchemaCommand { ...@@ -60,30 +60,6 @@ public class AlterSequence extends SchemaCommand {
} }
} }
public void setStartWith(Expression start) {
this.start = start;
}
public void setIncrement(Expression increment) {
this.increment = increment;
}
public void setCycle(Boolean cycle) {
this.cycle = cycle;
}
public void setMinValue(Expression minValue) {
this.minValue = minValue;
}
public void setMaxValue(Expression maxValue) {
this.maxValue = maxValue;
}
public void setCacheSize(Expression cacheSize) {
this.cacheSize = cacheSize;
}
@Override @Override
public int update() { public int update() {
Database db = session.getDatabase(); Database db = session.getDatabase();
...@@ -99,32 +75,22 @@ public class AlterSequence extends SchemaCommand { ...@@ -99,32 +75,22 @@ public class AlterSequence extends SchemaCommand {
if (table != null) { if (table != null) {
session.getUser().checkRight(table, Right.ALL); session.getUser().checkRight(table, Right.ALL);
} }
Boolean cycle = options.getCycle();
if (cycle != null) { if (cycle != null) {
sequence.setCycle(cycle); sequence.setCycle(cycle);
} }
if (cacheSize != null) { Long cache = options.getCacheSize(session);
long size = cacheSize.optimize(session).getValue(session).getLong(); if (cache != null) {
sequence.setCacheSize(size); sequence.setCacheSize(cache);
} }
if (start != null || minValue != null || if (options.isRangeSet()) {
maxValue != null || increment != null) { sequence.modify(options.getStartValue(session), options.getMinValue(sequence, session),
Long startValue = getLong(start); options.getMaxValue(sequence, session), options.getIncrement(session));
Long min = getLong(minValue);
Long max = getLong(maxValue);
Long inc = getLong(increment);
sequence.modify(startValue, min, max, inc);
} }
db.updateMeta(session, sequence); db.updateMeta(session, sequence);
return 0; return 0;
} }
private Long getLong(Expression expr) {
if (expr == null) {
return null;
}
return expr.optimize(session).getValue(session).getLong();
}
@Override @Override
public int getType() { public int getType() {
return CommandInterface.ALTER_SEQUENCE; return CommandInterface.ALTER_SEQUENCE;
......
...@@ -191,7 +191,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -191,7 +191,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
String name = generateConstraintName(table); String name = generateConstraintName(table);
ConstraintCheck check = new ConstraintCheck(getSchema(), id, name, table); ConstraintCheck check = new ConstraintCheck(getSchema(), id, name, table);
TableFilter filter = new TableFilter(session, table, null, false, null, 0, null); TableFilter filter = new TableFilter(session, table, null, false, null, 0, null);
checkExpression.mapColumns(filter, 0); checkExpression.mapColumns(filter, 0, Expression.MAP_INITIAL);
checkExpression = checkExpression.optimize(session); checkExpression = checkExpression.optimize(session);
check.setExpression(checkExpression); check.setExpression(checkExpression);
check.setTableFilter(filter); check.setTableFilter(filter);
......
...@@ -297,7 +297,7 @@ public class AlterTableAlterColumn extends CommandWithColumns { ...@@ -297,7 +297,7 @@ public class AlterTableAlterColumn extends CommandWithColumns {
checkViews(table, newTable); checkViews(table, newTable);
} catch (DbException e) { } catch (DbException e) {
execute("DROP TABLE " + newTable.getName(), true); execute("DROP TABLE " + newTable.getName(), true);
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, e, getSQL(), e.getMessage()); throw e;
} }
String tableName = table.getName(); String tableName = table.getName();
ArrayList<TableView> dependentViews = new ArrayList<>(table.getDependentViews()); ArrayList<TableView> dependentViews = new ArrayList<>(table.getDependentViews());
...@@ -547,7 +547,11 @@ public class AlterTableAlterColumn extends CommandWithColumns { ...@@ -547,7 +547,11 @@ public class AlterTableAlterColumn extends CommandWithColumns {
// check if the query is still valid // check if the query is still valid
// do not execute, not even with limit 1, because that could // do not execute, not even with limit 1, because that could
// have side effects or take a very long time // have side effects or take a very long time
session.prepare(sql); try {
session.prepare(sql);
} catch (DbException e) {
throw DbException.get(ErrorCode.COLUMN_IS_REFERENCED_1, e, view.getSQL());
}
checkViewsAreValid(view); checkViewsAreValid(view);
} }
} }
......
...@@ -8,8 +8,8 @@ package org.h2.command.ddl; ...@@ -8,8 +8,8 @@ package org.h2.command.ddl;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Domain;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.UserDataType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
...@@ -19,13 +19,13 @@ import org.h2.value.DataType; ...@@ -19,13 +19,13 @@ import org.h2.value.DataType;
* This class represents the statement * This class represents the statement
* CREATE DOMAIN * CREATE DOMAIN
*/ */
public class CreateUserDataType extends DefineCommand { public class CreateDomain extends DefineCommand {
private String typeName; private String typeName;
private Column column; private Column column;
private boolean ifNotExists; private boolean ifNotExists;
public CreateUserDataType(Session session) { public CreateDomain(Session session) {
super(session); super(session);
} }
...@@ -47,30 +47,30 @@ public class CreateUserDataType extends DefineCommand { ...@@ -47,30 +47,30 @@ public class CreateUserDataType extends DefineCommand {
session.commit(true); session.commit(true);
Database db = session.getDatabase(); Database db = session.getDatabase();
session.getUser().checkAdmin(); session.getUser().checkAdmin();
if (db.findUserDataType(typeName) != null) { if (db.findDomain(typeName) != null) {
if (ifNotExists) { if (ifNotExists) {
return 0; return 0;
} }
throw DbException.get( throw DbException.get(
ErrorCode.USER_DATA_TYPE_ALREADY_EXISTS_1, ErrorCode.DOMAIN_ALREADY_EXISTS_1,
typeName); typeName);
} }
DataType builtIn = DataType.getTypeByName(typeName, session.getDatabase().getMode()); DataType builtIn = DataType.getTypeByName(typeName, session.getDatabase().getMode());
if (builtIn != null) { if (builtIn != null) {
if (!builtIn.hidden) { if (!builtIn.hidden) {
throw DbException.get( throw DbException.get(
ErrorCode.USER_DATA_TYPE_ALREADY_EXISTS_1, ErrorCode.DOMAIN_ALREADY_EXISTS_1,
typeName); typeName);
} }
Table table = session.getDatabase().getFirstUserTable(); Table table = session.getDatabase().getFirstUserTable();
if (table != null) { if (table != null) {
throw DbException.get( throw DbException.get(
ErrorCode.USER_DATA_TYPE_ALREADY_EXISTS_1, ErrorCode.DOMAIN_ALREADY_EXISTS_1,
typeName + " (" + table.getSQL() + ")"); typeName + " (" + table.getSQL() + ")");
} }
} }
int id = getObjectId(); int id = getObjectId();
UserDataType type = new UserDataType(db, id, typeName); Domain type = new Domain(db, id, typeName);
type.setColumn(column); type.setColumn(column);
db.addDatabaseObject(session, type); db.addDatabaseObject(session, type);
return 0; return 0;
......
...@@ -9,25 +9,21 @@ import org.h2.api.ErrorCode; ...@@ -9,25 +9,21 @@ import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
/** /**
* This class represents the statement * This class represents the statement CREATE SEQUENCE.
* CREATE SEQUENCE
*/ */
public class CreateSequence extends SchemaCommand { public class CreateSequence extends SchemaCommand {
private String sequenceName; private String sequenceName;
private boolean ifNotExists; private boolean ifNotExists;
private boolean cycle;
private Expression minValue; private SequenceOptions options;
private Expression maxValue;
private Expression start;
private Expression increment;
private Expression cacheSize;
private boolean belongsToTable; private boolean belongsToTable;
public CreateSequence(Session session, Schema schema) { public CreateSequence(Session session, Schema schema) {
...@@ -42,8 +38,8 @@ public class CreateSequence extends SchemaCommand { ...@@ -42,8 +38,8 @@ public class CreateSequence extends SchemaCommand {
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
} }
public void setCycle(boolean cycle) { public void setOptions(SequenceOptions options) {
this.cycle = cycle; this.options = options;
} }
@Override @Override
...@@ -57,48 +53,17 @@ public class CreateSequence extends SchemaCommand { ...@@ -57,48 +53,17 @@ public class CreateSequence extends SchemaCommand {
throw DbException.get(ErrorCode.SEQUENCE_ALREADY_EXISTS_1, sequenceName); throw DbException.get(ErrorCode.SEQUENCE_ALREADY_EXISTS_1, sequenceName);
} }
int id = getObjectId(); int id = getObjectId();
Long startValue = getLong(start); Sequence sequence = new Sequence(getSchema(), id, sequenceName, options.getStartValue(session),
Long inc = getLong(increment); options.getIncrement(session), options.getCacheSize(session), options.getMinValue(null, session),
Long cache = getLong(cacheSize); options.getMaxValue(null, session), Boolean.TRUE.equals(options.getCycle()), belongsToTable);
Long min = getLong(minValue);
Long max = getLong(maxValue);
Sequence sequence = new Sequence(getSchema(), id, sequenceName, startValue, inc,
cache, min, max, cycle, belongsToTable);
db.addSchemaObject(session, sequence); db.addSchemaObject(session, sequence);
return 0; return 0;
} }
private Long getLong(Expression expr) {
if (expr == null) {
return null;
}
return expr.optimize(session).getValue(session).getLong();
}
public void setStartWith(Expression start) {
this.start = start;
}
public void setIncrement(Expression increment) {
this.increment = increment;
}
public void setMinValue(Expression minValue) {
this.minValue = minValue;
}
public void setMaxValue(Expression maxValue) {
this.maxValue = maxValue;
}
public void setBelongsToTable(boolean belongsToTable) { public void setBelongsToTable(boolean belongsToTable) {
this.belongsToTable = belongsToTable; this.belongsToTable = belongsToTable;
} }
public void setCacheSize(Expression cacheSize) {
this.cacheSize = cacheSize;
}
@Override @Override
public int getType() { public int getType() {
return CommandInterface.CREATE_SEQUENCE; return CommandInterface.CREATE_SEQUENCE;
......
...@@ -74,7 +74,7 @@ public class CreateUser extends DefineCommand { ...@@ -74,7 +74,7 @@ public class CreateUser extends DefineCommand {
char[] passwordChars = pwd == null ? new char[0] : pwd.toCharArray(); char[] passwordChars = pwd == null ? new char[0] : pwd.toCharArray();
byte[] userPasswordHash; byte[] userPasswordHash;
String userName = user.getName(); String userName = user.getName();
if (userName.length() == 0 && passwordChars.length == 0) { if (userName.isEmpty() && passwordChars.length == 0) {
userPasswordHash = new byte[0]; userPasswordHash = new byte[0];
} else { } else {
userPasswordHash = SHA256.getKeyPasswordHash(userName, passwordChars); userPasswordHash = SHA256.getKeyPasswordHash(userName, passwordChars);
......
...@@ -135,7 +135,7 @@ public class DropDatabase extends DefineCommand { ...@@ -135,7 +135,7 @@ public class DropDatabase extends DefineCommand {
ArrayList<DbObject> dbObjects = new ArrayList<>(); ArrayList<DbObject> dbObjects = new ArrayList<>();
dbObjects.addAll(db.getAllRights()); dbObjects.addAll(db.getAllRights());
dbObjects.addAll(db.getAllAggregates()); dbObjects.addAll(db.getAllAggregates());
dbObjects.addAll(db.getAllUserDataTypes()); dbObjects.addAll(db.getAllDomains());
for (DbObject obj : dbObjects) { for (DbObject obj : dbObjects) {
String sql = obj.getCreateSQL(); String sql = obj.getCreateSQL();
// the role PUBLIC must not be dropped // the role PUBLIC must not be dropped
......
...@@ -9,8 +9,8 @@ import org.h2.api.ErrorCode; ...@@ -9,8 +9,8 @@ import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.constraint.ConstraintActionType; import org.h2.constraint.ConstraintActionType;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Domain;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.UserDataType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
...@@ -19,13 +19,13 @@ import org.h2.table.Table; ...@@ -19,13 +19,13 @@ import org.h2.table.Table;
* This class represents the statement * This class represents the statement
* DROP DOMAIN * DROP DOMAIN
*/ */
public class DropUserDataType extends DefineCommand { public class DropDomain extends DefineCommand {
private String typeName; private String typeName;
private boolean ifExists; private boolean ifExists;
private ConstraintActionType dropAction; private ConstraintActionType dropAction;
public DropUserDataType(Session session) { public DropDomain(Session session) {
super(session); super(session);
dropAction = session.getDatabase().getSettings().dropRestrict ? dropAction = session.getDatabase().getSettings().dropRestrict ?
ConstraintActionType.RESTRICT : ConstraintActionType.CASCADE; ConstraintActionType.RESTRICT : ConstraintActionType.CASCADE;
...@@ -44,22 +44,22 @@ public class DropUserDataType extends DefineCommand { ...@@ -44,22 +44,22 @@ public class DropUserDataType extends DefineCommand {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
session.commit(true); session.commit(true);
Database db = session.getDatabase(); Database db = session.getDatabase();
UserDataType type = db.findUserDataType(typeName); Domain type = db.findDomain(typeName);
if (type == null) { if (type == null) {
if (!ifExists) { if (!ifExists) {
throw DbException.get(ErrorCode.USER_DATA_TYPE_NOT_FOUND_1, typeName); throw DbException.get(ErrorCode.DOMAIN_NOT_FOUND_1, typeName);
} }
} else { } else {
for (Table t : db.getAllTablesAndViews(false)) { for (Table t : db.getAllTablesAndViews(false)) {
boolean modified = false; boolean modified = false;
for (Column c : t.getColumns()) { for (Column c : t.getColumns()) {
UserDataType udt = c.getUserDataType(); Domain domain = c.getDomain();
if (udt != null && udt.getName().equals(typeName)) { if (domain != null && domain.getName().equals(typeName)) {
if (dropAction == ConstraintActionType.RESTRICT) { if (dropAction == ConstraintActionType.RESTRICT) {
throw DbException.get(ErrorCode.CANNOT_DROP_2, typeName, t.getCreateSQL()); throw DbException.get(ErrorCode.CANNOT_DROP_2, typeName, t.getCreateSQL());
} }
c.setOriginalSQL(type.getColumn().getOriginalSQL()); c.setOriginalSQL(type.getColumn().getOriginalSQL());
c.setUserDataType(null); c.setDomain(null);
modified = true; modified = true;
} }
} }
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.command.ddl;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.expression.ValueExpression;
import org.h2.schema.Sequence;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Sequence options.
*/
public class SequenceOptions {
private Expression start;
private Expression increment;
private Expression maxValue;
private Expression minValue;
private Boolean cycle;
private Expression cacheSize;
private static Long getLong(Session session, Expression expr) {
if (expr != null) {
Value value = expr.optimize(session).getValue(session);
if (value != ValueNull.INSTANCE) {
return value.getLong();
}
}
return null;
}
public Long getStartValue(Session session) {
return getLong(session, start);
}
public void setStartValue(Expression start) {
this.start = start;
}
public Long getIncrement(Session session) {
return getLong(session, increment);
}
public void setIncrement(Expression increment) {
this.increment = increment;
}
public Long getMaxValue(Sequence sequence, Session session) {
if (maxValue == ValueExpression.getNull() && sequence != null) {
return Sequence.getDefaultMaxValue(getCurrentStart(sequence, session),
increment != null ? getIncrement(session) : sequence.getIncrement());
}
return getLong(session, maxValue);
}
public void setMaxValue(Expression maxValue) {
this.maxValue = maxValue;
}
public Long getMinValue(Sequence sequence, Session session) {
if (minValue == ValueExpression.getNull() && sequence != null) {
return Sequence.getDefaultMinValue(getCurrentStart(sequence, session),
increment != null ? getIncrement(session) : sequence.getIncrement());
}
return getLong(session, minValue);
}
public long getCurrentStart(Sequence sequence, Session session) {
return start != null ? getStartValue(session) : sequence.getCurrentValue() + sequence.getIncrement();
}
public void setMinValue(Expression minValue) {
this.minValue = minValue;
}
public Boolean getCycle() {
return cycle;
}
public void setCycle(Boolean cycle) {
this.cycle = cycle;
}
public Long getCacheSize(Session session) {
return getLong(session, cacheSize);
}
public void setCacheSize(Expression cacheSize) {
this.cacheSize = cacheSize;
}
protected boolean isRangeSet() {
return start != null || minValue != null || maxValue != null || increment != null;
}
}
...@@ -80,10 +80,10 @@ public class SetComment extends DefineCommand { ...@@ -80,10 +80,10 @@ public class SetComment extends DefineCommand {
schemaName = null; schemaName = null;
object = db.getUser(objectName); object = db.getUser(objectName);
break; break;
case DbObject.USER_DATATYPE: case DbObject.DOMAIN:
schemaName = null; schemaName = null;
object = db.findUserDataType(objectName); object = db.findDomain(objectName);
errorCode = ErrorCode.USER_DATA_TYPE_ALREADY_EXISTS_1; errorCode = ErrorCode.DOMAIN_ALREADY_EXISTS_1;
break; break;
default: default:
} }
......
...@@ -5,14 +5,12 @@ ...@@ -5,14 +5,12 @@
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.sql.ResultSet;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.LocalResultFactory;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -65,9 +63,7 @@ public class Call extends Prepared { ...@@ -65,9 +63,7 @@ public class Call extends Prepared {
setCurrentRowNumber(1); setCurrentRowNumber(1);
Value v = expression.getValue(session); Value v = expression.getValue(session);
if (isResultSet) { if (isResultSet) {
v = v.convertTo(Value.RESULT_SET); return v.getResult();
ResultSet rs = v.getResultSet();
return LocalResultFactory.read(session, rs, maxrows);
} }
LocalResult result = session.getDatabase().getResultFactory().create(session, expressions, 1); LocalResult result = session.getDatabase().getResultFactory().create(session, expressions, 1);
Value[] row = { v }; Value[] row = { v };
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.util.HashSet;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared; import org.h2.command.Prepared;
...@@ -18,7 +20,6 @@ import org.h2.result.RowList; ...@@ -18,7 +20,6 @@ import org.h2.result.RowList;
import org.h2.table.PlanItem; import org.h2.table.PlanItem;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -40,6 +41,8 @@ public class Delete extends Prepared { ...@@ -40,6 +41,8 @@ public class Delete extends Prepared {
*/ */
private TableFilter sourceTableFilter; private TableFilter sourceTableFilter;
private HashSet<Long> keysFilter;
public Delete(Session session) { public Delete(Session session) {
super(session); super(session);
} }
...@@ -56,6 +59,15 @@ public class Delete extends Prepared { ...@@ -56,6 +59,15 @@ public class Delete extends Prepared {
return this.condition; return this.condition;
} }
/**
* Sets the keys filter.
*
* @param keysFilter the keys filter
*/
public void setKeysFilter(HashSet<Long> keysFilter) {
this.keysFilter = keysFilter;
}
@Override @Override
public int update() { public int update() {
targetTableFilter.startQuery(session); targetTableFilter.startQuery(session);
...@@ -79,16 +91,23 @@ public class Delete extends Prepared { ...@@ -79,16 +91,23 @@ public class Delete extends Prepared {
setCurrentRowNumber(rows.size() + 1); setCurrentRowNumber(rows.size() + 1);
if (condition == null || condition.getBooleanValue(session)) { if (condition == null || condition.getBooleanValue(session)) {
Row row = targetTableFilter.get(); Row row = targetTableFilter.get();
boolean done = false; if (keysFilter == null || keysFilter.contains(row.getKey())) {
if (table.fireRow()) { boolean done = false;
done = table.fireBeforeRow(session, row, null); if (table.fireRow()) {
} done = table.fireBeforeRow(session, row, null);
if (!done) { }
rows.add(row); if (!done) {
} if (table.isMVStore()) {
count++; done = table.lockRow(session, row) == null;
if (limitRows >= 0 && count >= limitRows) { }
break; if (!done) {
rows.add(row);
}
}
count++;
if (limitRows >= 0 && count >= limitRows) {
break;
}
} }
} }
} }
...@@ -117,15 +136,15 @@ public class Delete extends Prepared { ...@@ -117,15 +136,15 @@ public class Delete extends Prepared {
@Override @Override
public String getPlanSQL() { public String getPlanSQL() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append("DELETE "); buff.append("DELETE FROM ");
buff.append("FROM ").append(targetTableFilter.getPlanSQL(false)); targetTableFilter.getPlanSQL(buff, false);
if (condition != null) { if (condition != null) {
buff.append("\nWHERE ").append(StringUtils.unEnclose( buff.append("\nWHERE ");
condition.getSQL())); condition.getUnenclosedSQL(buff);
} }
if (limitExpr != null) { if (limitExpr != null) {
buff.append("\nLIMIT (").append(StringUtils.unEnclose( buff.append("\nLIMIT (");
limitExpr.getSQL())).append(')'); limitExpr.getUnenclosedSQL(buff).append(')');
} }
return buff.toString(); return buff.toString();
} }
...@@ -133,9 +152,9 @@ public class Delete extends Prepared { ...@@ -133,9 +152,9 @@ public class Delete extends Prepared {
@Override @Override
public void prepare() { public void prepare() {
if (condition != null) { if (condition != null) {
condition.mapColumns(targetTableFilter, 0); condition.mapColumns(targetTableFilter, 0, Expression.MAP_INITIAL);
if (sourceTableFilter != null) { if (sourceTableFilter != null) {
condition.mapColumns(sourceTableFilter, 0); condition.mapColumns(sourceTableFilter, 0, Expression.MAP_INITIAL);
} }
condition = condition.optimize(session); condition = condition.optimize(session);
condition.createIndexConditions(session, targetTableFilter); condition.createIndexConditions(session, targetTableFilter);
......
...@@ -18,12 +18,12 @@ import org.h2.engine.Mode; ...@@ -18,12 +18,12 @@ import org.h2.engine.Mode;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.UndoLogRecord; import org.h2.engine.UndoLogRecord;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.expression.condition.Comparison;
import org.h2.expression.condition.ConditionAndOr;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.PageDataIndex; import org.h2.index.PageDataIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -130,6 +130,14 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -130,6 +130,14 @@ public class Insert extends Prepared implements ResultTarget {
public int update() { public int update() {
Index index = null; Index index = null;
if (sortedInsertMode) { if (sortedInsertMode) {
if (!session.getDatabase().isMVStore()) {
/*
* Take exclusive lock, otherwise two different inserts running at
* the same time, the second might accidentally get
* sorted-insert-mode.
*/
table.lock(session, /* exclusive */true, /* forceLockEvenInMvcc */true);
}
index = table.getScanIndex(session); index = table.getScanIndex(session);
index.setSortedInsertMode(true); index.setSortedInsertMode(true);
} }
...@@ -297,15 +305,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -297,15 +305,7 @@ public class Insert extends Prepared implements ResultTarget {
buff.append(",\n"); buff.append(",\n");
} }
buff.append('('); buff.append('(');
buff.resetCount(); Expression.writeExpressions(buff.builder(), expr);
for (Expression e : expr) {
buff.appendExceptFirst(", ");
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
}
}
buff.append(')'); buff.append(')');
} }
} else { } else {
...@@ -333,7 +333,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -333,7 +333,7 @@ public class Insert extends Prepared implements ResultTarget {
Expression e = expr[i]; Expression e = expr[i];
if (e != null) { if (e != null) {
if(sourceTableFilter!=null){ if(sourceTableFilter!=null){
e.mapColumns(sourceTableFilter, 0); e.mapColumns(sourceTableFilter, 0, Expression.MAP_INITIAL);
} }
e = e.optimize(session); e = e.optimize(session);
if (e instanceof Parameter) { if (e instanceof Parameter) {
...@@ -421,7 +421,8 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -421,7 +421,8 @@ public class Insert extends Prepared implements ResultTarget {
for (Column column : duplicateKeyAssignmentMap.keySet()) { for (Column column : duplicateKeyAssignmentMap.keySet()) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
Expression ex = duplicateKeyAssignmentMap.get(column); Expression ex = duplicateKeyAssignmentMap.get(column);
buff.append(column.getSQL()).append('=').append(ex.getSQL()); buff.append(column.getSQL()).append('=');
ex.getSQL(buff.builder());
} }
buff.append(" WHERE "); buff.append(" WHERE ");
Index foundIndex = (Index) de.getSource(); Index foundIndex = (Index) de.getSource();
...@@ -429,7 +430,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -429,7 +430,7 @@ public class Insert extends Prepared implements ResultTarget {
throw DbException.getUnsupportedException( throw DbException.getUnsupportedException(
"Unable to apply ON DUPLICATE KEY UPDATE, no index found!"); "Unable to apply ON DUPLICATE KEY UPDATE, no index found!");
} }
buff.append(prepareUpdateCondition(foundIndex, row).getSQL()); prepareUpdateCondition(foundIndex, row).getSQL(buff.builder());
String sql = buff.toString(); String sql = buff.toString();
Update command = (Update) session.prepare(sql); Update command = (Update) session.prepare(sql);
command.setUpdateToCurrentValuesReturnsZero(true); command.setUpdateToCurrentValuesReturnsZero(true);
......
...@@ -242,15 +242,7 @@ public class Merge extends Prepared { ...@@ -242,15 +242,7 @@ public class Merge extends Prepared {
buff.append(", "); buff.append(", ");
} }
buff.append('('); buff.append('(');
buff.resetCount(); Expression.writeExpressions(buff.builder(), expr);
for (Expression e : expr) {
buff.appendExceptFirst(", ");
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
}
}
buff.append(')'); buff.append(')');
} }
} else { } else {
......
...@@ -19,9 +19,9 @@ import org.h2.expression.Alias; ...@@ -19,9 +19,9 @@ import org.h2.expression.Alias;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
import org.h2.expression.Function;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.expression.function.FunctionCall;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.ResultTarget; import org.h2.result.ResultTarget;
...@@ -344,6 +344,10 @@ public abstract class Query extends Prepared { ...@@ -344,6 +344,10 @@ public abstract class Query extends Prepared {
if (!cacheableChecked) { if (!cacheableChecked) {
long max = getMaxDataModificationId(); long max = getMaxDataModificationId();
noCache = max == Long.MAX_VALUE; noCache = max == Long.MAX_VALUE;
if (!isEverything(ExpressionVisitor.DETERMINISTIC_VISITOR) ||
!isEverything(ExpressionVisitor.INDEPENDENT_VISITOR)) {
noCache = true;
}
cacheableChecked = true; cacheableChecked = true;
} }
if (noCache) { if (noCache) {
...@@ -356,18 +360,10 @@ public abstract class Query extends Prepared { ...@@ -356,18 +360,10 @@ public abstract class Query extends Prepared {
return false; return false;
} }
} }
if (!isEverything(ExpressionVisitor.DETERMINISTIC_VISITOR) || return getMaxDataModificationId() <= lastEval;
!isEverything(ExpressionVisitor.INDEPENDENT_VISITOR)) {
return false;
}
if (db.getModificationDataId() > lastEval &&
getMaxDataModificationId() > lastEval) {
return false;
}
return true;
} }
public final Value[] getParameterValues() { private Value[] getParameterValues() {
ArrayList<Parameter> list = getParameters(); ArrayList<Parameter> list = getParameters();
if (list == null) { if (list == null) {
return new Value[0]; return new Value[0];
...@@ -559,8 +555,8 @@ public abstract class Query extends Prepared { ...@@ -559,8 +555,8 @@ public abstract class Query extends Prepared {
} }
} }
int count = expr.getSubexpressionCount(); int count = expr.getSubexpressionCount();
if (expr instanceof Function) { if (expr instanceof FunctionCall) {
if (!((Function) expr).isDeterministic()) { if (!((FunctionCall) expr).isDeterministic()) {
return false; return false;
} }
} else if (count <= 0) { } else if (count <= 0) {
......
...@@ -222,15 +222,7 @@ public class Replace extends Prepared { ...@@ -222,15 +222,7 @@ public class Replace extends Prepared {
buff.append(", "); buff.append(", ");
} }
buff.append('('); buff.append('(');
buff.resetCount(); Expression.writeExpressions(buff.builder(), expr);
for (Expression e : expr) {
buff.appendExceptFirst(", ");
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
}
}
buff.append(')'); buff.append(')');
} }
} else { } else {
......
...@@ -29,6 +29,7 @@ import org.h2.engine.Comment; ...@@ -29,6 +29,7 @@ import org.h2.engine.Comment;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Domain;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Role; import org.h2.engine.Role;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -36,7 +37,6 @@ import org.h2.engine.Setting; ...@@ -36,7 +37,6 @@ import org.h2.engine.Setting;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
import org.h2.engine.User; import org.h2.engine.User;
import org.h2.engine.UserAggregate; import org.h2.engine.UserAggregate;
import org.h2.engine.UserDataType;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.index.Cursor; import org.h2.index.Cursor;
...@@ -187,7 +187,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -187,7 +187,7 @@ public class ScriptCommand extends ScriptBase {
} }
add(schema.getCreateSQL(), false); add(schema.getCreateSQL(), false);
} }
for (UserDataType datatype : db.getAllUserDataTypes()) { for (Domain datatype : db.getAllDomains()) {
if (drop) { if (drop) {
add(datatype.getDropSQL(), false); add(datatype.getDropSQL(), false);
} }
...@@ -392,7 +392,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -392,7 +392,7 @@ public class ScriptCommand extends ScriptBase {
buff.append(table.getSQL()).append('('); buff.append(table.getSQL()).append('(');
for (Column col : columns) { for (Column col : columns) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(Parser.quoteIdentifier(col.getName())); Parser.quoteIdentifier(buff.builder(), col.getName());
} }
buff.append(") VALUES"); buff.append(") VALUES");
if (!simple) { if (!simple) {
...@@ -422,10 +422,10 @@ public class ScriptCommand extends ScriptBase { ...@@ -422,10 +422,10 @@ public class ScriptCommand extends ScriptBase {
id = writeLobStream(v); id = writeLobStream(v);
buff.append("SYSTEM_COMBINE_BLOB(").append(id).append(')'); buff.append("SYSTEM_COMBINE_BLOB(").append(id).append(')');
} else { } else {
buff.append(v.getSQL()); v.getSQL(buff.builder());
} }
} else { } else {
buff.append(v.getSQL()); v.getSQL(buff.builder());
} }
} }
buff.append(')'); buff.append(')');
...@@ -471,7 +471,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -471,7 +471,7 @@ public class ScriptCommand extends ScriptBase {
if (len <= 0) { if (len <= 0) {
break; break;
} }
buff.append(StringUtils.convertBytesToHex(bytes, len)).append("')"); StringUtils.convertBytesToHex(buff, bytes, len).append("')");
String sql = buff.toString(); String sql = buff.toString();
add(sql, true); add(sql, true);
} }
...@@ -490,7 +490,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -490,7 +490,7 @@ public class ScriptCommand extends ScriptBase {
if (len == 0) { if (len == 0) {
break; break;
} }
buff.append(StringUtils.quoteStringSQL(new String(chars, 0, len))). StringUtils.quoteStringSQL(buff, new String(chars, 0, len)).
append(", NULL)"); append(", NULL)");
String sql = buff.toString(); String sql = buff.toString();
add(sql, true); add(sql, true);
......
...@@ -33,9 +33,10 @@ public class SelectOrderBy { ...@@ -33,9 +33,10 @@ public class SelectOrderBy {
public String getSQL() { public String getSQL() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
if (expression != null) { if (expression != null) {
buff.append('=').append(expression.getSQL()); buff.append('=');
expression.getSQL(buff);
} else { } else {
buff.append(columnIndexExpr.getSQL()); columnIndexExpr.getSQL(buff);
} }
SortOrder.typeToString(buff, sortType); SortOrder.typeToString(buff, sortType);
return buff.toString(); return buff.toString();
......
...@@ -28,7 +28,6 @@ import org.h2.table.ColumnResolver; ...@@ -28,7 +28,6 @@ import org.h2.table.ColumnResolver;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.ColumnNamer; import org.h2.util.ColumnNamer;
import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -429,8 +428,8 @@ public class SelectUnion extends Query { ...@@ -429,8 +428,8 @@ public class SelectUnion extends Query {
} }
appendLimitToSQL(buff); appendLimitToSQL(buff);
if (sampleSizeExpr != null) { if (sampleSizeExpr != null) {
buff.append("\nSAMPLE_SIZE ").append( buff.append("\nSAMPLE_SIZE ");
StringUtils.unEnclose(sampleSizeExpr.getSQL())); sampleSizeExpr.getUnenclosedSQL(buff);
} }
if (isForUpdate) { if (isForUpdate) {
buff.append("\nFOR UPDATE"); buff.append("\nFOR UPDATE");
......
...@@ -56,15 +56,18 @@ public class ConstraintCheck extends Constraint { ...@@ -56,15 +56,18 @@ public class ConstraintCheck extends Constraint {
} }
buff.append(quotedName); buff.append(quotedName);
if (comment != null) { if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment)); buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
} }
buff.append(" CHECK").append(StringUtils.enclose(expr.getSQL())) buff.append(" CHECK(");
.append(" NOCHECK"); expr.getUnenclosedSQL(buff).append(") NOCHECK");
return buff.toString(); return buff.toString();
} }
private String getShortDescription() { private String getShortDescription() {
return getName() + ": " + expr.getSQL(); StringBuilder builder = new StringBuilder().append(getName()).append(": ");
expr.getSQL(builder);
return builder.toString();
} }
@Override @Override
...@@ -140,8 +143,11 @@ public class ConstraintCheck extends Constraint { ...@@ -140,8 +143,11 @@ public class ConstraintCheck extends Constraint {
// don't check at startup // don't check at startup
return; return;
} }
String sql = "SELECT 1 FROM " + filter.getTable().getSQL() + StringBuilder builder = new StringBuilder().append("SELECT 1 FROM ")
" WHERE NOT(" + expr.getSQL() + ")"; .append(filter.getTable().getSQL())
.append(" WHERE NOT(");
expr.getSQL(builder).append(')');
String sql = builder.toString();
ResultInterface r = session.prepare(sql).query(1); ResultInterface r = session.prepare(sql).query(1);
if (r.next()) { if (r.next()) {
throw DbException.get(ErrorCode.CHECK_CONSTRAINT_VIOLATED_1, getName()); throw DbException.get(ErrorCode.CHECK_CONSTRAINT_VIOLATED_1, getName());
......
...@@ -87,7 +87,8 @@ public class ConstraintReferential extends Constraint { ...@@ -87,7 +87,8 @@ public class ConstraintReferential extends Constraint {
} }
buff.append(quotedName); buff.append(quotedName);
if (comment != null) { if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment)); buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff.builder(), comment);
} }
IndexColumn[] cols = columns; IndexColumn[] cols = columns;
IndexColumn[] refCols = refColumns; IndexColumn[] refCols = refColumns;
...@@ -566,8 +567,8 @@ public class ConstraintReferential extends Constraint { ...@@ -566,8 +567,8 @@ public class ConstraintReferential extends Constraint {
buff.append("UPDATE ").append(table.getSQL()).append(" SET "); buff.append("UPDATE ").append(table.getSQL()).append(" SET ");
buff.resetCount(); buff.resetCount();
for (IndexColumn c : columns) { for (IndexColumn c : columns) {
buff.appendExceptFirst(" , "); buff.appendExceptFirst(", ");
buff.append(Parser.quoteIdentifier(c.column.getName())).append("=?"); Parser.quoteIdentifier(buff.builder(), c.column.getName()).append("=?");
} }
} }
...@@ -576,7 +577,7 @@ public class ConstraintReferential extends Constraint { ...@@ -576,7 +577,7 @@ public class ConstraintReferential extends Constraint {
buff.resetCount(); buff.resetCount();
for (IndexColumn c : columns) { for (IndexColumn c : columns) {
buff.appendExceptFirst(" AND "); buff.appendExceptFirst(" AND ");
buff.append(Parser.quoteIdentifier(c.column.getName())).append("=?"); Parser.quoteIdentifier(buff.builder(), c.column.getName()).append("=?");
} }
} }
......
...@@ -75,9 +75,9 @@ public interface DbObject { ...@@ -75,9 +75,9 @@ public interface DbObject {
int CONSTANT = 11; int CONSTANT = 11;
/** /**
* This object is a user data type (domain). * This object is a domain.
*/ */
int USER_DATATYPE = 12; int DOMAIN = 12;
/** /**
* This object is a comment. * This object is a comment.
......
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论