提交 4f409b1c authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 ab1e8d62
...@@ -322,6 +322,10 @@ public class Session implements SessionInterface { ...@@ -322,6 +322,10 @@ public class Session implements SessionInterface {
} }
public void unlockReadLocks() { public void unlockReadLocks() {
if (database.isMultiVersion()) {
// MVCC: keep shared locks (insert / update / delete)
return;
}
for (int i = 0; i < locks.size(); i++) { for (int i = 0; i < locks.size(); i++) {
Table t = (Table) locks.get(i); Table t = (Table) locks.get(i);
if (!t.isLockedExclusively()) { if (!t.isLockedExclusively()) {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package org.h2.engine; package org.h2.engine;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -21,7 +20,6 @@ import org.h2.message.TraceSystem; ...@@ -21,7 +20,6 @@ import org.h2.message.TraceSystem;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils; import org.h2.util.NetUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.RandomUtils; import org.h2.util.RandomUtils;
...@@ -61,19 +59,7 @@ public class SessionRemote implements SessionInterface, DataHandler { ...@@ -61,19 +59,7 @@ public class SessionRemote implements SessionInterface, DataHandler {
private Object lobSyncObject = new Object(); private Object lobSyncObject = new Object();
private Transfer initTransfer(ConnectionInfo ci, String db, String server) throws IOException, SQLException { private Transfer initTransfer(ConnectionInfo ci, String db, String server) throws IOException, SQLException {
int port = Constants.DEFAULT_SERVER_PORT; Socket socket = NetUtils.createSocket(server, Constants.DEFAULT_SERVER_PORT, ci.isSSL());
// IPv6: RFC 2732 format is '[a:b:c:d:e:f:g:h]' or
// '[a:b:c:d:e:f:g:h]:port'
// RFC 2396 format is 'a.b.c.d' or 'a.b.c.d:port' or 'hostname' or
// 'hostname:port'
int startIndex = server.startsWith("[") ? server.indexOf(']') : 0;
int idx = server.indexOf(':', startIndex);
if (idx >= 0) {
port = MathUtils.decodeInt(server.substring(idx + 1));
server = server.substring(0, idx);
}
InetAddress address = InetAddress.getByName(server);
Socket socket = NetUtils.createSocket(address, port, ci.isSSL());
Transfer trans = new Transfer(this); Transfer trans = new Transfer(this);
trans.setSocket(socket); trans.setSocket(socket);
trans.init(); trans.init();
......
...@@ -1128,8 +1128,13 @@ public class Function extends Expression implements FunctionCall { ...@@ -1128,8 +1128,13 @@ public class Function extends Expression implements FunctionCall {
} }
private static int locate(String search, String s, int start) { private static int locate(String search, String s, int start) {
int i = (start < 0) ? 0 : start - 1; if (start < 0) {
return s.indexOf(search, i) + 1; int i = s.length() + start;
return s.lastIndexOf(search, i) + 1;
} else {
int i = (start == 0) ? 0 : start - 1;
return s.indexOf(search, i) + 1;
}
} }
private static String right(String s, int count) { private static String right(String s, int count) {
......
...@@ -121,6 +121,9 @@ public class Operation extends Expression { ...@@ -121,6 +121,9 @@ public class Operation extends Expression {
switch (opType) { switch (opType) {
case NEGATE: case NEGATE:
dataType = left.getType(); dataType = left.getType();
if (dataType == Value.UNKNOWN) {
dataType = Value.DECIMAL;
}
break; break;
case CONCAT: case CONCAT:
right = right.optimize(session); right = right.optimize(session);
...@@ -136,7 +139,7 @@ public class Operation extends Expression { ...@@ -136,7 +139,7 @@ public class Operation extends Expression {
right = right.optimize(session); right = right.optimize(session);
int l = left.getType(); int l = left.getType();
int r = right.getType(); int r = right.getType();
if (l == Value.NULL && r == Value.NULL) { if ((l == Value.NULL && r == Value.NULL) || (l == Value.UNKNOWN && r == Value.UNKNOWN)) {
// example: (? + ?) - the most safe data type is probably // example: (? + ?) - the most safe data type is probably
// decimal // decimal
dataType = Value.DECIMAL; dataType = Value.DECIMAL;
......
...@@ -2108,6 +2108,7 @@ INSTR(string, searchString, [, startInt]): int ...@@ -2108,6 +2108,7 @@ INSTR(string, searchString, [, startInt]): int
"," ","
Returns the location of a search string in a string (s). Returns the location of a search string in a string (s).
If a start position is used, the characters before it are ignored. If a start position is used, the characters before it are ignored.
If position is negative, the rightmost location is returned.
0 is returned if the search string is not found. 0 is returned if the search string is not found.
"," ","
INSTR(EMAIL,'@') INSTR(EMAIL,'@')
...@@ -2154,6 +2155,7 @@ LOCATE(searchString, string [, startInt]): int ...@@ -2154,6 +2155,7 @@ LOCATE(searchString, string [, startInt]): int
"," ","
Returns the location of a search string in a string (s). Returns the location of a search string in a string (s).
If a start position is used, the characters before it are ignored. If a start position is used, the characters before it are ignored.
If position is negative, the rightmost location is returned.
0 is returned if the search string is not found. 0 is returned if the search string is not found.
"," ","
LOCATE('.', NAME) LOCATE('.', NAME)
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package org.h2.server.pg; package org.h2.server.pg;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.sql.Connection; import java.sql.Connection;
...@@ -159,7 +158,7 @@ public class PgServer implements Service { ...@@ -159,7 +158,7 @@ public class PgServer implements Service {
return false; return false;
} }
try { try {
Socket s = NetUtils.createSocket(InetAddress.getLocalHost(), serverSocket.getLocalPort(), false); Socket s = NetUtils.createLoopbackSocket(serverSocket.getLocalPort(), false);
s.close(); s.close();
return true; return true;
} catch (Exception e) { } catch (Exception e) {
......
...@@ -34,11 +34,11 @@ public class FileLister { ...@@ -34,11 +34,11 @@ public class FileLister {
* @throws SQLException * @throws SQLException
*/ */
public static ArrayList getDatabaseFiles(String dir, String db, boolean all) throws SQLException { public static ArrayList getDatabaseFiles(String dir, String db, boolean all) throws SQLException {
dir = FileUtils.normalize(dir);
ArrayList files = new ArrayList();
if (dir == null || dir.equals("")) { if (dir == null || dir.equals("")) {
dir = "."; dir = ".";
} }
dir = FileUtils.normalize(dir);
ArrayList files = new ArrayList();
String start = db == null ? null : FileUtils.normalize(dir + "/" + db); String start = db == null ? null : FileUtils.normalize(dir + "/" + db);
String[] list = FileUtils.listFiles(dir); String[] list = FileUtils.listFiles(dir);
for (int i = 0; list != null && i < list.length; i++) { for (int i = 0; list != null && i < list.length; i++) {
......
...@@ -8,12 +8,12 @@ import java.io.IOException; ...@@ -8,12 +8,12 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
public class FileInputStream extends InputStream { public class FileObjectInputStream extends InputStream {
private FileObject file; private FileObject file;
private byte[] buffer = new byte[1]; private byte[] buffer = new byte[1];
FileInputStream(FileObject file) { FileObjectInputStream(FileObject file) {
this.file = file; this.file = file;
} }
......
...@@ -7,12 +7,12 @@ package org.h2.store.fs; ...@@ -7,12 +7,12 @@ package org.h2.store.fs;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class FileOutputStream extends OutputStream { public class FileObjectOutputStream extends OutputStream {
private FileObject file; private FileObject file;
private byte[] buffer = new byte[1]; private byte[] buffer = new byte[1];
FileOutputStream(FileObject file, boolean append) throws IOException { FileObjectOutputStream(FileObject file, boolean append) throws IOException {
this.file = file; this.file = file;
if (append) { if (append) {
file.seek(file.length()); file.seek(file.length());
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store.fs;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class FileObjectZip implements FileObject {
private ZipFile file;
private ZipEntry entry;
private long pos;
private InputStream in;
private long inPos;
private long length;
public FileObjectZip(ZipFile file, ZipEntry entry) {
this.file = file;
this.entry = entry;
length = entry.getSize();
}
public void close() throws IOException {
}
public long getFilePointer() throws IOException {
return pos;
}
public long length() throws IOException {
return length;
}
public void readFully(byte[] b, int off, int len) throws IOException {
if (inPos > pos) {
if (in != null) {
in.close();
}
in = null;
}
if (in == null) {
in = file.getInputStream(entry);
inPos = 0;
}
if (inPos < pos) {
in.skip(pos - inPos);
inPos = pos;
}
in.read(b, off, len);
pos += len;
inPos += len;
}
public void seek(long pos) throws IOException {
this.pos = pos;
}
public void setLength(long newLength) throws IOException {
throw new IOException("File is read-only");
}
public void sync() throws IOException {
}
public void write(byte[] b, int off, int len) throws IOException {
throw new IOException("File is read-only");
}
}
...@@ -15,18 +15,21 @@ public abstract class FileSystem { ...@@ -15,18 +15,21 @@ public abstract class FileSystem {
public static final String MEMORY_PREFIX = "memFS:"; public static final String MEMORY_PREFIX = "memFS:";
public static final String MEMORY_PREFIX_LZF = "memLZF:"; public static final String MEMORY_PREFIX_LZF = "memLZF:";
public static final String DB_PREFIX = "jdbc:"; public static final String DB_PREFIX = "jdbc:";
public static final String ZIP_PREFIX = "zip:";
public static FileSystem getInstance(String fileName) { public static FileSystem getInstance(String fileName) {
if (isInMemory(fileName)) { if (isInMemory(fileName)) {
return FileSystemMemory.getInstance(); return FileSystemMemory.getInstance();
} else if (fileName.startsWith(DB_PREFIX)) { } else if (fileName.startsWith(DB_PREFIX)) {
return FileSystemDatabase.getInstance(fileName); return FileSystemDatabase.getInstance(fileName);
} else if (fileName.startsWith(ZIP_PREFIX)) {
return FileSystemZip.getInstance();
} }
return FileSystemDisk.getInstance(); return FileSystemDisk.getInstance();
} }
private static boolean isInMemory(String fileName) { private static boolean isInMemory(String fileName) {
return fileName != null && fileName.startsWith(MEMORY_PREFIX) || fileName.startsWith(MEMORY_PREFIX_LZF); return fileName != null && (fileName.startsWith(MEMORY_PREFIX) || fileName.startsWith(MEMORY_PREFIX_LZF));
} }
public abstract long length(String fileName); public abstract long length(String fileName);
......
...@@ -357,7 +357,7 @@ public class FileSystemDatabase extends FileSystem { ...@@ -357,7 +357,7 @@ public class FileSystemDatabase extends FileSystem {
} }
public InputStream openFileInputStream(String fileName) throws IOException { public InputStream openFileInputStream(String fileName) throws IOException {
return new FileInputStream(openFileObject(fileName, "r")); return new FileObjectInputStream(openFileObject(fileName, "r"));
} }
public FileObject openFileObject(String fileName, String mode) throws IOException { public FileObject openFileObject(String fileName, String mode) throws IOException {
...@@ -382,7 +382,7 @@ public class FileSystemDatabase extends FileSystem { ...@@ -382,7 +382,7 @@ public class FileSystemDatabase extends FileSystem {
public OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException { public OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException {
try { try {
return new FileOutputStream(openFileObject(fileName, "rw"), append); return new FileObjectOutputStream(openFileObject(fileName, "rw"), append);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, fileName); throw Message.convertIOException(e, fileName);
} }
......
...@@ -148,14 +148,14 @@ public class FileSystemMemory extends FileSystem { ...@@ -148,14 +148,14 @@ public class FileSystemMemory extends FileSystem {
public OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException { public OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException {
try { try {
return new FileOutputStream(getMemoryFile(fileName), append); return new FileObjectOutputStream(getMemoryFile(fileName), append);
} catch (IOException e) { } catch (IOException e) {
throw Message.convertIOException(e, fileName); throw Message.convertIOException(e, fileName);
} }
} }
public InputStream openFileInputStream(String fileName) throws IOException { public InputStream openFileInputStream(String fileName) throws IOException {
return new FileInputStream(getMemoryFile(fileName)); return new FileObjectInputStream(getMemoryFile(fileName));
} }
public FileObject openFileObject(String fileName, String mode) throws IOException { public FileObject openFileObject(String fileName, String mode) throws IOException {
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store.fs;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.h2.message.Message;
public class FileSystemZip extends FileSystem {
private static final FileSystemZip INSTANCE = new FileSystemZip();
private FileSystemZip() {
}
public static FileSystemZip getInstance() {
return INSTANCE;
}
public boolean canWrite(String fileName) {
return false;
}
public void copy(String original, String copy) throws SQLException {
throw Message.getUnsupportedException();
}
public void createDirs(String fileName) throws SQLException {
// ignore
}
public boolean createNewFile(String fileName) throws SQLException {
throw Message.getUnsupportedException();
}
public String createTempFile(String prefix, String suffix, boolean deleteOnExit, boolean inTempDir) throws IOException {
throw new IOException("File system is read-only");
}
public void delete(String fileName) throws SQLException {
throw Message.getUnsupportedException();
}
public void deleteRecursive(String fileName) throws SQLException {
throw Message.getUnsupportedException();
}
public boolean exists(String fileName) {
try {
String entryName = getEntryName(fileName);
if (entryName.length() == 0) {
return true;
}
ZipFile file = openZipFile(fileName);
return file.getEntry(entryName) != null;
} catch (IOException e) {
return false;
}
}
public boolean fileStartsWith(String fileName, String prefix) {
return fileName.startsWith(prefix);
}
public String getAbsolutePath(String fileName) {
return fileName;
}
public String getFileName(String name) throws SQLException {
name = getEntryName(name);
if (name.endsWith("/")) {
name = name.substring(0, name.length() - 1);
}
int idx = name.lastIndexOf('/');
if (idx >= 0) {
name = name.substring(idx + 1);
}
return name;
}
public long getLastModified(String fileName) {
return 0;
}
public String getParent(String fileName) {
int idx = fileName.lastIndexOf('/');
if (idx > 0) {
fileName = fileName.substring(0, idx);
}
return fileName;
}
public boolean isAbsolute(String fileName) {
return true;
}
public boolean isDirectory(String fileName) {
try {
String entryName = getEntryName(fileName);
if (entryName.length() == 0) {
return true;
}
ZipFile file = openZipFile(fileName);
Enumeration en = file.entries();
while (en.hasMoreElements()) {
ZipEntry entry = (ZipEntry) en.nextElement();
String n = entry.getName();
if (n.equals(entryName)) {
return entry.isDirectory();
} else if (n.startsWith(entryName)) {
if (n.length() == entryName.length() + 1) {
if (n.equals(entryName + "/")) {
return true;
}
}
}
}
return false;
} catch (IOException e) {
return false;
}
}
public boolean isReadOnly(String fileName) {
return true;
}
public long length(String fileName) {
try {
ZipFile file = openZipFile(fileName);
ZipEntry entry = file.getEntry(getEntryName(fileName));
return entry == null ? 0 : entry.getSize();
} catch (IOException e) {
return 0;
}
}
public String[] listFiles(String path) throws SQLException {
try {
if (!path.endsWith("/")) {
path += "/";
}
ZipFile file = openZipFile(path);
String dirName = getEntryName(path);
String prefix = path.substring(0, path.length() - dirName.length());
Enumeration en = file.entries();
ArrayList list = new ArrayList();
while (en.hasMoreElements()) {
ZipEntry entry = (ZipEntry) en.nextElement();
String name = entry.getName();
if (!name.startsWith(dirName)) {
continue;
}
if (name.length() <= dirName.length()) {
continue;
}
int idx = name.indexOf('/', dirName.length());
if (idx < 0 || idx >= name.length() - 1) {
list.add(prefix + name);
}
}
String[] result = new String[list.size()];
list.toArray(result);
return result;
} catch (IOException e) {
throw Message.convertIOException(e, "listFiles " + path);
}
}
public String normalize(String fileName) throws SQLException {
return fileName;
}
public InputStream openFileInputStream(String fileName) throws IOException {
FileObject file = openFileObject(fileName, "r");
return new FileObjectInputStream(file);
}
public FileObject openFileObject(String fileName, String mode) throws IOException {
ZipFile file = openZipFile(translateFileName(fileName));
ZipEntry entry = file.getEntry(getEntryName(fileName));
return new FileObjectZip(file, entry);
}
public OutputStream openFileOutputStream(String fileName, boolean append) throws SQLException {
throw Message.getUnsupportedException();
}
public void rename(String oldName, String newName) throws SQLException {
throw Message.getUnsupportedException();
}
public boolean tryDelete(String fileName) {
return false;
}
private String translateFileName(String fileName) {
if (fileName.startsWith(FileSystem.ZIP_PREFIX)) {
fileName = fileName.substring(FileSystem.ZIP_PREFIX.length());
}
int idx = fileName.indexOf('!');
if (idx >= 0) {
fileName = fileName.substring(0, idx);
}
return fileName;
}
private String getEntryName(String fileName) {
int idx = fileName.indexOf('!');
if (idx <= 0) {
fileName = "";
} else {
fileName = fileName.substring(idx + 1);
}
if (fileName.startsWith("/")) {
fileName = fileName.substring(1);
}
return fileName;
}
private ZipFile openZipFile(String fileName) throws IOException {
fileName = translateFileName(fileName);
return new ZipFile(fileName);
}
}
...@@ -316,11 +316,17 @@ public class TableData extends Table implements RecordReader { ...@@ -316,11 +316,17 @@ public class TableData extends Table implements RecordReader {
if (lockExclusive == session) { if (lockExclusive == session) {
return; return;
} }
if (!force && database.isMultiVersion()) {
// MVCC: update, delete, and insert use a shared lock
// but select doesn't lock
if (exclusive) {
exclusive = false;
} else {
return;
}
}
if (exclusive) { if (exclusive) {
if (lockExclusive == null) { if (lockExclusive == null) {
if (!force && database.isMultiVersion()) {
return;
}
if (lockShared.isEmpty()) { if (lockShared.isEmpty()) {
traceLock(session, exclusive, "added for"); traceLock(session, exclusive, "added for");
session.addLock(this); session.addLock(this);
...@@ -333,11 +339,8 @@ public class TableData extends Table implements RecordReader { ...@@ -333,11 +339,8 @@ public class TableData extends Table implements RecordReader {
} }
} }
} else { } else {
if (!force && database.isMultiVersion()) {
return;
}
if (lockExclusive == null) { if (lockExclusive == null) {
if (lockMode == Constants.LOCK_MODE_READ_COMMITTED && !SysProperties.multiThreadedKernel) { if (lockMode == Constants.LOCK_MODE_READ_COMMITTED && !SysProperties.multiThreadedKernel && !database.isMultiVersion()) {
// READ_COMMITTED read locks are acquired but they // READ_COMMITTED read locks are acquired but they
// are released immediately // are released immediately
// when allowing only one thread, no read locks are // when allowing only one thread, no read locks are
......
...@@ -17,17 +17,40 @@ import org.h2.security.SecureSocketFactory; ...@@ -17,17 +17,40 @@ import org.h2.security.SecureSocketFactory;
public class NetUtils { public class NetUtils {
public static Socket createLoopbackSocket(int port, boolean ssl) throws IOException, SQLException { public static Socket createLoopbackSocket(int port, boolean ssl) throws SQLException {
InetAddress address = InetAddress.getByName("127.0.0.1"); return createSocket("127.0.0.1", port, ssl);
return createSocket(address, port, ssl);
} }
public static Socket createSocket(InetAddress address, int port, boolean ssl) throws IOException, SQLException { public static Socket createSocket(String server, int defaultPort, boolean ssl) throws SQLException {
if (ssl) { int port = defaultPort;
SecureSocketFactory f = SecureSocketFactory.getInstance(); // IPv6: RFC 2732 format is '[a:b:c:d:e:f:g:h]' or
return f.createSocket(address, port); // '[a:b:c:d:e:f:g:h]:port'
} else { // RFC 2396 format is 'a.b.c.d' or 'a.b.c.d:port' or 'hostname' or
return new Socket(address, port); // 'hostname:port'
int startIndex = server.startsWith("[") ? server.indexOf(']') : 0;
int idx = server.indexOf(':', startIndex);
if (idx >= 0) {
port = MathUtils.decodeInt(server.substring(idx + 1));
server = server.substring(0, idx);
}
try {
InetAddress address = InetAddress.getByName(server);
return createSocket(address, port, ssl);
} catch (IOException e) {
throw Message.convert(e);
}
}
public static Socket createSocket(InetAddress address, int port, boolean ssl) throws SQLException {
try {
if (ssl) {
SecureSocketFactory f = SecureSocketFactory.getInstance();
return f.createSocket(address, port);
} else {
return new Socket(address, port);
}
} catch (IOException e) {
throw Message.convert(e);
} }
} }
......
...@@ -142,7 +142,17 @@ java org.h2.test.TestAll timer ...@@ -142,7 +142,17 @@ java org.h2.test.TestAll timer
/* /*
TODO history:
Math operations using unknown data types (for example -? and ?+?) are now interpreted as decimal.
INSTR, LOCATE: backward searching is not supported by using a negative start position
TODO doc:
MVCC still locks the table exclusively when adding or removing columns and when dropping the table.
Also, a shared lock is still added when inserting or removing rows.
replicating file system replicating file system
background thread writing file system (all writes)
test DbStarter test DbStarter
...@@ -519,8 +529,8 @@ write tests using the PostgreSQL JDBC driver ...@@ -519,8 +529,8 @@ write tests using the PostgreSQL JDBC driver
System.out.println("test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc); System.out.println("test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc);
beforeTest(); beforeTest();
// int testMvcc; // int testMvcc;
// mvcc = true; // mvcc = true;
// db // db
new TestScriptSimple().runTest(this); new TestScriptSimple().runTest(this);
......
...@@ -132,6 +132,13 @@ public class TestPreparedStatement extends TestBase { ...@@ -132,6 +132,13 @@ public class TestPreparedStatement extends TestBase {
} catch (SQLException e) { } catch (SQLException e) {
// expected // expected
} }
PreparedStatement prep = conn.prepareStatement("SELECT -?");
prep.setInt(1, 1);
prep.execute();
prep = conn.prepareStatement("SELECT ?-?");
prep.setInt(1, 1);
prep.setInt(2, 2);
prep.execute();
} }
private void testCancelReuse(Connection conn) throws Exception { private void testCancelReuse(Connection conn) throws Exception {
......
...@@ -47,6 +47,19 @@ public class TestMVCC extends TestBase { ...@@ -47,6 +47,19 @@ public class TestMVCC extends TestBase {
c1.setAutoCommit(false); c1.setAutoCommit(false);
c2.setAutoCommit(false); c2.setAutoCommit(false);
s1.execute("create table test(id int primary key)");
s1.execute("insert into test values(1)");
try {
s2.execute("drop table test");
error("Unexpected success");
} catch (SQLException e) {
// lock timeout expected
checkNotGeneralException(e);
}
c1.rollback();
s2.execute("drop table test");
c2.rollback();
s1.execute("create table test(id int primary key, name varchar(255))"); s1.execute("create table test(id int primary key, name varchar(255))");
s2.execute("insert into test values(4, 'Hello')"); s2.execute("insert into test values(4, 'Hello')");
c2.rollback(); c2.rollback();
...@@ -176,6 +189,7 @@ public class TestMVCC extends TestBase { ...@@ -176,6 +189,7 @@ public class TestMVCC extends TestBase {
s1.execute("SELECT * FROM TEST ORDER BY ID"); s1.execute("SELECT * FROM TEST ORDER BY ID");
s2.execute("SELECT * FROM TEST ORDER BY ID"); s2.execute("SELECT * FROM TEST ORDER BY ID");
} }
c2.rollback();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
...@@ -215,6 +229,7 @@ public class TestMVCC extends TestBase { ...@@ -215,6 +229,7 @@ public class TestMVCC extends TestBase {
s1.execute("SELECT * FROM TEST ORDER BY ID"); s1.execute("SELECT * FROM TEST ORDER BY ID");
s2.execute("SELECT * FROM TEST ORDER BY ID"); s2.execute("SELECT * FROM TEST ORDER BY ID");
} }
c2.rollback();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
......
select instr('asgisj','s', -1) from dual;
> 5;
CREATE TABLE TEST(ID INT); CREATE TABLE TEST(ID INT);
INSERT INTO TEST VALUES(1), (2), (3); INSERT INTO TEST VALUES(1), (2), (3);
create index idx_desc on test(id desc); create index idx_desc on test(id desc);
......
package org.h2.test.unit;
import java.sql.SQLException;
import org.h2.test.TestBase;
import org.h2.tools.Server;
public class TestFtp extends TestBase {
public void test() throws Exception {
test(baseDir);
}
private void test(String dir) throws SQLException {
Server server = Server.createFtpServer(new String[]{"-ftpDir", dir}).start();
server.stop();
}
}
package org.h2.tools.ftp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.sql.SQLException;
import java.util.ArrayList;
import org.h2.engine.Constants;
import org.h2.util.NetUtils;
public class FtpClient {
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
private int code;
private String message;
public static FtpClient open(String url) throws SQLException, IOException {
FtpClient client = new FtpClient();
client.connect(url);
return client;
}
private FtpClient() {
}
private void connect(String url) throws SQLException, IOException {
socket = NetUtils.createSocket(url, 21, false);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
reader = new BufferedReader(new InputStreamReader(in));
writer = new PrintWriter(new OutputStreamWriter(out, Constants.UTF8));
readCode(220);
}
private void readLine() throws IOException {
message = reader.readLine();
int idx = message.indexOf(' ');
if (idx < 0) {
code = 0;
} else {
code = Integer.parseInt(message.substring(0, idx));
}
}
private void readCode(int expected) throws IOException {
readLine();
if (code != expected) {
throw new IOException("Expected: " + expected + " got: " + message);
}
}
private void send(String command) throws IOException {
writer.println(command);
writer.flush();
}
public void sendUser(String userName) throws IOException {
send("USER " + userName);
readCode(331);
}
public void sendQuit() throws IOException {
send("QUIT");
readCode(221);
}
public void sendPassword(String password) throws IOException {
send("PASS " + password);
readCode(230);
}
public void sendChangeWorkingDirectory(String dir) throws IOException {
send("CWD " + dir);
readCode(250);
}
public void sendChangeDirectoryUp() throws IOException {
send("CDUP");
readCode(250);
}
public void sendDelete(String fileName) throws IOException {
send("DELE " + fileName);
readCode(250);
}
public void sendMakeDirectory(String dir) throws IOException {
}
public void sendMode(String dir) throws IOException {
}
public void sendModifiedTime(String dir) throws IOException {
}
public void sendNameList(String dir) throws IOException {
}
public void sendRenameFrom(String dir) throws IOException {
}
public String[] sendList(String dir) throws IOException {
send("LIST " + dir);
readCode(250);
ArrayList list = new ArrayList();
String[] result = new String[list.size()];
list.toArray(result);
return result;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论