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

Issue 454: Use Charset for type-safety.

上级 efdeceb1
...@@ -18,7 +18,8 @@ Change Log ...@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>Queries with both LIMIT and OFFSET could throw an IllegalArgumentException. <ul><li>Issue 454: Use Charset for type-safety.
</li><li>Queries with both LIMIT and OFFSET could throw an IllegalArgumentException.
</li><li>MVStore: larger stores (multiple GB) are now much faster. </li><li>MVStore: larger stores (multiple GB) are now much faster.
</li><li>When using local temporary tables and not dropping them manually before closing the session, </li><li>When using local temporary tables and not dropping them manually before closing the session,
and then killing the process could result in a database that couldn't be opened (except when using and then killing the process could result in a database that couldn't be opened (except when using
...@@ -26,11 +27,11 @@ Change Log ...@@ -26,11 +27,11 @@ Change Log
</li><li>Support TRUNC(timestamp) for improved Oracle compatibility. </li><li>Support TRUNC(timestamp) for improved Oracle compatibility.
</li><li>Add support for CREATE TABLE TEST (ID BIGSERIAL) for PostgreSQL compatibility. Patch from Jesse Long. </li><li>Add support for CREATE TABLE TEST (ID BIGSERIAL) for PostgreSQL compatibility. Patch from Jesse Long.
</li><li>Add new collation command SET BINARY_COLLATION UNSIGNED, helps with people testing BINARY columns in MySQL mode. </li><li>Add new collation command SET BINARY_COLLATION UNSIGNED, helps with people testing BINARY columns in MySQL mode.
</li><li>Fix issue #453, ABBA race conditions in TABLE LINK connection sharing. </li><li>Issue 453: ABBA race conditions in TABLE LINK connection sharing.
</li><li>Fix Issue 449: Postgres Serial data type should not automatically be marked as primary key </li><li>Issue 449: Postgres Serial data type should not automatically be marked as primary key
</li><li>Fix Issue 406: support "SELECT h2version()" </li><li>Issue 406: support "SELECT h2version()"
</li><li>Fix Issue 389: When there is a multi-column primary key, H2 does not seem to always pick the right index </li><li>Issue 389: When there is a multi-column primary key, H2 does not seem to always pick the right index
</li><li>Fix Issue 305: Implement SELECT ... FOR FETCH ONLY </li><li>Issue 305: Implement SELECT ... FOR FETCH ONLY
</li><li>Issue 274: Sybase/MSSQLServer compatibility - Add GETDATE and CHARINDEX system functions </li><li>Issue 274: Sybase/MSSQLServer compatibility - Add GETDATE and CHARINDEX system functions
</li><li>Issue 274: Sybase/MSSQLServer compatibility - swap parameters of CONVERT function. </li><li>Issue 274: Sybase/MSSQLServer compatibility - swap parameters of CONVERT function.
</li><li>Issue 274: Sybase/MSSQLServer compatibility - support index clause e.g. "select * from test (index table1_index)" </li><li>Issue 274: Sybase/MSSQLServer compatibility - support index clause e.g. "select * from test (index table1_index)"
......
...@@ -8,6 +8,7 @@ package org.h2.command; ...@@ -8,6 +8,7 @@ package org.h2.command;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.Collator; import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
...@@ -4733,7 +4734,7 @@ public class Parser { ...@@ -4733,7 +4734,7 @@ public class Parser {
} }
} }
if (readIf("CHARSET")) { if (readIf("CHARSET")) {
command.setCharset(readString()); command.setCharset(Charset.forName(readString()));
} }
return command; return command;
} }
...@@ -4777,7 +4778,7 @@ public class Parser { ...@@ -4777,7 +4778,7 @@ public class Parser {
} }
} }
if (readIf("CHARSET")) { if (readIf("CHARSET")) {
command.setCharset(readString()); command.setCharset(Charset.forName(readString()));
} }
} }
if (readIf("SCHEMA")) { if (readIf("SCHEMA")) {
......
...@@ -9,6 +9,7 @@ package org.h2.command.dml; ...@@ -9,6 +9,7 @@ package org.h2.command.dml;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -30,7 +31,7 @@ public class RunScriptCommand extends ScriptBase { ...@@ -30,7 +31,7 @@ public class RunScriptCommand extends ScriptBase {
*/ */
private static final char UTF8_BOM = '\uFEFF'; private static final char UTF8_BOM = '\uFEFF';
private String charset = Constants.UTF8; private Charset charset = Constants.UTF8;
public RunScriptCommand(Session session) { public RunScriptCommand(Session session) {
super(session); super(session);
...@@ -84,7 +85,7 @@ public class RunScriptCommand extends ScriptBase { ...@@ -84,7 +85,7 @@ public class RunScriptCommand extends ScriptBase {
} }
} }
public void setCharset(String charset) { public void setCharset(Charset charset) {
this.charset = charset; this.charset = charset;
} }
......
...@@ -11,6 +11,7 @@ import java.io.BufferedReader; ...@@ -11,6 +11,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -66,7 +67,7 @@ import org.h2.value.ValueString; ...@@ -66,7 +67,7 @@ import org.h2.value.ValueString;
*/ */
public class ScriptCommand extends ScriptBase { public class ScriptCommand extends ScriptBase {
private String charset = Constants.UTF8; private Charset charset = Constants.UTF8;
private Set<String> schemaNames; private Set<String> schemaNames;
private Collection<Table> tables; private Collection<Table> tables;
private boolean passwords; private boolean passwords;
...@@ -625,12 +626,8 @@ public class ScriptCommand extends ScriptBase { ...@@ -625,12 +626,8 @@ public class ScriptCommand extends ScriptBase {
private void reset() { private void reset() {
result = null; result = null;
buffer = null; buffer = null;
try {
lineSeparatorString = SysProperties.LINE_SEPARATOR; lineSeparatorString = SysProperties.LINE_SEPARATOR;
lineSeparator = lineSeparatorString.getBytes(charset); lineSeparator = lineSeparatorString.getBytes(charset);
} catch (IOException e) {
throw DbException.convertIOException(e, null);
}
} }
private boolean excludeSchema(Schema schema) { private boolean excludeSchema(Schema schema) {
...@@ -691,7 +688,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -691,7 +688,7 @@ public class ScriptCommand extends ScriptBase {
this.simple = simple; this.simple = simple;
} }
public void setCharset(String charset) { public void setCharset(Charset charset) {
this.charset = charset; this.charset = charset;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
package org.h2.engine; package org.h2.engine;
import java.nio.charset.Charset;
import java.sql.ResultSet; import java.sql.ResultSet;
/** /**
...@@ -463,7 +464,7 @@ public class Constants { ...@@ -463,7 +464,7 @@ public class Constants {
/** /**
* Name of the character encoding format. * Name of the character encoding format.
*/ */
public static final String UTF8 = "UTF8"; public static final Charset UTF8 = Charset.forName("UTF-8");
/** /**
* The maximum time in milliseconds to keep the cost of a view. * The maximum time in milliseconds to keep the cost of a view.
......
...@@ -657,10 +657,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -657,10 +657,10 @@ public class Function extends Expression implements FunctionCall {
result = ValueString.get(StringUtils.javaDecode(v0.getString())); result = ValueString.get(StringUtils.javaDecode(v0.getString()));
break; break;
case STRINGTOUTF8: case STRINGTOUTF8:
result = ValueBytes.getNoCopy(StringUtils.utf8Encode(v0.getString())); result = ValueBytes.getNoCopy(v0.getString().getBytes(Constants.UTF8));
break; break;
case UTF8TOSTRING: case UTF8TOSTRING:
result = ValueString.get(StringUtils.utf8Decode(v0.getBytesNoCopy())); result = ValueString.get(new String(v0.getBytesNoCopy(), Constants.UTF8));
break; break;
case XMLCOMMENT: case XMLCOMMENT:
result = ValueString.get(StringUtils.xmlComment(v0.getString())); result = ValueString.get(StringUtils.xmlComment(v0.getString()));
......
...@@ -650,55 +650,6 @@ public class DataUtils { ...@@ -650,55 +650,6 @@ public class DataUtils {
Constants.VERSION_MINOR + "." + Constants.BUILD_ID + "]"; Constants.VERSION_MINOR + "." + Constants.BUILD_ID + "]";
} }
/**
* Convert the text to UTF-8 format. For the Unicode characters
* 0xd800-0xdfff only one byte is returned.
*
* @param s the text
* @return the UTF-8 representation
*/
public static byte[] utf8Encode(String s) {
try {
return s.getBytes(Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw newIllegalArgumentException("UTF-8 not supported", e);
}
}
/**
* Convert a UTF-8 representation of a text to the text.
*
* @param utf8 the UTF-8 representation
* @return the text
*/
public static String utf8Decode(byte[] utf8) {
try {
return new String(utf8, Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw newIllegalArgumentException("UTF-8 not supported", e);
}
}
/**
* Convert a UTF-8 representation of a text to the text using the given
* offset and length.
*
* @param bytes the UTF-8 representation
* @param offset the offset in the bytes array
* @param length the number of bytes
* @return the text
*/
public static String utf8Decode(byte[] bytes, int offset, int length) {
try {
return new String(bytes, offset, length, Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw newIllegalArgumentException("UTF-8 not supported", e);
}
}
/** /**
* Create an array of bytes with the given size. If this is not possible * Create an array of bytes with the given size. If this is not possible
* because not enough memory is available, an OutOfMemoryError with the * because not enough memory is available, an OutOfMemoryError with the
......
...@@ -21,6 +21,7 @@ import java.util.Set; ...@@ -21,6 +21,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.h2.compress.CompressLZF; import org.h2.compress.CompressLZF;
import org.h2.compress.Compressor; import org.h2.compress.Compressor;
import org.h2.engine.Constants;
import org.h2.mvstore.cache.CacheLongKeyLIRS; import org.h2.mvstore.cache.CacheLongKeyLIRS;
import org.h2.mvstore.cache.FilePathCache; import org.h2.mvstore.cache.FilePathCache;
import org.h2.mvstore.type.StringDataType; import org.h2.mvstore.type.StringDataType;
...@@ -600,7 +601,7 @@ public class MVStore { ...@@ -600,7 +601,7 @@ public class MVStore {
fileReadCount++; fileReadCount++;
DataUtils.readFully(file, 0, buff); DataUtils.readFully(file, 0, buff);
for (int i = 0; i < 3 * BLOCK_SIZE; i += BLOCK_SIZE) { for (int i = 0; i < 3 * BLOCK_SIZE; i += BLOCK_SIZE) {
String s = DataUtils.utf8Decode(buff.array(), i, BLOCK_SIZE) String s = new String(buff.array(), i, BLOCK_SIZE, Constants.UTF8)
.trim(); .trim();
HashMap<String, String> m = DataUtils.parseMap(s); HashMap<String, String> m = DataUtils.parseMap(s);
String f = m.remove("fletcher"); String f = m.remove("fletcher");
...@@ -613,8 +614,8 @@ public class MVStore { ...@@ -613,8 +614,8 @@ public class MVStore {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
check = -1; check = -1;
} }
s = s.substring(0, s.lastIndexOf("fletcher") - 1) + " "; s = s.substring(0, s.lastIndexOf("fletcher") - 1);
byte[] bytes = DataUtils.utf8Encode(s); byte[] bytes = s.getBytes(Constants.UTF8);
int checksum = DataUtils.getFletcher32(bytes, bytes.length / 2 * 2); int checksum = DataUtils.getFletcher32(bytes, bytes.length / 2 * 2);
if (check != checksum) { if (check != checksum) {
continue; continue;
...@@ -640,10 +641,10 @@ public class MVStore { ...@@ -640,10 +641,10 @@ public class MVStore {
fileHeader.put("rootChunk", "" + rootChunkStart); fileHeader.put("rootChunk", "" + rootChunkStart);
fileHeader.put("version", "" + currentVersion); fileHeader.put("version", "" + currentVersion);
DataUtils.appendMap(buff, fileHeader); DataUtils.appendMap(buff, fileHeader);
byte[] bytes = DataUtils.utf8Encode(buff.toString() + " "); byte[] bytes = buff.toString().getBytes(Constants.UTF8);
int checksum = DataUtils.getFletcher32(bytes, bytes.length / 2 * 2); int checksum = DataUtils.getFletcher32(bytes, bytes.length / 2 * 2);
DataUtils.appendMap(buff, "fletcher", Integer.toHexString(checksum)); DataUtils.appendMap(buff, "fletcher", Integer.toHexString(checksum));
bytes = DataUtils.utf8Encode(buff.toString()); bytes = buff.toString().getBytes(Constants.UTF8);
DataUtils.checkArgument(bytes.length <= BLOCK_SIZE, DataUtils.checkArgument(bytes.length <= BLOCK_SIZE,
"File header too large: {0}", buff); "File header too large: {0}", buff);
return bytes; return bytes;
......
...@@ -946,7 +946,7 @@ public class WebApp { ...@@ -946,7 +946,7 @@ public class WebApp {
} }
final Connection conn = session.getConnection(); final Connection conn = session.getConnection();
if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) { if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
String page = StringUtils.utf8Decode(server.getFile("result.jsp")); String page = new String(server.getFile("result.jsp"), Constants.UTF8);
int idx = page.indexOf("${result}"); int idx = page.indexOf("${result}");
// the first element of the list is the header, the last the footer // the first element of the list is the header, the last the footer
list.add(0, page.substring(0, idx)); list.add(0, page.substring(0, idx));
......
...@@ -12,13 +12,15 @@ import java.net.UnknownHostException; ...@@ -12,13 +12,15 @@ import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Properties; import java.util.Properties;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.h2.engine.Constants;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils;
/** /**
* This servlet lets the H2 Console be used in a standard servlet container * This servlet lets the H2 Console be used in a standard servlet container
...@@ -130,12 +132,12 @@ public class WebServlet extends HttpServlet { ...@@ -130,12 +132,12 @@ public class WebServlet extends HttpServlet {
byte[] bytes = server.getFile(file); byte[] bytes = server.getFile(file);
if (bytes == null) { if (bytes == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND); resp.sendError(HttpServletResponse.SC_NOT_FOUND);
bytes = StringUtils.utf8Encode("File not found: " + file); bytes = ("File not found: " + file).getBytes(Constants.UTF8);
} else { } else {
if (session != null && file.endsWith(".jsp")) { if (session != null && file.endsWith(".jsp")) {
String page = StringUtils.utf8Decode(bytes); String page = new String(bytes, Constants.UTF8);
page = PageParser.parse(page, session.map); page = PageParser.parse(page, session.map);
bytes = StringUtils.utf8Encode(page); bytes = page.getBytes(Constants.UTF8);
} }
resp.setContentType(mimeType); resp.setContentType(mimeType);
if (!cache) { if (!cache) {
......
...@@ -148,10 +148,10 @@ class WebThread extends WebApp implements Runnable { ...@@ -148,10 +148,10 @@ class WebThread extends WebApp implements Runnable {
bytes = server.getFile(file); bytes = server.getFile(file);
if (bytes == null) { if (bytes == null) {
message = "HTTP/1.0 404 Not Found\r\n"; message = "HTTP/1.0 404 Not Found\r\n";
bytes = StringUtils.utf8Encode("File not found: " + file); bytes = ("File not found: " + file).getBytes(Constants.UTF8);
} else { } else {
if (session != null && file.endsWith(".jsp")) { if (session != null && file.endsWith(".jsp")) {
String page = StringUtils.utf8Decode(bytes); String page = new String(bytes, Constants.UTF8);
if (SysProperties.CONSOLE_STREAM) { if (SysProperties.CONSOLE_STREAM) {
Iterator<String> it = (Iterator<String>) session.map.remove("chunks"); Iterator<String> it = (Iterator<String>) session.map.remove("chunks");
if (it != null) { if (it != null) {
...@@ -165,7 +165,7 @@ class WebThread extends WebApp implements Runnable { ...@@ -165,7 +165,7 @@ class WebThread extends WebApp implements Runnable {
while (it.hasNext()) { while (it.hasNext()) {
String s = it.next(); String s = it.next();
s = PageParser.parse(s, session.map); s = PageParser.parse(s, session.map);
bytes = StringUtils.utf8Encode(s); bytes = s.getBytes(Constants.UTF8);
if (bytes.length == 0) { if (bytes.length == 0) {
continue; continue;
} }
...@@ -181,7 +181,7 @@ class WebThread extends WebApp implements Runnable { ...@@ -181,7 +181,7 @@ class WebThread extends WebApp implements Runnable {
} }
} }
page = PageParser.parse(page, session.map); page = PageParser.parse(page, session.map);
bytes = StringUtils.utf8Encode(page); bytes = page.getBytes(Constants.UTF8);
} }
message = "HTTP/1.1 200 OK\r\n"; message = "HTTP/1.1 200 OK\r\n";
message += "Content-Type: " + mimeType + "\r\n"; message += "Content-Type: " + mimeType + "\r\n";
......
...@@ -18,6 +18,7 @@ import java.sql.Statement; ...@@ -18,6 +18,7 @@ import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -26,7 +27,6 @@ import org.h2.tools.CompressTool; ...@@ -26,7 +27,6 @@ import org.h2.tools.CompressTool;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
...@@ -199,7 +199,7 @@ public class LobStorage { ...@@ -199,7 +199,7 @@ public class LobStorage {
if (SysProperties.LOB_IN_DATABASE) { if (SysProperties.LOB_IN_DATABASE) {
int precision; int precision;
if (type == Value.CLOB) { if (type == Value.CLOB) {
precision = StringUtils.utf8Decode(small).length(); precision = new String(small, Constants.UTF8).length();
} else { } else {
precision = small.length; precision = small.length;
} }
...@@ -834,7 +834,7 @@ public class LobStorage { ...@@ -834,7 +834,7 @@ public class LobStorage {
if (len < 0) { if (len < 0) {
buffer = null; buffer = null;
} else { } else {
buffer = StringUtils.utf8Encode(new String(charBuffer, 0, len)); buffer = new String(charBuffer, 0, len).getBytes(Constants.UTF8);
length += len; length += len;
remaining -= len; remaining -= len;
} }
......
...@@ -14,6 +14,8 @@ import java.nio.ByteBuffer; ...@@ -14,6 +14,8 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.channels.FileLock; import java.nio.channels.FileLock;
import java.util.Arrays; import java.util.Arrays;
import org.h2.engine.Constants;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.security.AES; import org.h2.security.AES;
import org.h2.security.BlockCipher; import org.h2.security.BlockCipher;
...@@ -37,7 +39,7 @@ public class FilePathCrypt extends FilePathWrapper { ...@@ -37,7 +39,7 @@ public class FilePathCrypt extends FilePathWrapper {
public FileChannel open(String mode) throws IOException { public FileChannel open(String mode) throws IOException {
String[] parsed = parse(name); String[] parsed = parse(name);
FileChannel file = FileUtils.open(parsed[1], mode); FileChannel file = FileUtils.open(parsed[1], mode);
byte[] passwordBytes = DataUtils.utf8Encode(parsed[0]); byte[] passwordBytes = parsed[0].getBytes(Constants.UTF8);
return new FileCrypt(name, passwordBytes, file); return new FileCrypt(name, passwordBytes, file);
} }
......
...@@ -11,6 +11,7 @@ import java.io.IOException; ...@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -177,20 +178,20 @@ public class RunScript extends Tool { ...@@ -177,20 +178,20 @@ public class RunScript extends Tool {
} }
private void process(Connection conn, String fileName, private void process(Connection conn, String fileName,
boolean continueOnError, String charsetName) throws SQLException, IOException { boolean continueOnError, Charset charset) throws SQLException, IOException {
InputStream in = FileUtils.newInputStream(fileName); InputStream in = FileUtils.newInputStream(fileName);
String path = FileUtils.getParent(fileName); String path = FileUtils.getParent(fileName);
try { try {
in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE); in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE);
Reader reader = new InputStreamReader(in, charsetName); Reader reader = new InputStreamReader(in, charset);
process(conn, continueOnError, path, reader, charsetName); process(conn, continueOnError, path, reader, charset);
} finally { } finally {
IOUtils.closeSilently(in); IOUtils.closeSilently(in);
} }
} }
private void process(Connection conn, boolean continueOnError, private void process(Connection conn, boolean continueOnError,
String path, Reader reader, String charsetName) throws SQLException, IOException { String path, Reader reader, Charset charset) throws SQLException, IOException {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ScriptReader r = new ScriptReader(reader); ScriptReader r = new ScriptReader(reader);
while (true) { while (true) {
...@@ -208,7 +209,7 @@ public class RunScript extends Tool { ...@@ -208,7 +209,7 @@ public class RunScript extends Tool {
if (!FileUtils.isAbsolute(sql)) { if (!FileUtils.isAbsolute(sql)) {
sql = path + SysProperties.FILE_SEPARATOR + sql; sql = path + SysProperties.FILE_SEPARATOR + sql;
} }
process(conn, sql, continueOnError, charsetName); process(conn, sql, continueOnError, charset);
} else { } else {
try { try {
if (showResults && !trim.startsWith("-->")) { if (showResults && !trim.startsWith("-->")) {
...@@ -286,12 +287,12 @@ public class RunScript extends Tool { ...@@ -286,12 +287,12 @@ public class RunScript extends Tool {
* @param user the user name * @param user the user name
* @param password the password * @param password the password
* @param fileName the script file * @param fileName the script file
* @param charsetName the character set name or null for UTF-8 * @param charset the character set or null for UTF-8
* @param continueOnError if execution should be continued if an error occurs * @param continueOnError if execution should be continued if an error occurs
*/ */
public static void execute(String url, String user, String password, public static void execute(String url, String user, String password,
String fileName, String charsetName, boolean continueOnError) throws SQLException { String fileName, Charset charset, boolean continueOnError) throws SQLException {
new RunScript().process(url, user, password, fileName, charsetName, continueOnError); new RunScript().process(url, user, password, fileName, charset, continueOnError);
} }
/** /**
...@@ -301,20 +302,20 @@ public class RunScript extends Tool { ...@@ -301,20 +302,20 @@ public class RunScript extends Tool {
* @param user the user name * @param user the user name
* @param password the password * @param password the password
* @param fileName the script file * @param fileName the script file
* @param charsetName the character set name or null for UTF-8 * @param charset the character set or null for UTF-8
* @param continueOnError if execution should be continued if an error occurs * @param continueOnError if execution should be continued if an error occurs
*/ */
void process(String url, String user, String password, void process(String url, String user, String password,
String fileName, String charsetName, String fileName, Charset charset,
boolean continueOnError) throws SQLException { boolean continueOnError) throws SQLException {
try { try {
org.h2.Driver.load(); org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url, user, password); Connection conn = DriverManager.getConnection(url, user, password);
if (charsetName == null) { if (charset == null) {
charsetName = Constants.UTF8; charset = Constants.UTF8;
} }
try { try {
process(conn, fileName, continueOnError, charsetName); process(conn, fileName, continueOnError, charset);
} finally { } finally {
conn.close(); conn.close();
} }
......
...@@ -18,7 +18,6 @@ import java.io.InputStreamReader; ...@@ -18,7 +18,6 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
...@@ -379,13 +378,7 @@ public class IOUtils { ...@@ -379,13 +378,7 @@ public class IOUtils {
* @return the reader * @return the reader
*/ */
public static Reader getBufferedReader(InputStream in) { public static Reader getBufferedReader(InputStream in) {
try {
//
return in == null ? null : new BufferedReader(new InputStreamReader(in, Constants.UTF8)); return in == null ? null : new BufferedReader(new InputStreamReader(in, Constants.UTF8));
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
} }
/** /**
...@@ -398,13 +391,8 @@ public class IOUtils { ...@@ -398,13 +391,8 @@ public class IOUtils {
* @return the reader * @return the reader
*/ */
public static Reader getReader(InputStream in) { public static Reader getReader(InputStream in) {
try {
// InputStreamReader may read some more bytes // InputStreamReader may read some more bytes
return in == null ? null : new BufferedReader(new InputStreamReader(in, Constants.UTF8)); return in == null ? null : new BufferedReader(new InputStreamReader(in, Constants.UTF8));
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
} }
/** /**
...@@ -415,23 +403,7 @@ public class IOUtils { ...@@ -415,23 +403,7 @@ public class IOUtils {
* @return the writer * @return the writer
*/ */
public static Writer getBufferedWriter(OutputStream out) { public static Writer getBufferedWriter(OutputStream out) {
try {
return out == null ? null : new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8)); return out == null ? null : new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8));
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
}
/**
* Create a reader to read from a string.
* If the string is null, this method returns null.
*
* @param s the string or null
* @return the reader
*/
public static Reader getReaderFromString(String s) {
return s == null ? null : new StringReader(s);
} }
/** /**
...@@ -475,7 +447,7 @@ public class IOUtils { ...@@ -475,7 +447,7 @@ public class IOUtils {
if (s == null) { if (s == null) {
return null; return null;
} }
return new ByteArrayInputStream(StringUtils.utf8Encode(s)); return new ByteArrayInputStream(s.getBytes(Constants.UTF8));
} }
/** /**
......
...@@ -325,55 +325,6 @@ public class StringUtils { ...@@ -325,55 +325,6 @@ public class StringUtils {
return "\"" + javaEncode(s) + "\""; return "\"" + javaEncode(s) + "\"";
} }
/**
* Convert the text to UTF-8 format. For the Unicode characters
* 0xd800-0xdfff only one byte is returned.
*
* @param s the text
* @return the UTF-8 representation
*/
public static byte[] utf8Encode(String s) {
try {
return s.getBytes(Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
}
/**
* Convert a UTF-8 representation of a text to the text.
*
* @param utf8 the UTF-8 representation
* @return the text
*/
public static String utf8Decode(byte[] utf8) {
try {
return new String(utf8, Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
}
/**
* Convert a UTF-8 representation of a text to the text using the given
* offset and length.
*
* @param bytes the UTF-8 representation
* @param offset the offset in the bytes array
* @param length the number of bytes
* @return the text
*/
public static String utf8Decode(byte[] bytes, int offset, int length) {
try {
return new String(bytes, offset, length, Constants.UTF8);
} catch (Exception e) {
// UnsupportedEncodingException
throw DbException.convert(e);
}
}
/** /**
* Convert a string array to the Java source code that represents this * Convert a string array to the Java source code that represents this
* array. Null will be converted to 'null'. * array. Null will be converted to 'null'.
...@@ -479,7 +430,7 @@ public class StringUtils { ...@@ -479,7 +430,7 @@ public class StringUtils {
buff[j++] = (byte) ch; buff[j++] = (byte) ch;
} }
} }
String s = utf8Decode(buff, 0, j); String s = new String(buff, 0, j, Constants.UTF8);
return s; return s;
} }
......
...@@ -22,8 +22,10 @@ import java.sql.Types; ...@@ -22,8 +22,10 @@ import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.SessionInterface; import org.h2.engine.SessionInterface;
import org.h2.jdbc.JdbcBlob; import org.h2.jdbc.JdbcBlob;
import org.h2.jdbc.JdbcClob; import org.h2.jdbc.JdbcClob;
...@@ -32,7 +34,6 @@ import org.h2.message.DbException; ...@@ -32,7 +34,6 @@ import org.h2.message.DbException;
import org.h2.store.LobStorage; import org.h2.store.LobStorage;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
/** /**
...@@ -539,7 +540,7 @@ public class DataType { ...@@ -539,7 +540,7 @@ public class DataType {
} }
case Value.CLOB: { case Value.CLOB: {
if (session == null) { if (session == null) {
v = LobStorage.createSmallLob(Value.CLOB, StringUtils.utf8Encode(rs.getString(columnIndex))); v = LobStorage.createSmallLob(Value.CLOB, rs.getString(columnIndex).getBytes(Constants.UTF8));
} else { } else {
Reader in = rs.getCharacterStream(columnIndex); Reader in = rs.getCharacterStream(columnIndex);
if (in == null) { if (in == null) {
......
...@@ -9,6 +9,7 @@ package org.h2.value; ...@@ -9,6 +9,7 @@ package org.h2.value;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Date; import java.sql.Date;
...@@ -18,14 +19,15 @@ import java.sql.SQLException; ...@@ -18,14 +19,15 @@ import java.sql.SQLException;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.LobStorage; import org.h2.store.LobStorage;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.Utils; import org.h2.util.Utils;
...@@ -426,7 +428,7 @@ public abstract class Value { ...@@ -426,7 +428,7 @@ public abstract class Value {
} }
public Reader getReader() { public Reader getReader() {
return IOUtils.getReaderFromString(getString()); return new StringReader(getString());
} }
/** /**
...@@ -832,7 +834,7 @@ public abstract class Value { ...@@ -832,7 +834,7 @@ public abstract class Value {
case FLOAT: case FLOAT:
return ValueFloat.get(Float.parseFloat(s.trim())); return ValueFloat.get(Float.parseFloat(s.trim()));
case CLOB: case CLOB:
return LobStorage.createSmallLob(CLOB, StringUtils.utf8Encode(s)); return LobStorage.createSmallLob(CLOB, s.getBytes(Constants.UTF8));
case BLOB: case BLOB:
return LobStorage.createSmallLob(BLOB, StringUtils.convertHexToBytes(s.trim())); return LobStorage.createSmallLob(BLOB, StringUtils.convertHexToBytes(s.trim()));
case ARRAY: case ARRAY:
......
...@@ -144,7 +144,7 @@ public class ValueLob extends Value { ...@@ -144,7 +144,7 @@ public class ValueLob extends Value {
try { try {
if (handler == null) { if (handler == null) {
String s = IOUtils.readStringAndClose(in, (int) length); String s = IOUtils.readStringAndClose(in, (int) length);
return createSmallLob(Value.CLOB, StringUtils.utf8Encode(s)); return createSmallLob(Value.CLOB, s.getBytes(Constants.UTF8));
} }
boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null; boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null;
long remaining = Long.MAX_VALUE; long remaining = Long.MAX_VALUE;
...@@ -163,7 +163,7 @@ public class ValueLob extends Value { ...@@ -163,7 +163,7 @@ public class ValueLob extends Value {
len = len < 0 ? 0 : len; len = len < 0 ? 0 : len;
} }
if (len <= handler.getMaxLengthInplaceLob()) { if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = StringUtils.utf8Encode(new String(buff, 0, len)); byte[] small = new String(buff, 0, len).getBytes(Constants.UTF8);
return ValueLob.createSmallLob(Value.CLOB, small); return ValueLob.createSmallLob(Value.CLOB, small);
} }
ValueLob lob = new ValueLob(Value.CLOB, null); ValueLob lob = new ValueLob(Value.CLOB, null);
...@@ -204,7 +204,7 @@ public class ValueLob extends Value { ...@@ -204,7 +204,7 @@ public class ValueLob extends Value {
try { try {
while (true) { while (true) {
precision += len; precision += len;
byte[] b = StringUtils.utf8Encode(new String(buff, 0, len)); byte[] b = new String(buff, 0, len).getBytes(Constants.UTF8);
out.write(b, 0, b.length); out.write(b, 0, b.length);
remaining -= len; remaining -= len;
if (remaining <= 0) { if (remaining <= 0) {
...@@ -546,7 +546,7 @@ public class ValueLob extends Value { ...@@ -546,7 +546,7 @@ public class ValueLob extends Value {
try { try {
if (type == Value.CLOB) { if (type == Value.CLOB) {
if (small != null) { if (small != null) {
return StringUtils.utf8Decode(small); return new String(small, Constants.UTF8);
} }
return IOUtils.readStringAndClose(getReader(), len); return IOUtils.readStringAndClose(getReader(), len);
} }
......
...@@ -196,7 +196,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo ...@@ -196,7 +196,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
try { try {
if (type == Value.CLOB) { if (type == Value.CLOB) {
if (small != null) { if (small != null) {
return StringUtils.utf8Decode(small); return new String(small, Constants.UTF8);
} }
return IOUtils.readStringAndClose(getReader(), len); return IOUtils.readStringAndClose(getReader(), len);
} }
...@@ -407,7 +407,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo ...@@ -407,7 +407,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
len = len < 0 ? 0 : len; len = len < 0 ? 0 : len;
} }
if (len <= handler.getMaxLengthInplaceLob()) { if (len <= handler.getMaxLengthInplaceLob()) {
byte[] small = StringUtils.utf8Encode(new String(buff, 0, len)); byte[] small = new String(buff, 0, len).getBytes(Constants.UTF8);
return ValueLobDb.createSmallLob(Value.CLOB, small, len); return ValueLobDb.createSmallLob(Value.CLOB, small, len);
} }
ValueLobDb lob = new ValueLobDb(Value.CLOB, null, 0); ValueLobDb lob = new ValueLobDb(Value.CLOB, null, 0);
...@@ -461,7 +461,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo ...@@ -461,7 +461,7 @@ public class ValueLobDb extends Value implements Value.ValueClob, Value.ValueBlo
try { try {
while (true) { while (true) {
precision += len; precision += len;
byte[] b = StringUtils.utf8Encode(new String(buff, 0, len)); byte[] b = new String(buff, 0, len).getBytes(Constants.UTF8);
out.write(b, 0, b.length); out.write(b, 0, b.length);
remaining -= len; remaining -= len;
if (remaining <= 0) { if (remaining <= 0) {
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
*/ */
package org.h2.test.store; package org.h2.test.store;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
...@@ -36,6 +39,7 @@ public class TestMVTableEngine extends TestBase { ...@@ -36,6 +39,7 @@ public class TestMVTableEngine extends TestBase {
public void test() throws Exception { public void test() throws Exception {
//testSpeed(); //testSpeed();
// testBlob();
testExclusiveLock(); testExclusiveLock();
testEncryption(); testEncryption();
testReadOnly(); testReadOnly();
...@@ -125,6 +129,35 @@ int tes; ...@@ -125,6 +129,35 @@ int tes;
System.out.println((System.currentTimeMillis() - time) + " " + dbName + " after"); System.out.println((System.currentTimeMillis() - time) + " " + dbName + " after");
} }
private void testBlob() throws SQLException, IOException {
FileUtils.deleteRecursive(getBaseDir(), true);
String dbName = "mvstore" +
";DEFAULT_TABLE_ENGINE=org.h2.mvstore.db.MVTableEngine";
Connection conn;
Statement stat;
conn = getConnection(dbName);
stat = conn.createStatement();
stat.execute("create table test(id int, name blob)");
PreparedStatement prep = conn.prepareStatement("insert into test values(1, ?)");
prep.setBinaryStream(1, new ByteArrayInputStream(new byte[1000]));
prep.execute();
conn.close();
conn = getConnection(dbName);
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from test");
while (rs.next()) {
InputStream in = rs.getBinaryStream(2);
int len = 0;
while (in.read() >= 0) {
len++;
}
assertEquals(10000, len);
}
conn.close();
FileUtils.deleteRecursive(getBaseDir(), true);
}
private void testEncryption() throws Exception { private void testEncryption() throws Exception {
FileUtils.deleteRecursive(getBaseDir(), true); FileUtils.deleteRecursive(getBaseDir(), true);
String dbName = "mvstore" + String dbName = "mvstore" +
......
...@@ -17,6 +17,7 @@ import java.io.RandomAccessFile; ...@@ -17,6 +17,7 @@ import java.io.RandomAccessFile;
import java.net.URL; import java.net.URL;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import org.h2.engine.Constants;
import org.h2.tools.RunScript; import org.h2.tools.RunScript;
/** /**
...@@ -89,7 +90,7 @@ public class Migrate { ...@@ -89,7 +90,7 @@ public class Migrate {
"-password", password "-password", password
}); });
file.renameTo(new File(file.getAbsoluteFile() + ".backup")); file.renameTo(new File(file.getAbsoluteFile() + ".backup"));
RunScript.execute(url, user, password, TEMP_SCRIPT, "UTF-8", true); RunScript.execute(url, user, password, TEMP_SCRIPT, Constants.UTF8, true);
new File(TEMP_SCRIPT).delete(); new File(TEMP_SCRIPT).delete();
} }
......
...@@ -12,10 +12,9 @@ import java.io.IOException; ...@@ -12,10 +12,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer; import java.io.Writer;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.message.DbException;
/** /**
* The reader input stream wraps a reader and convert the character to the UTF-8 * The reader input stream wraps a reader and convert the character to the UTF-8
...@@ -35,11 +34,7 @@ public class ReaderInputStream extends InputStream { ...@@ -35,11 +34,7 @@ public class ReaderInputStream extends InputStream {
chars = new char[Constants.IO_BUFFER_SIZE]; chars = new char[Constants.IO_BUFFER_SIZE];
this.reader = reader; this.reader = reader;
out = new ByteArrayOutputStream(Constants.IO_BUFFER_SIZE); out = new ByteArrayOutputStream(Constants.IO_BUFFER_SIZE);
try {
writer = new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8)); writer = new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8));
} catch (UnsupportedEncodingException e) {
throw DbException.convert(e);
}
} }
private void fillBuffer() throws IOException { private void fillBuffer() throws IOException {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论