提交 8da94fcb authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 2e63b5ff
...@@ -155,6 +155,8 @@ ...@@ -155,6 +155,8 @@
90132=Aggregate {0} not found 90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open 90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied 90134=Access to the class {0} is denied
90135=The database is open in exclusive mode; can not open additional connections
90136=Unsupported outer join condition\: {0}
HY000=General error\: {0} HY000=General error\: {0}
HY004=Unknown data type\: {0} HY004=Unknown data type\: {0}
HYC00=Feature not supported HYC00=Feature not supported
......
...@@ -2397,7 +2397,10 @@ public class Parser { ...@@ -2397,7 +2397,10 @@ public class Parser {
if (types[i] == CHAR_SPECIAL_2) { if (types[i] == CHAR_SPECIAL_2) {
i++; i++;
} }
// fall through currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken);
parseIndex = i;
return;
case CHAR_SPECIAL_1: case CHAR_SPECIAL_1:
currentToken = sqlCommand.substring(start, i); currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken); currentTokenType = getSpecialType(currentToken);
...@@ -2600,7 +2603,6 @@ public class Parser { ...@@ -2600,7 +2603,6 @@ public class Parser {
command[i] = ' '; command[i] = ' ';
command[i + 1] = ' '; command[i + 1] = ' ';
i++; i++;
break;
} else if (command[i + 1] == '/') { } else if (command[i + 1] == '/') {
// single line comment // single line comment
changed = true; changed = true;
...@@ -2613,9 +2615,10 @@ public class Parser { ...@@ -2613,9 +2615,10 @@ public class Parser {
command[i++] = ' '; command[i++] = ' ';
checkRunOver(i, len, startLoop); checkRunOver(i, len, startLoop);
} }
break; } else {
type = CHAR_SPECIAL_1;
} }
// fall through break;
case '-': case '-':
if (command[i + 1] == '-') { if (command[i + 1] == '-') {
// single line comment // single line comment
...@@ -2629,9 +2632,10 @@ public class Parser { ...@@ -2629,9 +2632,10 @@ public class Parser {
command[i++] = ' '; command[i++] = ' ';
checkRunOver(i, len, startLoop); checkRunOver(i, len, startLoop);
} }
break; } else {
type = CHAR_SPECIAL_1;
} }
// fall through break;
case '(': case '(':
case ')': case ')':
case '{': case '{':
......
...@@ -549,6 +549,9 @@ public class Select extends Query { ...@@ -549,6 +549,9 @@ public class Select extends Query {
Expression on = f.getJoinCondition(); Expression on = f.getJoinCondition();
if (on != null) { if (on != null) {
if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) { if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) {
if (f.isJoinOuter()) {
throw Message.getSQLException(ErrorCode.UNSUPPORTED_OUTER_JOIN_CONDITION_1, on.getSQL());
}
f.removeJoinCondition(); f.removeJoinCondition();
// need to check that all added are bound to a table // need to check that all added are bound to a table
on = on.optimize(session); on = on.optimize(session);
......
...@@ -316,6 +316,7 @@ public class ErrorCode { ...@@ -316,6 +316,7 @@ public class ErrorCode {
public static final int CANNOT_CHANGE_SETTING_WHEN_OPEN_1 = 90133; public static final int CANNOT_CHANGE_SETTING_WHEN_OPEN_1 = 90133;
public static final int ACCESS_DENIED_TO_CLASS_1 = 90134; public static final int ACCESS_DENIED_TO_CLASS_1 = 90134;
public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135; public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135;
public static final int UNSUPPORTED_OUTER_JOIN_CONDITION_1 = 90136;
/** /**
* INTERNAL * INTERNAL
......
...@@ -127,6 +127,7 @@ public class ScanIndex extends BaseIndex { ...@@ -127,6 +127,7 @@ public class ScanIndex extends BaseIndex {
row.setPos(key); row.setPos(key);
rows.set(key, row); rows.set(key, row);
} }
row.setDeleted(false);
} }
if (database.isMultiVersion()) { if (database.isMultiVersion()) {
if (delta == null) { if (delta == null) {
......
...@@ -155,7 +155,8 @@ ...@@ -155,7 +155,8 @@
90132=Aggregat-Funktion {0} nicht gefunden 90132=Aggregat-Funktion {0} nicht gefunden
90133=Kann das Setting {0} nicht \u00E4ndern wenn die Datenbank bereits ge\u00F6ffnet ist 90133=Kann das Setting {0} nicht \u00E4ndern wenn die Datenbank bereits ge\u00F6ffnet ist
90134=Der Zugriff auf die Klasse {0} ist nicht erlaubt 90134=Der Zugriff auf die Klasse {0} ist nicht erlaubt
90135=Die Datenbank befindet sich im Exclusiv Modus; es können keine zusätzlichen Verbindungen geöffnet werden 90135=Die Datenbank befindet sich im Exclusiv Modus; es k\u00F6nnen keine zus\u00E4tzlichen Verbindungen ge\u00F6ffnet werden
90136=Diese Outer Join Bedingung wird nicht unterst\u00FCtzt\: {0}
HY000=Allgemeiner Fehler\: {0} HY000=Allgemeiner Fehler\: {0}
HY004=Unbekannter Datentyp\: {0} HY004=Unbekannter Datentyp\: {0}
HYC00=Dieses Feature wird unterst\u00FCtzt HYC00=Dieses Feature wird unterst\u00FCtzt
......
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
90133=Cannot change the setting {0} when the database is already open 90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied 90134=Access to the class {0} is denied
90135=The database is open in exclusive mode; can not open additional connections 90135=The database is open in exclusive mode; can not open additional connections
90136=Unsupported outer join condition\: {0}
HY000=General error\: {0} HY000=General error\: {0}
HY004=Unknown data type\: {0} HY004=Unknown data type\: {0}
HYC00=Feature not supported HYC00=Feature not supported
......
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open 90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied 90134=\#Access to the class {0} is denied
90135=\#The database is open in exclusive mode; can not open additional connections 90135=\#The database is open in exclusive mode; can not open additional connections
90136=\#Unsupported outer join condition\: {0}
HY000=\u4E00\u822C\u30A8\u30E9\u30FC\: {0} HY000=\u4E00\u822C\u30A8\u30E9\u30FC\: {0}
HY004=\u4E0D\u660E\u306A\u30C7\u30FC\u30BF\u578B\: {0} HY004=\u4E0D\u660E\u306A\u30C7\u30FC\u30BF\u578B\: {0}
HYC00=\u6A5F\u80FD\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093 HYC00=\u6A5F\u80FD\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093
......
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open 90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied 90134=\#Access to the class {0} is denied
90135=\#The database is open in exclusive mode; can not open additional connections 90135=\#The database is open in exclusive mode; can not open additional connections
90136=\#Unsupported outer join condition\: {0}
HY000=Blad ogolny\: {0} HY000=Blad ogolny\: {0}
HY004=Nieznany typ danyche\: {0} HY004=Nieznany typ danyche\: {0}
HYC00=Cecha nie jest wspierana HYC00=Cecha nie jest wspierana
......
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
90133=\#Cannot change the setting {0} when the database is already open 90133=\#Cannot change the setting {0} when the database is already open
90134=\#Access to the class {0} is denied 90134=\#Access to the class {0} is denied
90135=\#The database is open in exclusive mode; can not open additional connections 90135=\#The database is open in exclusive mode; can not open additional connections
90136=\#Unsupported outer join condition\: {0}
HY000=Erro geral\: {0} HY000=Erro geral\: {0}
HY004=Tipo de dados desconhecido\: {0} HY004=Tipo de dados desconhecido\: {0}
HYC00=Recurso n\u00E3o suportado HYC00=Recurso n\u00E3o suportado
......
...@@ -91,6 +91,12 @@ public class FtpControl extends Thread { ...@@ -91,6 +91,12 @@ public class FtpControl extends Thread {
return; return;
} }
server.log(">" + command); server.log(">" + command);
FtpEventListener listener = server.getEventListener();
FtpEvent event = null;
if (listener != null) {
event = new FtpEvent(this, command, param);
listener.beforeCommand(event);
}
replied = false; replied = false;
if (connected) { if (connected) {
processConnected(command, param); processConnected(command, param);
...@@ -126,8 +132,12 @@ public class FtpControl extends Thread { ...@@ -126,8 +132,12 @@ public class FtpControl extends Thread {
} }
} }
if (!replied) { if (!replied) {
listener.onUnsupportedCommand(event);
reply(506, "Invalid command"); reply(506, "Invalid command");
} }
if (listener != null) {
listener.afterCommand(event);
}
} }
private void processConnected(String command, String param) throws SQLException, IOException { private void processConnected(String command, String param) throws SQLException, 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.server.ftp;
/**
* Describes an FTP event. This class is used by the FtpEventListener.
*/
public class FtpEvent {
private final FtpControl control;
private final String command;
private final String param;
FtpEvent(FtpControl control, String command, String param) {
this.control = control;
this.command = command;
this.param = param;
}
/**
* Get the FTP command. Example: RETR
*
* @return the command
*/
public String getCommand() {
return command;
}
/**
* Get the FTP control object.
*
* @return the control object
*/
public FtpControl getControl() {
return control;
}
/**
* Get the parameter of the FTP command (if any).
*
* @return the parameter
*/
public String getParam() {
return param;
}
}
/*
* 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.server.ftp;
/**
* Event listener for the FTP Server.
*/
public interface FtpEventListener {
/**
* Called before the given command is processed.
*
* @param event the event
*/
void beforeCommand(FtpEvent event);
/**
* Called after the command has been processed.
*
* @param event the event
*/
void afterCommand(FtpEvent event);
/**
* Called when an unsupported command is processed.
* This method is called after beforeCommand.
*
* @param event the event
*/
void onUnsupportedCommand(FtpEvent event);
}
...@@ -56,6 +56,8 @@ public class FtpServer implements Service { ...@@ -56,6 +56,8 @@ public class FtpServer implements Service {
private boolean allowTask; private boolean allowTask;
static final String TASK_SUFFIX = ".task"; static final String TASK_SUFFIX = ".task";
private FtpEventListener eventListener;
public void listen() { public void listen() {
try { try {
while (serverSocket != null) { while (serverSocket != null) {
...@@ -311,8 +313,31 @@ public class FtpServer implements Service { ...@@ -311,8 +313,31 @@ public class FtpServer implements Service {
p.destroy(); p.destroy();
} }
/**
* Get the file system used by this FTP server.
*
* @return the file system
*/
public FileSystem getFileSystem() { public FileSystem getFileSystem() {
return fs; return fs;
} }
/**
* Set the event listener. Only one listener can be registered.
*
* @param eventListener the new listener, or null to de-register
*/
public void setEventListener(FtpEventListener eventListener) {
this.eventListener = eventListener;
}
/**
* Get the registered event listener.
*
* @return the event listener, or null if non is registered
*/
public FtpEventListener getEventListener() {
return eventListener;
}
} }
...@@ -336,8 +336,6 @@ public class DiskFile implements CacheWriter { ...@@ -336,8 +336,6 @@ public class DiskFile implements CacheWriter {
Record rec = (Record) list.get(i); Record rec = (Record) list.get(i);
writeBack(rec); writeBack(rec);
} }
// TODO flush performance: maybe it would be faster to write records in
// the same loop
for (int i = 0; i < fileBlockCount; i++) { for (int i = 0; i < fileBlockCount; i++) {
i = deleted.nextSetBit(i); i = deleted.nextSetBit(i);
if (i < 0) { if (i < 0) {
...@@ -351,32 +349,33 @@ public class DiskFile implements CacheWriter { ...@@ -351,32 +349,33 @@ public class DiskFile implements CacheWriter {
} }
} }
public void flushNew() throws SQLException { // this implementation accesses the file in a linear way
int todoTest; // public void flushNew() throws SQLException {
synchronized (database) { // int todoTest;
database.checkPowerOff(); // synchronized (database) {
ObjectArray list = cache.getAllChanged(); // database.checkPowerOff();
CacheObject.sort(list); // ObjectArray list = cache.getAllChanged();
int deletePos = deleted.nextSetBit(0); // CacheObject.sort(list);
int writeIndex = 0; // int deletePos = deleted.nextSetBit(0);
Record writeRecord = null; // int writeIndex = 0;
while (true) { // Record writeRecord = null;
if (writeRecord == null && writeIndex < list.size()) { // while (true) {
writeRecord = (Record) list.get(writeIndex++); // if (writeRecord == null && writeIndex < list.size()) {
} // writeRecord = (Record) list.get(writeIndex++);
if (writeRecord != null && (deletePos < 0 || writeRecord.getPos() < deletePos)) { // }
writeBack(writeRecord); // if (writeRecord != null && (deletePos < 0 || writeRecord.getPos() < deletePos)) {
writeRecord = null; // writeBack(writeRecord);
} else if (deletePos < fileBlockCount && deletePos >= 0) { // writeRecord = null;
writeDirectDeleted(deletePos, 1); // } else if (deletePos < fileBlockCount && deletePos >= 0) {
deleted.clear(deletePos); // writeDirectDeleted(deletePos, 1);
deletePos = deleted.nextSetBit(deletePos); // deleted.clear(deletePos);
} else { // deletePos = deleted.nextSetBit(deletePos);
break; // } else {
} // break;
} // }
} // }
} // }
// }
public void close() throws SQLException { public void close() throws SQLException {
synchronized (database) { synchronized (database) {
......
...@@ -31,7 +31,6 @@ public class FileLister { ...@@ -31,7 +31,6 @@ public class FileLister {
* files are included. If false, only data, index and log files * files are included. If false, only data, index and log files
* are returned * are returned
* @return the list of files * @return the list of files
* @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 {
if (dir == null || dir.equals("")) { if (dir == null || dir.equals("")) {
......
...@@ -347,15 +347,6 @@ public class Csv implements SimpleRowSource { ...@@ -347,15 +347,6 @@ public class Csv implements SimpleRowSource {
continue; continue;
} else if (ch == fieldSeparatorRead) { } else if (ch == fieldSeparatorRead) {
break; break;
} else if (ch == commentLineStart) {
while (true) {
ch = readChar();
if (ch < 0 || ch == '\r' || ch == '\n') {
break;
}
}
endOfLine = true;
break;
} else if (ch == fieldDelimiter) { } else if (ch == fieldDelimiter) {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
boolean containsEscape = false; boolean containsEscape = false;
...@@ -406,6 +397,15 @@ public class Csv implements SimpleRowSource { ...@@ -406,6 +397,15 @@ public class Csv implements SimpleRowSource {
} }
} }
break; break;
} else if (ch == commentLineStart) {
while (true) {
ch = readChar();
if (ch < 0 || ch == '\r' || ch == '\n') {
break;
}
}
endOfLine = true;
break;
} else { } else {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
buff.append((char) ch); buff.append((char) ch);
...@@ -433,13 +433,22 @@ public class Csv implements SimpleRowSource { ...@@ -433,13 +433,22 @@ public class Csv implements SimpleRowSource {
private String unEscape(String s) { private String unEscape(String s) {
StringBuffer buff = new StringBuffer(s.length()); StringBuffer buff = new StringBuffer(s.length());
int start = 0; int start = 0;
char[] chars = null;
while (true) { while (true) {
int idx = s.indexOf(escapeCharacter, start); int idx = s.indexOf(escapeCharacter, start);
if (idx < 0) { if (idx < 0) {
break; break;
} }
buff.append(s.toCharArray(), start, idx); if (chars == null) {
start = idx + 1; chars = s.toCharArray();
}
buff.append(chars, start, idx - start);
if (idx == s.length() - 1) {
start = s.length();
break;
}
buff.append(chars[idx + 1]);
start = idx + 2;
} }
buff.append(s.substring(start)); buff.append(s.substring(start));
return buff.toString(); return buff.toString();
......
...@@ -534,4 +534,13 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -534,4 +534,13 @@ public class Server implements Runnable, ShutdownHandler {
stopAll(); stopAll();
} }
} }
/**
* Get the service attached to this server.
*
* @return the service
*/
public Service getService() {
return service;
}
} }
...@@ -12,6 +12,11 @@ import org.h2.tools.Script; ...@@ -12,6 +12,11 @@ import org.h2.tools.Script;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.tools.RunScript; import org.h2.tools.RunScript;
/**
* This sample application shows how to compact the database files.
* This is done by creating a SQL script, and then re-creating the database
* using this script.
*/
public class Compact { public class Compact {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
DeleteDbFiles.execute("data", "test", true); DeleteDbFiles.execute("data", "test", true);
......
...@@ -11,6 +11,11 @@ import java.sql.Types; ...@@ -11,6 +11,11 @@ import java.sql.Types;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
/**
* This sample application shows how to use the CSV tool
* to write CSV (comma separated values) files, and
* how to use the tool to read such files.
*/
public class CsvSample { public class CsvSample {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
CsvSample.write(); CsvSample.write();
......
...@@ -11,6 +11,10 @@ import java.sql.DriverManager; ...@@ -11,6 +11,10 @@ import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
/**
* This sample application shows how to create a user defined function
* to read a file from the file system.
*/
public class FileFunctions { public class FileFunctions {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
...@@ -14,6 +14,10 @@ import java.sql.Types; ...@@ -14,6 +14,10 @@ import java.sql.Types;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
/**
* This sample application shows how to define and use
* custom (user defined) functions in this database.
*/
public class Function { public class Function {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
...@@ -14,6 +14,12 @@ import java.sql.Types; ...@@ -14,6 +14,12 @@ import java.sql.Types;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
/**
* User defined functions can return a result set,
* and can therefore be used like a table.
* This sample application uses such a function to convert
* polar to cartesian coordinates.
*/
public class FunctionMultiReturn { public class FunctionMultiReturn {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
...@@ -13,6 +13,9 @@ import java.sql.Statement; ...@@ -13,6 +13,9 @@ import java.sql.Statement;
import org.h2.tools.RunScript; import org.h2.tools.RunScript;
/**
* In this example a database is initialized from compressed script in a jar file.
*/
public class InitDatabaseFromJar { public class InitDatabaseFromJar {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
...@@ -10,11 +10,16 @@ import java.sql.SQLException; ...@@ -10,11 +10,16 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import org.h2.tools.Server; import org.h2.tools.Server;
/**
* This sample program opens the same database once in embedded mode,
* and once in the server mode. The embedded mode is faster, but only
* the server mode supports remote connections.
*/
public class MixedMode { public class MixedMode {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// start the server, allows to access the database remotly // start the server, allows to access the database remotly
Server server = Server.createTcpServer(new String[]{"-tcpPort", "9081"}); Server server = Server.createTcpServer(new String[] { "-tcpPort", "9081" });
server.start(); server.start();
System.out.println("You can access the database remotely now, using the URL:"); System.out.println("You can access the database remotely now, using the URL:");
System.out.println("jdbc:h2:tcp://localhost:9081/~/test (user: sa, password: sa)"); System.out.println("jdbc:h2:tcp://localhost:9081/~/test (user: sa, password: sa)");
......
...@@ -16,6 +16,10 @@ import java.sql.ResultSet; ...@@ -16,6 +16,10 @@ import java.sql.ResultSet;
import org.h2.tools.RunScript; import org.h2.tools.RunScript;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
/**
* The newsfeed application uses XML functions to create an RSS and Atom feed
* from a simple SQL script. A textual representation of the data is created as well.
*/
public class Newsfeed { public class Newsfeed {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
Class.forName("org.h2.Driver"); Class.forName("org.h2.Driver");
......
...@@ -13,10 +13,16 @@ import java.sql.ResultSet; ...@@ -13,10 +13,16 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
/**
* SQL Injection is a common security vulnerability for applications that use database.
* It is one of the most common security vulnerabilities for web applications today.
* This sample application shows how SQL injection works, and how to protect
* the application from it.
*/
public class SQLInjection { public class SQLInjection {
Connection conn; private Connection conn;
Statement stat; private Statement stat;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new SQLInjection().run("org.h2.Driver", new SQLInjection().run("org.h2.Driver",
...@@ -47,14 +53,14 @@ public class SQLInjection { ...@@ -47,14 +53,14 @@ public class SQLInjection {
stat.execute("INSERT INTO USERS VALUES(2, 'guest', '123456')"); stat.execute("INSERT INTO USERS VALUES(2, 'guest', '123456')");
stat.execute("INSERT INTO USERS VALUES(3, 'test', 'abc')"); stat.execute("INSERT INTO USERS VALUES(3, 'test', 'abc')");
// loginByNameInsecure(); loginByNameInsecure();
if (url.startsWith("jdbc:h2:")) { if (url.startsWith("jdbc:h2:")) {
// loginStoredProcedureInsecure(); loginStoredProcedureInsecure();
limitRowAccess(); limitRowAccess();
} }
// loginByNameSecure(); loginByNameSecure();
if (url.startsWith("jdbc:h2:")) { if (url.startsWith("jdbc:h2:")) {
stat.execute("SET ALLOW_LITERALS NONE"); stat.execute("SET ALLOW_LITERALS NONE");
...@@ -62,8 +68,8 @@ public class SQLInjection { ...@@ -62,8 +68,8 @@ public class SQLInjection {
stat.execute("SET ALLOW_LITERALS ALL"); stat.execute("SET ALLOW_LITERALS ALL");
} }
// loginByIdInsecure(); loginByIdInsecure();
// loginByIdSecure(); loginByIdSecure();
try { try {
stat.execute("DROP TABLE ITEMS"); stat.execute("DROP TABLE ITEMS");
...@@ -89,12 +95,12 @@ public class SQLInjection { ...@@ -89,12 +95,12 @@ public class SQLInjection {
listActiveItemsUsingConstants(); listActiveItemsUsingConstants();
} }
// listItemsSortedInsecure(); listItemsSortedInsecure();
// listItemsSortedSecure(); listItemsSortedSecure();
if (url.startsWith("jdbc:h2:")) { if (url.startsWith("jdbc:h2:")) {
listItemsSortedSecureParam(); listItemsSortedSecureParam();
// storePasswordHashWithSalt(); storePasswordHashWithSalt();
} }
conn.close(); conn.close();
......
...@@ -13,6 +13,11 @@ import java.sql.Statement; ...@@ -13,6 +13,11 @@ import java.sql.Statement;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
/**
* This example application implements a database event listener.
* This is useful to display progress information while opening a large database,
* or to log database exceptions.
*/
public class ShowProgress implements DatabaseEventListener { public class ShowProgress implements DatabaseEventListener {
private long last, start; private long last, start;
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
*/ */
package org.h2.samples; package org.h2.samples;
/**
* This very simple sample application stops a H2 TCP server
* if it is running.
*/
public class ShutdownServer { public class ShutdownServer {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
org.h2.tools.Server.shutdownTcpServer("tcp://localhost:9094", "", false); org.h2.tools.Server.shutdownTcpServer("tcp://localhost:9094", "", false);
......
...@@ -14,6 +14,9 @@ import java.sql.Statement; ...@@ -14,6 +14,9 @@ import java.sql.Statement;
import org.h2.api.Trigger; import org.h2.api.Trigger;
/**
* This sample application shows how to use database triggers.
*/
public class TriggerSample { public class TriggerSample {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
......
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>H2 Database Engine</title>
<link>http://www.h2database.com</link>
<description>H2 Database Engine</description>
<language>en-us</language>
<pubDate>Thu, 15 Jun 2006 05:59:06 GMT</pubDate>
<lastBuildDate>Thu, 15 Jun 2006 05:59:06 GMT</lastBuildDate>
<item>
<title>New version available: 0.9 Alpha / 2006-06-02</title>
<link>http://www.h2database.com</link>
<description>
<![CDATA[A new version of H2 is available for download at http://www.h2database.com
Changes and new functionality:
- The GCJ version for Windows is no longer included in the download.
It was not stable in this release.
- ORDER BY now uses an index if possible.
Queries with LIMIT with ORDER BY
are faster when the index can be used.
- Statements containing LIKE are now re-compiled when executed.
Depending on the data, an index on the column is used or not.
- New option to disable automatic closing of a database
when the virtual machine exits.
Database URL: jdbc:h2:test;db_close_on_exit=false
- New event: DatabaseEventListener.closingDatabase()
- Connection.getCatalog() now returns the database name
- The function DATABASE() now return the short name
- Automatic starting of a web browser for Mac OS X should work now.
Security:
- TCP Server: Can now specify a password (tcpPassword).
- New option -ifExists for the TCP and ODBC server
to disallow creating new databases.
Bugfixes:
- Issue #103: Shutdown of a TCP Server from command line
didn't always work.
- Issue #104: A HAVING condition on a column
that was not in the GROUP BY list didn't work.
- Issue #105: RUNSCRIPT (the command) didn't commit
after each command if autocommit was on.
- Issue #106: SET commands where not persisted
- Issue# 107: When executing scripts that contained inserts
with many columns, an OutOfMemory error could occur.
- Issue #108: There is a concurrency problem when multi threads
access the same database.
- Issue #109: ALTER TABLE ADD COLUMN can make
the database unusable.
For details see also the history. The plans for the next release are:
- Bugfixes, write more tests, more bugfixes, more tests
- Define which modules are alpha, beta and production quality
- Proposal for changed license (still pending...)
- For other plans, see the new 'Roadmap' part on the web site
]]>
</description>
</item>
</channel>
</rss>
...@@ -63,7 +63,8 @@ import org.h2.test.jdbc.TestTransactionIsolation; ...@@ -63,7 +63,8 @@ import org.h2.test.jdbc.TestTransactionIsolation;
import org.h2.test.jdbc.TestUpdatableResultSet; import org.h2.test.jdbc.TestUpdatableResultSet;
import org.h2.test.jdbc.TestZloty; import org.h2.test.jdbc.TestZloty;
import org.h2.test.jdbc.xa.TestXA; import org.h2.test.jdbc.xa.TestXA;
import org.h2.test.mvcc.TestMVCC; import org.h2.test.mvcc.TestMvcc1;
import org.h2.test.mvcc.TestMvcc2;
import org.h2.test.server.TestNestedLoop; import org.h2.test.server.TestNestedLoop;
import org.h2.test.server.TestPgServer; import org.h2.test.server.TestPgServer;
import org.h2.test.server.TestWeb; import org.h2.test.server.TestWeb;
...@@ -153,7 +154,19 @@ java org.h2.test.TestAll timer ...@@ -153,7 +154,19 @@ java org.h2.test.TestAll timer
/* /*
C:\temp\test\db documentation: package.html
write to the db file what version was used to create a database
History:
CSV tool: the character # could not be used as a separator when reading.
CSV tool: some escape/separator character combinations did not work. Fixed.
Roadmap:
remove
* Stop the server: close all open databases first
Web site: Web site:
link to history page, bug page link to history page, bug page
...@@ -188,12 +201,8 @@ CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR); ...@@ -188,12 +201,8 @@ CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
<reconnect> <reconnect>
out of memory? out of memory?
shrink newsletter list (migrate to google groups)
don't create @~ of not translated don't create @~ of not translated
clustered tables: test, document
extend tests that simulate power off extend tests that simulate power off
HSQLDB compatibility: HSQLDB compatibility:
...@@ -214,20 +223,16 @@ move Performance Tuning > Advanced Topics ...@@ -214,20 +223,16 @@ move Performance Tuning > Advanced Topics
testHalt testHalt
java org.h2.test.TestAll halt java org.h2.test.TestAll halt
Automate real power off tests
timer test timer test
java.lang.Exception: query was too quick; result: 0 time:968
at org.h2.test.TestBase.logError(TestBase.java:220)
at org.h2.test.db.TestCases$1.run(TestCases.java:170)
at java.lang.Thread.run(Thread.java:595)
ftp server: problem with multithreading? ftp server: problem with multithreading?
h2\src\docsrc\html\images\SQLInjection.txt h2\src\docsrc\html\images\SQLInjection.txt
Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide, send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide,
Send SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,... Send SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,...
Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
MySQL, PostgreSQL MySQL, PostgreSQL
READ_TEXT(fileName String) returning a CLOB. READ_TEXT(fileName String) returning a CLOB.
...@@ -235,8 +240,6 @@ I am not sure if this will read the CLOB in memory however. ...@@ -235,8 +240,6 @@ I am not sure if this will read the CLOB in memory however.
Improve LOB in directories performance Improve LOB in directories performance
Automate real power off tests
http://fastutil.dsi.unimi.it/ http://fastutil.dsi.unimi.it/
http://javolution.org/ http://javolution.org/
http://joda-time.sourceforge.net/ http://joda-time.sourceforge.net/
...@@ -251,8 +254,6 @@ glossary ...@@ -251,8 +254,6 @@ glossary
spell check / word list per language spell check / word list per language
translated .pdf translated .pdf
write tests using the PostgreSQL JDBC driver
*/ */
// run TestHalt // run TestHalt
...@@ -280,6 +281,9 @@ write tests using the PostgreSQL JDBC driver ...@@ -280,6 +281,9 @@ write tests using the PostgreSQL JDBC driver
Features of H2 Features of H2
- Case insensitive string data type - Case insensitive string data type
- GROUP_CONCAT aggregate, User defined aggregates - GROUP_CONCAT aggregate, User defined aggregates
- Fulltext search
- MVCC
- User defined types
*/ */
if (args.length > 0) { if (args.length > 0) {
...@@ -499,6 +503,8 @@ Features of H2 ...@@ -499,6 +503,8 @@ Features of H2
cache2Q = false; cache2Q = false;
testAll(); testAll();
memory = true;
testAll();
} }
void testAll() throws Exception { void testAll() throws Exception {
...@@ -539,9 +545,6 @@ Features of H2 ...@@ -539,9 +545,6 @@ Features of H2
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;
// mvcc = true;
// db // db
new TestScriptSimple().runTest(this); new TestScriptSimple().runTest(this);
new TestScript().runTest(this); new TestScript().runTest(this);
...@@ -607,7 +610,8 @@ Features of H2 ...@@ -607,7 +610,8 @@ Features of H2
new TestZloty().runTest(this); new TestZloty().runTest(this);
// mvcc // mvcc
new TestMVCC().runTest(this); new TestMvcc1().runTest(this);
new TestMvcc2().runTest(this);
// synthetic // synthetic
new TestCrashAPI().runTest(this); new TestCrashAPI().runTest(this);
......
...@@ -52,9 +52,6 @@ public abstract class TestBase { ...@@ -52,9 +52,6 @@ public abstract class TestBase {
} }
public void runTest(TestAll conf) { public void runTest(TestAll conf) {
if (conf.networked) {
return;
}
try { try {
init(conf); init(conf);
start = System.currentTimeMillis(); start = System.currentTimeMillis();
......
...@@ -8,9 +8,12 @@ import java.io.File; ...@@ -8,9 +8,12 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList;
import java.util.Random;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.Csv; import org.h2.tools.Csv;
...@@ -20,6 +23,7 @@ import org.h2.util.StringUtils; ...@@ -20,6 +23,7 @@ import org.h2.util.StringUtils;
public class TestCsv extends TestBase { public class TestCsv extends TestBase {
public void test() throws Exception { public void test() throws Exception {
testRandomData();
testEmptyFieldDelimiter(); testEmptyFieldDelimiter();
testFieldDelimiter(); testFieldDelimiter();
testAsTable(); testAsTable();
...@@ -28,6 +32,48 @@ public class TestCsv extends TestBase { ...@@ -28,6 +32,48 @@ public class TestCsv extends TestBase {
testPipe(); testPipe();
} }
private void testRandomData() throws Exception {
deleteDb("csv");
Connection conn = getConnection("csv");
Statement stat = conn.createStatement();
stat.execute("drop table if exists test");
stat.execute("create table test(a varchar, b varchar)");
int len = getSize(1000, 10000);
PreparedStatement prep = conn.prepareStatement("insert into test values(?, ?)");
ArrayList list = new ArrayList();
Random random = new Random(1);
for (int i = 0; i < len; i++) {
String a = randomData(random), b = randomData(random);
prep.setString(1, a);
prep.setString(2, b);
list.add(new String[]{a, b});
prep.execute();
}
stat.execute("CALL CSVWRITE('test.csv', 'SELECT * FROM test', 'UTF-8', '|', '#')");
Csv csv = Csv.getInstance();
csv.setFieldSeparatorRead('|');
csv.setFieldDelimiter('#');
ResultSet rs = csv.read("test.csv", null, "UTF-8");
for (int i = 0; i < len; i++) {
check(rs.next());
String[] pair = (String[]) list.get(i);
check(pair[0], rs.getString(1));
check(pair[1], rs.getString(2));
}
checkFalse(rs.next());
conn.close();
}
private String randomData(Random random) {
int len = random.nextInt(5);
StringBuffer buff = new StringBuffer();
String chars = "\\\'\",\r\n\t ;.-123456|#";
for (int i = 0; i < len; i++) {
buff.append(chars.charAt(random.nextInt(chars.length())));
}
return buff.toString();
}
private void testEmptyFieldDelimiter() throws Exception { private void testEmptyFieldDelimiter() throws Exception {
File f = new File(baseDir + "/test.csv"); File f = new File(baseDir + "/test.csv");
f.delete(); f.delete();
......
...@@ -15,7 +15,10 @@ import org.h2.constant.ErrorCode; ...@@ -15,7 +15,10 @@ import org.h2.constant.ErrorCode;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
public class TestMVCC extends TestBase { /**
* Basic MVCC (multi version concurrency) test cases.
*/
public class TestMvcc1 extends TestBase {
Connection c1, c2; Connection c1, c2;
Statement s1, s2; Statement s1, s2;
...@@ -359,8 +362,6 @@ public class TestMVCC extends TestBase { ...@@ -359,8 +362,6 @@ public class TestMVCC extends TestBase {
c1.close(); c1.close();
c2.close(); c2.close();
} }
private void test(Statement stat, String sql, String expected) throws Exception { private void test(Statement stat, String sql, String expected) throws Exception {
...@@ -377,7 +378,5 @@ public class TestMVCC extends TestBase { ...@@ -377,7 +378,5 @@ public class TestMVCC extends TestBase {
throw new Error("expected: " + expected + ", got: no rows"); throw new Error("expected: " + expected + ", got: no rows");
} }
} }
// TODO Auto-generated method stub
} }
} }
/*
* 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.test.mvcc;
import java.sql.Connection;
import java.sql.Statement;
import org.h2.test.TestBase;
/**
* Additional MVCC (multi version concurrency) test cases.
*/
public class TestMvcc2 extends TestBase {
private static final String DROP_TABLE = "DROP TABLE IF EXISTS EMPLOYEE";
private static final String CREATE_TABLE = "CREATE TABLE EMPLOYEE (id BIGINT, version BIGINT, NAME VARCHAR(255))";
private static final String INSERT = "INSERT INTO EMPLOYEE (id, version, NAME) VALUES (1, 1, 'Jones')";
private static final String UPDATE = "UPDATE EMPLOYEE SET NAME = 'Miller' WHERE version = 1";
public void test() throws Exception {
if (!config.mvcc) {
return;
}
deleteDb("mvcc2");
testInsertUpdateRollback();
testInsertRollback();
}
Connection getConnection() throws Exception {
return getConnection("mvcc2");
}
public void testInsertUpdateRollback() throws Exception {
Connection conn = getConnection();
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute(DROP_TABLE);
stmt.execute(CREATE_TABLE);
conn.commit();
stmt.execute(INSERT);
stmt.execute(UPDATE);
conn.rollback();
conn.close();
}
public void testInsertRollback() throws Exception {
Connection conn = getConnection();
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute(DROP_TABLE);
stmt.execute(CREATE_TABLE);
conn.commit();
stmt.execute(INSERT);
conn.rollback();
conn.close();
}
}
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
select * from dual a left join dual b on b.x=(select max(x) from dual);
> exception
select count(*) from system_range(1, 2) where x in(1, 1, 1); select count(*) from system_range(1, 2) where x in(1, 1, 1);
> COUNT(*) > COUNT(*)
> -------- > --------
......
Defect report:
What steps will reproduce the problem?
(simple SQL scripts or simple standalone applications are preferred)
1.
2.
3.
What is the expected output? What do you see instead?
What version of the product are you using? On what operating system, file system, and virtual machine?
Do you know a workaround?
How important/urgent is the problem for you?
In your view, is this a defect or a feature request?
Please provide any additional information below.
-----------------
Corrupted database
I am sorry to say that, but it looks like a corruption problem. I am very interested in analyzing and solving this problem. It has top priority for me. I have a few question:
- What is your database URL?
- What version H2 are you using?
- Do you use any settings or special features (for example, the setting LOG=0, or two phase commit, linked tables, cache settings)?
- On what operating system, file system, and virtual machine?
- How big is the database?
- Is the database usually closed normally, or is process terminated forcefully or the computer switched off?
- Is it possible to reproduce this problem using a fresh database?
- Are there any other exceptions (maybe in the .trace.db file)? Could you post them please?
- Was the database originally created with an older version of H2?
- Do you still have any .trace.db files, and if yes could you send them?
- Could you send me the .data.db file where this exception occurs?
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import org.h2.server.ftp.FtpEvent;
import org.h2.server.ftp.FtpEventListener;
import org.h2.server.ftp.FtpServer;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.Server; import org.h2.tools.Server;
public class TestFtp extends TestBase { public class TestFtp extends TestBase implements FtpEventListener {
private FtpEvent lastEvent;
public void test() throws Exception { public void test() throws Exception {
test(baseDir); test(baseDir);
...@@ -15,17 +20,33 @@ public class TestFtp extends TestBase { ...@@ -15,17 +20,33 @@ public class TestFtp extends TestBase {
private void test(String dir) throws Exception { private void test(String dir) throws Exception {
Server server = Server.createFtpServer(new String[]{"-ftpDir", dir}).start(); Server server = Server.createFtpServer(new String[]{"-ftpDir", dir}).start();
FtpServer ftp = (FtpServer) server.getService();
ftp.setEventListener(this);
FtpClient client = FtpClient.open("localhost:8021"); FtpClient client = FtpClient.open("localhost:8021");
client.login("sa", "sa"); client.login("sa", "sa");
client.makeDirectory("test"); client.makeDirectory("test");
client.changeWorkingDirectory("test"); client.changeWorkingDirectory("test");
check(lastEvent.getCommand(), "CWD");
client.makeDirectory("hello"); client.makeDirectory("hello");
client.changeWorkingDirectory("hello"); client.changeWorkingDirectory("hello");
client.changeDirectoryUp(); client.changeDirectoryUp();
check(lastEvent.getCommand(), "CDUP");
client.nameList("hello"); client.nameList("hello");
client.removeDirectory("hello"); client.removeDirectory("hello");
client.close(); client.close();
server.stop(); server.stop();
} }
public void beforeCommand(FtpEvent event) {
lastEvent = event;
}
public void afterCommand(FtpEvent event) {
lastEvent = event;
}
public void onUnsupportedCommand(FtpEvent event) {
lastEvent = event;
}
} }
...@@ -237,6 +237,9 @@ public class TestTools extends TestBase { ...@@ -237,6 +237,9 @@ public class TestTools extends TestBase {
} }
private void testManagementDb() throws Exception { private void testManagementDb() throws Exception {
if (config.networked) {
return;
}
int count = getSize(2, 10); int count = getSize(2, 10);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Server server = Server.createTcpServer(new String[] {}).start(); Server server = Server.createTcpServer(new String[] {}).start();
...@@ -331,11 +334,13 @@ public class TestTools extends TestBase { ...@@ -331,11 +334,13 @@ public class TestTools extends TestBase {
Server.shutdownTcpServer("tcp://localhost", "", true); Server.shutdownTcpServer("tcp://localhost", "", true);
error("shouldn't work and should throw an exception"); error("shouldn't work and should throw an exception");
} catch (SQLException e) { } catch (SQLException e) {
// expected checkNotGeneralException(e);
} }
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", ""); conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", "");
conn.close(); // conn.close();
Server.shutdownTcpServer("tcp://localhost", "abc", true); Server.shutdownTcpServer("tcp://localhost", "abc", true);
// check that the database is closed
deleteDb("test");
try { try {
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", ""); conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/test", "sa", "");
error("server must have been closed"); error("server must have been closed");
......
...@@ -517,4 +517,4 @@ russian backward alexahin vlad ffffffffffff bfff ffffffff webapp undeploy initia ...@@ -517,4 +517,4 @@ russian backward alexahin vlad ffffffffffff bfff ffffffff webapp undeploy initia
llc computing oliver road inaccessible android velasques duplicates eduardo chunk brazilian near langpair xrmd xmkd llc computing oliver road inaccessible android velasques duplicates eduardo chunk brazilian near langpair xrmd xmkd
encapsulates negating igor midnight fulfill prefixes communicates nesting convenience negated resides optimizing principal applets dobrovolskyi encapsulates negating igor midnight fulfill prefixes communicates nesting convenience negated resides optimizing principal applets dobrovolskyi
involves ukrainian chile machines restricting summer aliased backus naur multiples avl operates grow normalized rijndael involves ukrainian chile machines restricting summer aliased backus naur multiples avl operates grow normalized rijndael
countdown paused javac countdown paused javac analyzing accesses solving forcefully urgent originally defect coordinates
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论