diff --git a/h2/src/docsrc/html/changelog.html b/h2/src/docsrc/html/changelog.html
index 5a908d027b..1159bb8242 100644
--- a/h2/src/docsrc/html/changelog.html
+++ b/h2/src/docsrc/html/changelog.html
@@ -21,6 +21,10 @@
Change Log
Next Version (unreleased)
+- Issue #3376: Data cannot be read after insert of clob data > MAX_LENGTH_INPLACE_LOB with data change delta table
+
+- PR #3377: Add -webExternalNames setting and fix WebServer.getConnection()
+
- PR #3367: Use faster checks of dimension systems of geometries
- PR #3369: Added v2 changes in migration docs
diff --git a/h2/src/main/org/h2/command/Parser.java b/h2/src/main/org/h2/command/Parser.java
index 1584396c0e..6aa8a51d37 100644
--- a/h2/src/main/org/h2/command/Parser.java
+++ b/h2/src/main/org/h2/command/Parser.java
@@ -1989,6 +1989,10 @@ private Table readDataChangeDeltaTable(String resultOptionName, int backupIndex)
throw getSyntaxError();
}
read(CLOSE_PAREN);
+ if (currentSelect != null) {
+ // Lobs aren't copied, so use it for more safety
+ currentSelect.setNeverLazy(true);
+ }
return new DataChangeDeltaTable(getSchemaWithDefault(), session, statement, resultOption);
}
diff --git a/h2/src/main/org/h2/result/LocalResult.java b/h2/src/main/org/h2/result/LocalResult.java
index b35721f3a3..fa630ed495 100644
--- a/h2/src/main/org/h2/result/LocalResult.java
+++ b/h2/src/main/org/h2/result/LocalResult.java
@@ -62,6 +62,7 @@ public static LocalResult forTable(SessionLocal session, Table table) {
private int visibleColumnCount;
private int resultColumnCount;
private Expression[] expressions;
+ private boolean forDataChangeDeltaTable;
private long rowId, rowCount;
private ArrayList rows;
private SortOrder sort;
@@ -140,6 +141,13 @@ public void setMaxMemoryRows(int maxValue) {
this.maxMemoryRows = maxValue;
}
+ /**
+ * Sets value collection mode for data change delta tables.
+ */
+ public void setForDataChangeDeltaTable() {
+ forDataChangeDeltaTable = true;
+ }
+
/**
* Create a shallow copy of the result set. The data and a temporary table
* (if there is any) is not copied.
@@ -343,10 +351,14 @@ private void cloneLobs(Value[] values) {
for (int i = 0; i < values.length; i++) {
Value v = values[i];
if (v instanceof ValueLob) {
- ValueLob v2 = ((ValueLob) v).copyToResult();
- if (v2 != v) {
+ if (forDataChangeDeltaTable) {
containsLobs = true;
- values[i] = session.addTemporaryLob(v2);
+ } else {
+ ValueLob v2 = ((ValueLob) v).copyToResult();
+ if (v2 != v) {
+ containsLobs = true;
+ values[i] = session.addTemporaryLob(v2);
+ }
}
}
}
diff --git a/h2/src/main/org/h2/server/web/WebThread.java b/h2/src/main/org/h2/server/web/WebThread.java
index 471fda78d8..8180c15853 100644
--- a/h2/src/main/org/h2/server/web/WebThread.java
+++ b/h2/src/main/org/h2/server/web/WebThread.java
@@ -184,7 +184,7 @@ private boolean process() throws IOException {
message += "Transfer-Encoding: chunked\r\n";
message += "\r\n";
trace(message);
- output.write(message.getBytes());
+ output.write(message.getBytes(StandardCharsets.ISO_8859_1));
while (it.hasNext()) {
String s = it.next();
s = PageParser.parse(s, session.map);
@@ -192,13 +192,14 @@ private boolean process() throws IOException {
if (bytes.length == 0) {
continue;
}
- output.write(Integer.toHexString(bytes.length).getBytes());
- output.write("\r\n".getBytes());
+ output.write(Integer.toHexString(bytes.length).getBytes(StandardCharsets.ISO_8859_1));
+ output.write(RN);
output.write(bytes);
- output.write("\r\n".getBytes());
+ output.write(RN);
output.flush();
}
- output.write("0\r\n\r\n".getBytes());
+ output.write('0');
+ output.write(RNRN);
output.flush();
return keepAlive;
}
@@ -217,7 +218,7 @@ private boolean process() throws IOException {
message += "Content-Length: " + bytes.length + "\r\n";
message += "\r\n";
trace(message);
- output.write(message.getBytes());
+ output.write(message.getBytes(StandardCharsets.ISO_8859_1));
output.write(bytes);
output.flush();
return keepAlive;
@@ -252,6 +253,9 @@ private boolean checkHost(String host) throws IOException {
if (index >= 0) {
host = host.substring(0, index);
}
+ if (host.isEmpty()) {
+ return false;
+ }
if (host.equals(server.getHost()) || host.equals("localhost") || host.equals("127.0.0.1")) {
return true;
}
diff --git a/h2/src/main/org/h2/store/fs/encrypt/FileEncrypt.java b/h2/src/main/org/h2/store/fs/encrypt/FileEncrypt.java
index fea13dae0c..38bc227b04 100644
--- a/h2/src/main/org/h2/store/fs/encrypt/FileEncrypt.java
+++ b/h2/src/main/org/h2/store/fs/encrypt/FileEncrypt.java
@@ -10,6 +10,7 @@
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.h2.security.AES;
import org.h2.security.SHA256;
@@ -37,7 +38,7 @@ public class FileEncrypt extends FileBaseDefault {
*/
static final int HEADER_LENGTH = BLOCK_SIZE;
- private static final byte[] HEADER = "H2encrypt\n".getBytes();
+ private static final byte[] HEADER = "H2encrypt\n".getBytes(StandardCharsets.ISO_8859_1);
private static final int SALT_POS = HEADER.length;
/**
diff --git a/h2/src/main/org/h2/table/DataChangeDeltaTable.java b/h2/src/main/org/h2/table/DataChangeDeltaTable.java
index 7c483cccdd..e9046a3130 100644
--- a/h2/src/main/org/h2/table/DataChangeDeltaTable.java
+++ b/h2/src/main/org/h2/table/DataChangeDeltaTable.java
@@ -116,6 +116,7 @@ public ResultInterface getResult(SessionLocal session) {
statement.prepare();
int columnCount = expressions.length;
LocalResult result = new LocalResult(session, expressions, columnCount, columnCount);
+ result.setForDataChangeDeltaTable();
statement.update(result, resultOption);
return result;
}
diff --git a/h2/src/test/org/h2/test/scripts/other/data-change-delta-table.sql b/h2/src/test/org/h2/test/scripts/other/data-change-delta-table.sql
index dc854a2f11..f8040387ee 100644
--- a/h2/src/test/org/h2/test/scripts/other/data-change-delta-table.sql
+++ b/h2/src/test/org/h2/test/scripts/other/data-change-delta-table.sql
@@ -387,3 +387,31 @@ SELECT * FROM NEW TABLE (MERGE INTO TEST_VIEW TEST USING
DROP TABLE TEST CASCADE;
> ok
+
+CREATE TABLE TEST(ID BIGINT, DATA CHARACTER LARGE OBJECT);
+> ok
+
+INSERT INTO TEST VALUES (1, REPEAT('A', 1000));
+> update count: 1
+
+SELECT ID FROM FINAL TABLE (INSERT INTO TEST VALUES (2, REPEAT('B', 1000)));
+>> 2
+
+SELECT ID, SUBSTRING(DATA FROM 1 FOR 2) FROM TEST;
+> ID SUBSTRING(DATA FROM 1 FOR 2)
+> -- ----------------------------
+> 1 AA
+> 2 BB
+> rows: 2
+
+@reconnect
+
+SELECT ID, SUBSTRING(DATA FROM 1 FOR 2) FROM TEST;
+> ID SUBSTRING(DATA FROM 1 FOR 2)
+> -- ----------------------------
+> 1 AA
+> 2 BB
+> rows: 2
+
+DROP TABLE TEST;
+> ok