提交 003d1ab8 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 1cdec2b8
......@@ -249,7 +249,6 @@ Roadmap
</li><li>Support materialized views (using triggers)
</li><li>Store dates in local time zone (portability of database files)
</li><li>Ability to resize the cache array when resizing the cache
</li><li>Automatic conversion from WHERE X>10 AND X>20 to X>20
</li><li>Time based cache writing (one second after writing the log)
</li><li>Check state of H2 driver for DDLUtils: https://issues.apache.org/jira/browse/DDLUTILS-185
</li><li>Index usage for REGEXP LIKE.
......@@ -263,30 +262,24 @@ Roadmap
</li><li>Set a connection read only (Connection.setReadOnly)
</li><li>In MySQL mode, for AUTO_INCREMENT columns, don't set the primary key
</li><li>Use JDK 1.4 file locking to create the lock file (but not yet by default); writing a system property to detect concurrent access from the same VM (different classloaders).
</li><li>Read-only sessions (Connection.setReadOnly)
</li><li>Support compatibility for jdbc:hsqldb:res:
</li><li>In the MySQL and PostgreSQL, use lower case identifiers by default (DatabaseMetaData.storesLowerCaseIdentifiers = true)
</li><li>Provide a simple, lightweight O/R mapping tool
</li><li>Provide an Java SQL builder with standard and H2 syntax
</li><li>Trace: write OS, file system, JVM,... when opening the database
</li><li>Trace: write dangerous operations (set log 0,...) in every case (including when opening the database)
</li><li>Support indexes for views (probably requires materialized views)
</li><li>Linked tables that point to the same database should share the connection
</li><li>Document SET SEARCH_PATH, BEGIN, EXECUTE, parameters
</li><li>Complete Javadocs for ErrorCode messages and add to docs
</li><li>Browser: use Desktop.isDesktopSupported and browse when using JDK 1.6
</li><li>Document org.h2.samples.MixedMode
</li><li>Server: use one listener (detect if the request comes from an PG or TCP client)
</li><li>Store dates as 'local'. Existing files use GMT. Use escape syntax for compatibility.
</li><li>Support data type INTERVAL
</li><li>NATURAL JOIN: MySQL and PostgreSQL don't repeat columns when using SELECT * ...
</li><li>Optimize SELECT MIN(ID), MAX(ID), COUNT(*) FROM TEST WHERE ID BETWEEN 100 AND 200
</li><li>Support Oracle functions: TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER
</li><li>Support setQueryTimeout (using System.currentTimeMillis in a loop; not using a thread)
</li><li>Sequence: PostgreSQL compatibility (rename, create) (http://www.postgresql.org/docs/8.2/static/sql-altersequence.html)
</li><li>DISTINCT: Support large result sets by sorting on all columns (additionally) and then removing duplicates.
</li><li>Add replicating file system
</li><li>File system that writes to two file systems (for replication)
</li><li>File system that writes to two file systems (replicating file system)
</li><li>File system with a background writer thread; test if this is faster
</li><li>FTP access to a database (.csv for a table, a directory for a schema, a file for a lob, a script.sql file).
</li><li>LIMIT and OFFSET for GROUP_CONCAT
......@@ -299,12 +292,10 @@ Roadmap
</li><li>Native search: support "phrase search", wildcard search (* and ?), case-insensitive search, boolean operators, and grouping
</li><li>Improve documentation of access rights
</li><li>Support ENUM data type (see MySQL, PostgreSQL, MS SQL Server, maybe others)
</li><li>Command line option for the H2 Console and TCP configuration (.h2.server.properties and .h2.keystore)
</li><li>Automatically switch the source code to the right platform before compiling
</li><li>Command line option for the H2 Console and TCP configuration (which .h2.server.properties and .h2.keystore to use)
</li><li>Support a schema name for Java functions
</li><li>Remember the domain of a column
</li><li>Support Jackcess (MS Access databases)
</li><li>Optimize truncate and drop table (currently all pages are overwritten)
</li><li>Built-in methods to write large objects (BLOB and CLOB): FILE_WRITE('test.txt', 'Hello World')
</li><li>Change package name in version 2.0: org.h2database
</li><li>MVCC: support transactionally consistent backups using SCRIPT
......@@ -312,16 +303,14 @@ Roadmap
</li><li>Use ARRAY for fulltext search return value, at least internally in the native implementation (and as an option for the user)
</li><li>Move Maven 2 repository from hsql.sf.net to h2database.sf.net
</li><li>Java 1.5 tool: JdbcUtils.closeSilently(s1, s2,...)
</li><li>Document how to use IKVM
</li><li>Javadoc: document design patterns used
</li><li>Update Wikipedia
</li><li>Try https://hudson.dev.java.net/
</li><li>Don't create @~ of not translated
</li><li>Triggers for metadata tables; use for PostgreSQL catalog
</li><li>Does the FTP server has problems with multithreading?
</li><li>Write an article about SQLInjection (h2\src\docsrc\html\images\SQLInjection.txt)
</li><li>Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
</li><li>Send SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,...
</li><li>Send SQL Injection solution proposal to MySQL, Derby, HSQLDB,...
</li><li>Improve LOB in directories performance
</li><li>Web site design: http://www.igniterealtime.org/projects/openfire/index.jsp
</li><li>HSQLDB compatibility: Openfire server uses: CREATE SCHEMA PUBLIC AUTHORIZATION DBA;
......@@ -340,22 +329,17 @@ Roadmap
</li><li>Recovery tool: bad blocks should be converted to INSERT INTO SYSTEM_ERRORS(...), and things should go into the .trace.db file
</li><li>RECOVER=2 to backup the database, run recovery, open the database
</li><li>Recovery should work with encrypted databases
</li><li>Integrate tools in H2 Console
</li><li>Corruption: new error code, add help
</li><li>Space reuse: after init, scan all storages and free those that don't belong to a live database object
</li><li>SysProperties: change everything to H2_...
</li><li>Use FilterIn / FilterOut putStream?
</li><li>Access rights: add missing features (users should be 'owner' of objects; missing rights for sequences; dropping objects)
</li><li>Support NOCACHE table option (Oracle)
</li><li>Use ant 'get' to download dependencies
</li><li>Index usage for UPDATE ... WHERE .. IN (SELECT...)
</li><li>The RunScript tool should support interactive mode (reading from system in). Password using a second thread.
</li><li>Add regular javadocs to the homepage.
</li><li>Add regular javadocs (using the default doclet, but another css) to the homepage.
</li><li>The database should be kept open for a longer time when using the server mode.
</li><li>Javadocs: for each tool, add a copy &amp; paste sample in the class level.
</li><li>Add google site search to web page.
</li><li>Javadocs: add @author tags.
</li><li>SET LOG_SYSTEM {NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
</li><li>Fluent API for tools: Server.createTcpServer().setPort(9081).setPassword(password).start();
</li><li>MySQL compatibility: real SQL statements for SHOW TABLES, DESCRIBE TEST (then remove from Shell)
</li><li>Use a default delay of 1 second before closing a database.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -78,7 +78,7 @@
90055=Unsupported cipher {0}
90056=No default value is set for column {0}
90057=Constraint {0} not found
90058=Duplicate table or table alias {0}
90058=Commit or rollback is not allowed within a trigger
90059=Ambiguous column name {0}
90060=Unsupported file lock method {0}
90061=Exception opening port {0} (port may be in use), cause\: {1}
......
......@@ -20,6 +20,7 @@ import org.h2.result.ResultInterface;
import org.h2.result.ResultRemote;
import org.h2.util.ObjectArray;
import org.h2.value.Transfer;
import org.h2.value.Value;
/**
* Represents the client-side part of a SQL statement.
......@@ -53,7 +54,7 @@ public class CommandRemote implements CommandInterface {
private void prepare(SessionRemote session, boolean createParams) throws SQLException {
id = session.getNextId();
paramCount = 0;
boolean readParams = session.getClientVersion() >= Constants.TCP_DRIVER_VERSION_6;
boolean readParams = session.getClientVersion() >= Constants.TCP_PROTOCOL_VERSION_6;
for (int i = 0; i < transferList.size(); i++) {
try {
Transfer transfer = (Transfer) transferList.get(i);
......@@ -227,13 +228,24 @@ public class CommandRemote implements CommandInterface {
session.traceOperation("COMMAND_CLOSE", id);
transfer.writeInt(SessionRemote.COMMAND_CLOSE).writeInt(id);
} catch (IOException e) {
// TODO cluster: do we need to to handle io exception on
// close?
trace.error("close", e);
}
}
session = null;
}
int len = parameters.size();
try {
for (int i = 0; i < len; i++) {
ParameterInterface p = (ParameterInterface) parameters.get(i);
Value v = p.getParamValue();
if (v != null) {
v.close();
}
}
} catch (SQLException e) {
trace.error("close", e);
}
parameters.clear();
}
/**
......
......@@ -77,30 +77,104 @@ package org.h2.engine;
*/
public class Constants {
/**
* The build id is incremented for each public release.
*/
public static final int BUILD_ID = 72;
private static final String BUILD = "2008-04-30";
/**
* The build date is updated for each public release.
*/
private static final String BUILD_DATE = "2008-04-30";
/**
* The major version of this product.
*/
public static final int VERSION_MAJOR = 1;
/**
* The minor version of this product.
*/
public static final int VERSION_MINOR = 0;
/**
* If empty b-tree pages are allowed. This is supported for backward
* compatibility.
*/
public static final boolean ALLOW_EMPTY_BTREE_PAGES = true;
/**
* Constant meaning no literals are allowed in SQL statements.
*/
public static final int ALLOW_LITERALS_NONE = 0;
/**
* Constant meaning only numbers are allowed in SQL statements (but no
* texts).
*/
public static final int ALLOW_LITERALS_NUMBERS = 1;
/**
* Constant meaning both numbers and text is allowed in SQL statements.
*/
public static final int ALLOW_LITERALS_ALL = 2;
public static final boolean AUTO_CONVERT_LOB_TO_FILES = true;
public static final int VERSION_MAJOR = 1;
public static final int VERSION_MINOR = 0;
/**
* Automatically convert large LOB objects to files even if they have been
* set using setBytes.
*/
public static final boolean AUTO_CONVERT_LOB_TO_FILES = true;
/**
* The version of this product, consisting of major version, minor version, and build id.
*/
public static final String VERSION = VERSION_MAJOR + "." + VERSION_MINOR + "." + BUILD_ID;
/**
* The 'word size' of a file (the minimum allocation size).
*/
public static final int FILE_BLOCK_SIZE = 16;
/**
* The file header used for text files.
*/
public static final String MAGIC_FILE_HEADER_TEXT = "-- H2 0.5/T -- ".substring(0, FILE_BLOCK_SIZE - 1) + "\n";
/**
* The file header used for binary files.
*/
public static final String MAGIC_FILE_HEADER = "-- H2 0.5/B -- ".substring(0, FILE_BLOCK_SIZE - 1) + "\n";
public static final int TCP_DRIVER_VERSION_5 = 5;
public static final int TCP_DRIVER_VERSION_6 = 6;
/**
* The TCP protocol version number 5. This protocol is used by the TCP
* server and remote JDBC client.
*/
public static final int TCP_PROTOCOL_VERSION_5 = 5;
/**
* The TCP protocol version number 6. This protocol is used by the TCP
* server and remote JDBC client.
*/
public static final int TCP_PROTOCOL_VERSION_6 = 6;
/**
* The major version number of the supported JDBC API.
*/
public static final int VERSION_JDBC_MAJOR = 3;
/**
* The minor version number of the supported JDBC API.
*/
public static final int VERSION_JDBC_MINOR = 0;
/**
* Get the complete version number of this database, consisting of
* the major version, the minor version, the build id, and the build date.
*
* @return the complete version
*/
public static String getFullVersion() {
return VERSION+ " (" + BUILD + ")";
return VERSION+ " (" + BUILD_DATE + ")";
}
public static final int DEFAULT_SERVER_PORT = 9092; // this is also in the docs
......
......@@ -72,7 +72,7 @@ public class SessionRemote implements SessionInterface, DataHandler {
private byte[] fileEncryptionKey;
private Object lobSyncObject = new Object();
private String sessionId;
private int clientVersion = Constants.TCP_DRIVER_VERSION_5;
private int clientVersion = Constants.TCP_PROTOCOL_VERSION_5;
private Transfer initTransfer(ConnectionInfo ci, String db, String server) throws IOException, SQLException {
Socket socket = NetUtils.createSocket(server, Constants.DEFAULT_SERVER_PORT, ci.isSSL());
......@@ -108,14 +108,23 @@ public class SessionRemote implements SessionInterface, DataHandler {
// however Statement.cancel is supported
}
/**
* Cancel the statement with the given id.
*
* @param id the statement id
*/
public void cancelStatement(int id) {
if (clientVersion <= Constants.TCP_PROTOCOL_VERSION_5) {
// older servers don't support this feature
return;
}
for (int i = 0; i < transferList.size(); i++) {
Transfer transfer = (Transfer) transferList.get(i);
try {
Transfer trans = transfer.openNewConnection();
trans.init();
trans.writeInt(clientVersion);
if (clientVersion >= Constants.TCP_DRIVER_VERSION_6) {
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_6) {
trans.writeInt(clientVersion);
}
trans.writeString(null);
......@@ -275,13 +284,13 @@ public class SessionRemote implements SessionInterface, DataHandler {
// not required when sending TCP_DRIVER_VERSION_6
CommandInterface command = prepareCommand("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?", 1);
ParameterInterface param = (ParameterInterface) command.getParameters().get(0);
param.setValue(ValueString.get("info.BUILD_ID"));
param.setValue(ValueString.get("info.BUILD_ID"), false);
ResultInterface result = command.executeQuery(1, false);
if (result.next()) {
Value[] v = result.currentRow();
String version = v[0].getString();
if (version.compareTo("71") > 0) {
clientVersion = Constants.TCP_DRIVER_VERSION_6;
clientVersion = Constants.TCP_PROTOCOL_VERSION_6;
}
}
result.close();
......@@ -289,7 +298,7 @@ public class SessionRemote implements SessionInterface, DataHandler {
trace.error("Error trying to upgrade client version", e);
// ignore
}
if (clientVersion >= Constants.TCP_DRIVER_VERSION_6) {
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_6) {
sessionId = ByteUtils.convertBytesToString(RandomUtils.getSecureBytes(32));
synchronized (this) {
for (int i = 0; i < transferList.size(); i++) {
......
......@@ -35,6 +35,11 @@ public class Parameter extends Expression implements ParameterInterface {
return "?" + (index + 1);
}
public void setValue(Value v, boolean closeOld) {
// don't need to close the old value as temporary files are anyway removed
this.value = v;
}
public void setValue(Value v) {
this.value = v;
}
......
......@@ -19,8 +19,9 @@ public interface ParameterInterface {
* Set the value of the parameter.
*
* @param value the new value
* @param closeOld if the old value (if one is set) should be closed
*/
void setValue(Value value);
void setValue(Value value, boolean closeOld) throws SQLException;
/**
* Get the value of the parameter if set.
......
......@@ -31,8 +31,11 @@ public class ParameterRemote implements ParameterInterface {
this.index = index;
}
public void setValue(Value value) {
this.value = value;
public void setValue(Value newValue, boolean closeOld) throws SQLException {
if (closeOld && value != null) {
value.close();
}
value = newValue;
}
public Value getParamValue() {
......
......@@ -560,7 +560,7 @@ public class JdbcConnection extends TraceObject implements Connection {
}
commit();
setLockMode = prepareCommand("SET LOCK_MODE ?", setLockMode);
((ParameterInterface) setLockMode.getParameters().get(0)).setValue(ValueInt.get(lockMode));
((ParameterInterface) setLockMode.getParameters().get(0)).setValue(ValueInt.get(lockMode), false);
setLockMode.executeUpdate();
} catch (Throwable e) {
throw logAndConvert(e);
......@@ -574,7 +574,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try {
commit();
setQueryTimeout = prepareCommand("SET QUERY_TIMEOUT ?", setQueryTimeout);
((ParameterInterface) setQueryTimeout.getParameters().get(0)).setValue(ValueInt.get(seconds * 1000));
((ParameterInterface) setQueryTimeout.getParameters().get(0)).setValue(ValueInt.get(seconds * 1000), false);
setQueryTimeout.executeUpdate();
} catch (Throwable e) {
throw logAndConvert(e);
......@@ -587,7 +587,7 @@ public class JdbcConnection extends TraceObject implements Connection {
public int getQueryTimeout() throws SQLException {
try {
getQueryTimeout = prepareCommand("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?", getQueryTimeout);
((ParameterInterface) getQueryTimeout.getParameters().get(0)).setValue(ValueString.get("QUERY_TIMEOUT"));
((ParameterInterface) getQueryTimeout.getParameters().get(0)).setValue(ValueString.get("QUERY_TIMEOUT"), false);
ResultInterface result = getQueryTimeout.executeQuery(0, false);
result.next();
int queryTimeout = result.currentRow()[0].getInt();
......
......@@ -188,7 +188,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
ObjectArray parameters = command.getParameters();
for (int i = 0; i < parameters.size(); i++) {
ParameterInterface param = (ParameterInterface) parameters.get(i);
param.setValue(null);
// can only delete old temp files if they are not in the batch
param.setValue(null, batchParameters == null);
}
} catch (Throwable e) {
throw logAndConvert(e);
......@@ -1004,6 +1005,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
public void close() throws SQLException {
try {
super.close();
batchParameters = null;
if (command != null) {
command.close();
command = null;
......@@ -1035,7 +1037,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
for (int j = 0; j < set.length; j++) {
Value value = set[j];
ParameterInterface param = (ParameterInterface) parameters.get(j);
param.setValue(value);
param.setValue(value, false);
}
try {
result[i] = executeUpdateInternal();
......@@ -1222,7 +1224,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
throw Message.getInvalidValueException("" + (parameterIndex + 1), "parameterIndex");
}
ParameterInterface param = (ParameterInterface) parameters.get(parameterIndex);
param.setValue(value);
// can only delete old temp files if they are not in the batch
param.setValue(value, batchParameters == null);
}
/**
......
......@@ -69,12 +69,12 @@ public class TcpServerThread implements Runnable {
if (!server.allow(transfer.getSocket())) {
throw Message.getSQLException(ErrorCode.REMOTE_CONNECTION_NOT_ALLOWED);
}
if (clientVersion == Constants.TCP_DRIVER_VERSION_6) {
if (clientVersion == Constants.TCP_PROTOCOL_VERSION_6) {
// version 6 and newer: read max version (currently not used)
transfer.readInt();
} else if (clientVersion != Constants.TCP_DRIVER_VERSION_5) {
} else if (clientVersion != Constants.TCP_PROTOCOL_VERSION_5) {
throw Message.getSQLException(ErrorCode.DRIVER_VERSION_ERROR_2, new String[] { "" + clientVersion,
"" + Constants.TCP_DRIVER_VERSION_5 });
"" + Constants.TCP_PROTOCOL_VERSION_5 });
}
String db = transfer.readString();
String originalURL = transfer.readString();
......@@ -110,9 +110,9 @@ public class TcpServerThread implements Runnable {
session = engine.getSession(ci);
transfer.setSession(session);
transfer.writeInt(SessionRemote.STATUS_OK);
if (clientVersion >= Constants.TCP_DRIVER_VERSION_6) {
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_6) {
// version 6: reply what version to use
transfer.writeInt(Constants.TCP_DRIVER_VERSION_6);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
}
transfer.flush();
server.addConnection(id, originalURL, ci.getUserName());
......
......@@ -10,6 +10,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
......@@ -291,6 +292,16 @@ public class Shell {
}
private String readPassword() throws IOException {
try {
Method getConsole = System.class.getMethod("console", new Class[0]);
Object console = getConsole.invoke(null, null);
Method readPassword = console.getClass().getMethod("readPassword", new Class[0]);
System.out.print("Password ");
char[] password = (char[]) readPassword.invoke(console, null);
return password == null ? null : new String(password);
} catch (Throwable t) {
// ignore, use the default solution
}
class PasswordHider extends Thread {
volatile boolean stop;
public void run() {
......
......@@ -86,8 +86,12 @@ public class JdbcUtils {
*/
public static Connection getConnection(String driver, String url, String user, String password) throws SQLException {
Properties prop = new Properties();
if (user != null) {
prop.setProperty("user", user);
}
if (password != null) {
prop.setProperty("password", password);
}
return getConnection(driver, url, prop);
}
......
......@@ -160,11 +160,8 @@ java org.h2.test.TestAll timer
/*
improve javadocs
Shell / JDK 1.6: use java.io.Console
</li><li>Implement Statement.cancel for server connections
improve javadocs
upload jazoon
......@@ -215,13 +212,20 @@ Add where required // TODO: change in version 1.1
http://www.w3schools.com/sql/
History:
When setting BLOB or CLOB values larger than 65 KB using
a remote connection, temporary files were kept on the client
longer than required (until the connection was closed or the
object is garbage collected). Now they are removed as soon
as the PreparedStatement is closed, or when the value is
overwritten.
Statements can now be cancelled remotely
(when using remote connections).
The Shell tool now uses java.io.Console to read the password
when using JDK 1.6
Roadmap:
*/
if (args.length > 0) {
if ("crash".equals(args[0])) {
test.endless = true;
......
......@@ -312,7 +312,15 @@ public abstract class TestBase {
break;
}
}
error("string a: " + a + " (" + a.length() + ") b: " + b + " (" + b.length() + ")");
int al = a.length();
int bl = b.length();
if (al > 100) {
a = a.substring(0, 100);
}
if (bl > 100) {
b = b.substring(0, 100);
}
error("string a: " + a + " (" + al + ") b: " + b + " (" + bl + ")");
}
}
......
......@@ -33,6 +33,7 @@ public class TestPreparedStatement extends TestBase {
deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement");
testLobTempFiles(conn);
testExecuteErrorTwice(conn);
testTempView(conn);
testInsertFunction(conn);
......@@ -61,6 +62,48 @@ public class TestPreparedStatement extends TestBase {
conn.close();
}
private void testLobTempFiles(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, DATA CLOB)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?)");
for (int i = 0; i < 5; i++) {
prep.setInt(1, i);
if (i % 2 == 0) {
prep.setCharacterStream(2, new StringReader(getString(i)), -1);
}
prep.execute();
}
ResultSet rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
int check = 0;
for (int i = 0; i < 5; i++) {
check(rs.next());
if (i % 2 == 0) {
check = i;
}
check(getString(check), rs.getString(2));
}
checkFalse(rs.next());
stat.execute("DELETE FROM TEST");
for (int i = 0; i < 3; i++) {
prep.setInt(1, i);
prep.setCharacterStream(2, new StringReader(getString(i)), -1);
prep.addBatch();
}
prep.executeBatch();
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
for (int i = 0; i < 3; i++) {
check(rs.next());
check(getString(i), rs.getString(2));
}
checkFalse(rs.next());
stat.execute("DROP TABLE TEST");
}
private String getString(int i) {
return new String(new char[100000]).replace('\0', (char) ('0' + i));
}
private void testExecuteErrorTwice(Connection conn) throws Exception {
PreparedStatement prep = conn.prepareStatement("CREATE TABLE BAD AS SELECT A");
try {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论